@@ -3967,6 +3967,7 @@ def_type_content_sets! {
3967
3967
None = 0b0000_0000__0000_0000__0000 ,
3968
3968
3969
3969
// Things that are interior to the value (first nibble):
3970
+ InteriorUnsized = 0b0000_0000__0000_0000__0001 ,
3970
3971
InteriorUnsafe = 0b0000_0000__0000_0000__0010 ,
3971
3972
InteriorParam = 0b0000_0000__0000_0000__0100 ,
3972
3973
// InteriorAll = 0b00000000__00000000__1111,
@@ -3976,9 +3977,18 @@ def_type_content_sets! {
3976
3977
OwnsDtor = 0b0000_0000__0000_0010__0000 ,
3977
3978
OwnsAll = 0b0000_0000__1111_1111__0000 ,
3978
3979
3980
+ // Things that are reachable by the value in any way (fourth nibble):
3981
+ ReachesBorrowed = 0b0000_0010__0000_0000__0000 ,
3982
+ ReachesMutable = 0b0000_1000__0000_0000__0000 ,
3983
+ ReachesFfiUnsafe = 0b0010_0000__0000_0000__0000 ,
3984
+ ReachesAll = 0b0011_1111__0000_0000__0000 ,
3985
+
3979
3986
// Things that mean drop glue is necessary
3980
3987
NeedsDrop = 0b0000_0000__0000_0111__0000 ,
3981
3988
3989
+ // Things that prevent values from being considered sized
3990
+ Nonsized = 0b0000_0000__0000_0000__0001 ,
3991
+
3982
3992
// All bits
3983
3993
All = 0b1111_1111__1111_1111__1111
3984
3994
}
@@ -3997,6 +4007,10 @@ impl TypeContents {
3997
4007
self . intersects ( TC :: OwnsOwned )
3998
4008
}
3999
4009
4010
+ pub fn is_sized ( & self , _: & ctxt ) -> bool {
4011
+ !self . intersects ( TC :: Nonsized )
4012
+ }
4013
+
4000
4014
pub fn interior_param ( & self ) -> bool {
4001
4015
self . intersects ( TC :: InteriorParam )
4002
4016
}
@@ -4005,13 +4019,29 @@ impl TypeContents {
4005
4019
self . intersects ( TC :: InteriorUnsafe )
4006
4020
}
4007
4021
4022
+ pub fn interior_unsized ( & self ) -> bool {
4023
+ self . intersects ( TC :: InteriorUnsized )
4024
+ }
4025
+
4008
4026
pub fn needs_drop ( & self , _: & ctxt ) -> bool {
4009
4027
self . intersects ( TC :: NeedsDrop )
4010
4028
}
4011
4029
4012
4030
/// Includes only those bits that still apply when indirected through a `Box` pointer
4013
4031
pub fn owned_pointer ( & self ) -> TypeContents {
4014
- TC :: OwnsOwned | ( * self & TC :: OwnsAll )
4032
+ TC :: OwnsOwned | (
4033
+ * self & ( TC :: OwnsAll | TC :: ReachesAll ) )
4034
+ }
4035
+
4036
+ /// Includes only those bits that still apply when indirected through a reference (`&`)
4037
+ pub fn reference ( & self , bits : TypeContents ) -> TypeContents {
4038
+ bits | (
4039
+ * self & TC :: ReachesAll )
4040
+ }
4041
+
4042
+ /// Includes only those bits that still apply when indirected through a raw pointer (`*`)
4043
+ pub fn unsafe_pointer ( & self ) -> TypeContents {
4044
+ * self & TC :: ReachesAll
4015
4045
}
4016
4046
4017
4047
pub fn union < T , F > ( v : & [ T ] , mut f : F ) -> TypeContents where
@@ -4099,7 +4129,7 @@ impl<'tcx> TyS<'tcx> {
4099
4129
let result = match ty. sty {
4100
4130
// usize and isize are ffi-unsafe
4101
4131
TyUint ( ast:: TyUs ) | TyInt ( ast:: TyIs ) => {
4102
- TC :: None
4132
+ TC :: ReachesFfiUnsafe
4103
4133
}
4104
4134
4105
4135
// Scalar and unique types are sendable, and durable
@@ -4110,35 +4140,40 @@ impl<'tcx> TyS<'tcx> {
4110
4140
}
4111
4141
4112
4142
TyBox ( typ) => {
4113
- tc_ty ( cx, typ, cache) . owned_pointer ( )
4143
+ TC :: ReachesFfiUnsafe | tc_ty ( cx, typ, cache) . owned_pointer ( )
4114
4144
}
4115
4145
4116
- TyTrait ( _ ) => {
4117
- TC :: All - TC :: InteriorParam
4146
+ TyTrait ( box TraitTy { ref bounds , .. } ) => {
4147
+ object_contents ( bounds ) | TC :: ReachesFfiUnsafe | TC :: Nonsized
4118
4148
}
4119
4149
4120
- TyRawPtr ( _ ) => {
4121
- TC :: None
4150
+ TyRawPtr ( ref mt ) => {
4151
+ tc_ty ( cx , mt . ty , cache ) . unsafe_pointer ( )
4122
4152
}
4123
4153
4124
- TyRef ( _, _) => {
4125
- TC :: None
4154
+ TyRef ( r, ref mt) => {
4155
+ tc_ty ( cx, mt. ty , cache) . reference ( borrowed_contents ( * r, mt. mutbl ) ) |
4156
+ TC :: ReachesFfiUnsafe
4126
4157
}
4127
4158
4128
4159
TyArray ( ty, _) => {
4129
4160
tc_ty ( cx, ty, cache)
4130
4161
}
4131
4162
4132
4163
TySlice ( ty) => {
4133
- tc_ty ( cx, ty, cache)
4164
+ tc_ty ( cx, ty, cache) | TC :: Nonsized
4134
4165
}
4135
- TyStr => TC :: None ,
4166
+ TyStr => TC :: Nonsized ,
4136
4167
4137
4168
TyStruct ( did, substs) => {
4138
4169
let flds = cx. struct_fields ( did, substs) ;
4139
4170
let mut res =
4140
4171
TypeContents :: union ( & flds[ ..] ,
4141
- |f| tc_ty ( cx, f. mt . ty , cache) ) ;
4172
+ |f| tc_mt ( cx, f. mt , cache) ) ;
4173
+
4174
+ if !cx. lookup_repr_hints ( did) . contains ( & attr:: ReprExtern ) {
4175
+ res = res | TC :: ReachesFfiUnsafe ;
4176
+ }
4142
4177
4143
4178
if cx. has_dtor ( did) {
4144
4179
res = res | TC :: OwnsDtor ;
@@ -4147,6 +4182,7 @@ impl<'tcx> TyS<'tcx> {
4147
4182
}
4148
4183
4149
4184
TyClosure ( did, substs) => {
4185
+ // FIXME(#14449): `borrowed_contents` below assumes `&mut` closure.
4150
4186
let param_env = cx. empty_parameter_environment ( ) ;
4151
4187
let infcx = infer:: new_infer_ctxt ( cx, & cx. tables , Some ( param_env) , false ) ;
4152
4188
let upvars = infcx. closure_upvars ( did, substs) . unwrap ( ) ;
@@ -4172,6 +4208,44 @@ impl<'tcx> TyS<'tcx> {
4172
4208
res = res | TC :: OwnsDtor ;
4173
4209
}
4174
4210
4211
+ if !variants. is_empty ( ) {
4212
+ let repr_hints = cx. lookup_repr_hints ( did) ;
4213
+ if repr_hints. len ( ) > 1 {
4214
+ // this is an error later on, but this type isn't safe
4215
+ res = res | TC :: ReachesFfiUnsafe ;
4216
+ }
4217
+
4218
+ match repr_hints. get ( 0 ) {
4219
+ Some ( h) => if !h. is_ffi_safe ( ) {
4220
+ res = res | TC :: ReachesFfiUnsafe ;
4221
+ } ,
4222
+ // ReprAny
4223
+ None => {
4224
+ res = res | TC :: ReachesFfiUnsafe ;
4225
+
4226
+ // We allow ReprAny enums if they are eligible for
4227
+ // the nullable pointer optimization and the
4228
+ // contained type is an `extern fn`
4229
+
4230
+ if variants. len ( ) == 2 {
4231
+ let mut data_idx = 0 ;
4232
+
4233
+ if variants[ 0 ] . args . is_empty ( ) {
4234
+ data_idx = 1 ;
4235
+ }
4236
+
4237
+ if variants[ data_idx] . args . len ( ) == 1 {
4238
+ match variants[ data_idx] . args [ 0 ] . sty {
4239
+ TyBareFn ( ..) => { res = res - TC :: ReachesFfiUnsafe ; }
4240
+ _ => { }
4241
+ }
4242
+ }
4243
+ }
4244
+ }
4245
+ }
4246
+ }
4247
+
4248
+
4175
4249
apply_lang_items ( cx, did, res)
4176
4250
}
4177
4251
@@ -4190,6 +4264,14 @@ impl<'tcx> TyS<'tcx> {
4190
4264
result
4191
4265
}
4192
4266
4267
+ fn tc_mt < ' tcx > ( cx : & ctxt < ' tcx > ,
4268
+ mt : TypeAndMut < ' tcx > ,
4269
+ cache : & mut FnvHashMap < Ty < ' tcx > , TypeContents > ) -> TypeContents
4270
+ {
4271
+ let mc = TC :: ReachesMutable . when ( mt. mutbl == MutMutable ) ;
4272
+ mc | tc_ty ( cx, mt. ty , cache)
4273
+ }
4274
+
4193
4275
fn apply_lang_items ( cx : & ctxt , did : ast:: DefId , tc : TypeContents )
4194
4276
-> TypeContents {
4195
4277
if Some ( did) == cx. lang_items . unsafe_cell_type ( ) {
@@ -4198,6 +4280,32 @@ impl<'tcx> TyS<'tcx> {
4198
4280
tc
4199
4281
}
4200
4282
}
4283
+
4284
+ /// Type contents due to containing a reference with
4285
+ /// the region `region` and borrow kind `bk`.
4286
+ fn borrowed_contents ( region : ty:: Region ,
4287
+ mutbl : ast:: Mutability )
4288
+ -> TypeContents {
4289
+ let b = match mutbl {
4290
+ ast:: MutMutable => TC :: ReachesMutable ,
4291
+ ast:: MutImmutable => TC :: None ,
4292
+ } ;
4293
+ b | ( TC :: ReachesBorrowed ) . when ( region != ty:: ReStatic )
4294
+ }
4295
+
4296
+ fn object_contents ( bounds : & ExistentialBounds ) -> TypeContents {
4297
+ // These are the type contents of the (opaque) interior. We
4298
+ // make no assumptions (other than that it cannot have an
4299
+ // in-scope type parameter within, which makes no sense).
4300
+ let mut tc = TC :: All - TC :: InteriorParam ;
4301
+ for bound in & bounds. builtin_bounds {
4302
+ tc = tc - match bound {
4303
+ BoundSync | BoundSend | BoundCopy => TC :: None ,
4304
+ BoundSized => TC :: Nonsized ,
4305
+ } ;
4306
+ }
4307
+ return tc;
4308
+ }
4201
4309
}
4202
4310
4203
4311
fn impls_bound < ' a > ( & ' tcx self , param_env : & ParameterEnvironment < ' a , ' tcx > ,
@@ -4291,6 +4399,10 @@ impl<'tcx> TyS<'tcx> {
4291
4399
result
4292
4400
}
4293
4401
4402
+ pub fn is_ffi_safe ( & ' tcx self , cx : & ctxt < ' tcx > ) -> bool {
4403
+ !self . type_contents ( cx) . intersects ( TC :: ReachesFfiUnsafe )
4404
+ }
4405
+
4294
4406
// True if instantiating an instance of `r_ty` requires an instance of `r_ty`.
4295
4407
pub fn is_instantiable ( & ' tcx self , cx : & ctxt < ' tcx > ) -> bool {
4296
4408
fn type_requires < ' tcx > ( cx : & ctxt < ' tcx > , seen : & mut Vec < DefId > ,
0 commit comments