@@ -147,61 +147,28 @@ impl<'tcx> FfiResult<'tcx> {
147
147
}
148
148
149
149
impl < ' tcx > std:: ops:: AddAssign < FfiResult < ' tcx > > for FfiResult < ' tcx > {
150
- fn add_assign ( & mut self , mut other : Self ) {
150
+ fn add_assign ( & mut self , other : Self ) {
151
151
// note: we shouldn't really encounter FfiPhantoms here, they should be dealt with beforehand
152
152
// still, this function deals with them in a reasonable way, I think
153
153
154
- // this function is awful to look but that's because matching mutable references consumes them (?!)
155
- // the function itself imitates the following piece of non-compiling code:
156
-
157
- // match (self, other) {
158
- // (Self::FfiUnsafe(_), _) => {
159
- // // nothing to do
160
- // },
161
- // (_, Self::FfiUnsafe(_)) => {
162
- // *self = other;
163
- // },
164
- // (Self::FfiPhantom(ref ty1),Self::FfiPhantom(ty2)) => {
165
- // println!("whoops, both FfiPhantom: self({:?}) += other({:?})", ty1, ty2);
166
- // },
167
- // (Self::FfiSafe,Self::FfiPhantom(_)) => {
168
- // *self = other;
169
- // },
170
- // (_, Self::FfiSafe) => {
171
- // // nothing to do
172
- // },
173
- // }
174
-
175
- let s_disc = std:: mem:: discriminant ( self ) ;
176
- let o_disc = std:: mem:: discriminant ( & other) ;
177
- if s_disc == o_disc {
178
- match ( self , & mut other) {
179
- ( Self :: FfiUnsafe ( s_inner) , Self :: FfiUnsafe ( o_inner) ) => {
180
- s_inner. append ( o_inner) ;
181
- }
182
- ( Self :: FfiPhantom ( ty1) , Self :: FfiPhantom ( ty2) ) => {
183
- debug ! ( "whoops: both FfiPhantom, self({:?}) += other({:?})" , ty1, ty2) ;
184
- }
185
- ( Self :: FfiSafe , Self :: FfiSafe ) => { }
186
- _ => unreachable ! ( ) ,
154
+ match ( self , other) {
155
+ ( Self :: FfiUnsafe ( self_reasons) , Self :: FfiUnsafe ( mut other_reasons) ) => {
156
+ self_reasons. append ( & mut other_reasons) ;
187
157
}
188
- } else {
189
- if let Self :: FfiUnsafe ( _) = self {
190
- return ;
158
+ ( Self :: FfiUnsafe ( _) , _) => {
159
+ // nothing to do
191
160
}
192
- match other {
193
- Self :: FfiUnsafe ( o_inner) => {
194
- // self is Safe or Phantom: Unsafe wins
195
- * self = Self :: FfiUnsafe ( o_inner) ;
196
- }
197
- Self :: FfiSafe => {
198
- // self is always "wins"
199
- return ;
200
- }
201
- Self :: FfiPhantom ( o_inner) => {
202
- // self is Safe: Phantom wins
203
- * self = Self :: FfiPhantom ( o_inner) ;
204
- }
161
+ ( myself, other @ Self :: FfiUnsafe ( _) ) => {
162
+ * myself = other;
163
+ }
164
+ ( Self :: FfiPhantom ( ty1) , Self :: FfiPhantom ( ty2) ) => {
165
+ debug ! ( "whoops, both FfiPhantom: self({:?}) += other({:?})" , ty1, ty2) ;
166
+ }
167
+ ( myself @ Self :: FfiSafe , other @ Self :: FfiPhantom ( _) ) => {
168
+ * myself = other;
169
+ }
170
+ ( _, Self :: FfiSafe ) => {
171
+ // nothing to do
205
172
}
206
173
}
207
174
}
@@ -214,7 +181,7 @@ impl<'tcx> std::ops::Add<FfiResult<'tcx>> for FfiResult<'tcx> {
214
181
}
215
182
}
216
183
217
- /// Determine if a type is sized or not, and wether it affects references/pointers/boxes to it
184
+ /// Determine if a type is sized or not, and whether it affects references/pointers/boxes to it
218
185
#[ derive( Clone , Copy ) ]
219
186
enum TypeSizedness {
220
187
/// type of definite size (pointers are C-compatible)
@@ -353,51 +320,63 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
353
320
}
354
321
}
355
322
323
+ #[ allow( non_snake_case) ]
324
+ mod CTypesVisitorStateFlags {
325
+ pub ( super ) const NO_FLAGS : u8 = 0b0000 ;
326
+ /// for static variables (not used in functions)
327
+ pub ( super ) const STATIC : u8 = 0b0010 ;
328
+ /// for variables in function returns (implicitly: not for static variables)
329
+ pub ( super ) const FN_RETURN : u8 = 0b0100 ;
330
+ /// for variables in functions which are defined in rust (implicitly: not for static variables)
331
+ pub ( super ) const FN_DECLARED : u8 = 0b1000 ;
332
+ }
333
+
356
334
#[ repr( u8 ) ]
357
335
#[ derive( Clone , Copy , Debug ) ]
358
336
enum CTypesVisitorState {
359
- // bitflags:
360
- // 0010: static
361
- // 0100: function return
362
- // 1000: used in declared function
363
- StaticTy = 0b0010 ,
364
- ArgumentTyInDefinition = 0b1000 ,
365
- ReturnTyInDefinition = 0b1100 ,
366
- ArgumentTyInDeclaration = 0b0000 ,
367
- ReturnTyInDeclaration = 0b0100 ,
337
+ // uses bitflags from CTypesVisitorStateFlags
338
+ StaticTy = CTypesVisitorStateFlags :: STATIC ,
339
+ ArgumentTyInDefinition = CTypesVisitorStateFlags :: FN_DECLARED ,
340
+ ReturnTyInDefinition =
341
+ CTypesVisitorStateFlags :: FN_DECLARED | CTypesVisitorStateFlags :: FN_RETURN ,
342
+ ArgumentTyInDeclaration = CTypesVisitorStateFlags :: NO_FLAGS ,
343
+ ReturnTyInDeclaration = CTypesVisitorStateFlags :: FN_RETURN ,
368
344
}
369
345
370
346
impl CTypesVisitorState {
371
- /// wether the type is used (directly or not) in a static variable
347
+ /// whether the type is used (directly or not) in a static variable
372
348
fn is_in_static ( self ) -> bool {
373
- ( ( self as u8 ) & 0b0010 ) != 0
349
+ use CTypesVisitorStateFlags :: * ;
350
+ ( ( self as u8 ) & STATIC ) != 0
374
351
}
375
- /// wether the type is used (directly or not) in a function, in return position
352
+ /// whether the type is used (directly or not) in a function, in return position
376
353
fn is_in_function_return ( self ) -> bool {
377
- let ret = ( ( self as u8 ) & 0b0100 ) != 0 ;
354
+ use CTypesVisitorStateFlags :: * ;
355
+ let ret = ( ( self as u8 ) & FN_RETURN ) != 0 ;
378
356
#[ cfg( debug_assertions) ]
379
357
if ret {
380
358
assert ! ( !self . is_in_static( ) ) ;
381
359
}
382
360
ret
383
361
}
384
- /// wether the type is used (directly or not) in a defined function
385
- /// in other words, wether or not we allow non-FFI-safe types behind a C pointer,
362
+ /// whether the type is used (directly or not) in a defined function
363
+ /// in other words, whether or not we allow non-FFI-safe types behind a C pointer,
386
364
/// to be treated as an opaque type on the other side of the FFI boundary
387
365
fn is_in_defined_function ( self ) -> bool {
388
- let ret = ( ( self as u8 ) & 0b1000 ) != 0 ;
366
+ use CTypesVisitorStateFlags :: * ;
367
+ let ret = ( ( self as u8 ) & FN_DECLARED ) != 0 ;
389
368
#[ cfg( debug_assertions) ]
390
369
if ret {
391
370
assert ! ( !self . is_in_static( ) ) ;
392
371
}
393
372
ret
394
373
}
395
374
396
- /// wether the value for that type might come from the non-rust side of a FFI boundary
375
+ /// whether the value for that type might come from the non-rust side of a FFI boundary
397
376
fn value_may_be_unchecked ( self ) -> bool {
398
377
// function declarations are assumed to be rust-caller, non-rust-callee
399
378
// function definitions are assumed to be maybe-not-rust-caller, rust-callee
400
- // FnPtrs are... well, nothing's certain about anything. (TODO need more flags in enum?)
379
+ // FnPtrs are... well, nothing's certain about anything. (FIXME need more flags in enum?)
401
380
// Same with statics.
402
381
if self . is_in_static ( ) {
403
382
true
@@ -410,7 +389,7 @@ impl CTypesVisitorState {
410
389
}
411
390
412
391
impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
413
- /// Checks wether an `extern "ABI" fn` function pointer is indeed FFI-safe to call
392
+ /// Checks whether an `extern "ABI" fn` function pointer is indeed FFI-safe to call
414
393
fn visit_fnptr ( & mut self , mode : CItemKind , ty : Ty < ' tcx > , sig : Sig < ' tcx > ) -> FfiResult < ' tcx > {
415
394
use FfiResult :: * ;
416
395
debug_assert ! ( !sig. abi( ) . is_rustic_abi( ) ) ;
@@ -532,7 +511,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
532
511
// there are three remaining concerns with the pointer:
533
512
// - is the pointer compatible with a C pointer in the first place? (if not, only send that error message)
534
513
// - is the pointee FFI-safe? (it might not matter, see mere lines below)
535
- // - does the pointer type contain a non-zero assumption, but a value given by non-rust code?
514
+ // - does the pointer type contain a non-zero assumption, but has a value given by non-rust code?
536
515
// this block deals with the first two.
537
516
let mut ffi_res = match get_type_sizedness ( self . cx , inner_ty) {
538
517
TypeSizedness :: UnsizedWithExternType | TypeSizedness :: Definite => {
@@ -581,7 +560,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
581
560
// 'fake' declarations (in traits, needed to be implemented elsewhere), and definitions.
582
561
// (for instance, definitions should worry about &self with Self:?Sized, but fake declarations shouldn't)
583
562
584
- // wether they are FFI-safe or not does not depend on the indirections involved (&Self, &T, Box<impl Trait>),
563
+ // whether they are FFI-safe or not does not depend on the indirections involved (&Self, &T, Box<impl Trait>),
585
564
// so let's not wrap the current context around a potential FfiUnsafe type param.
586
565
self . visit_type ( state, Some ( ty) , inner_ty)
587
566
}
@@ -601,6 +580,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
601
580
} ;
602
581
603
582
// and now the third concern (does the pointer type contain a non-zero assumption, and is the value given by non-rust code?)
583
+ // technically, pointers with non-rust-given values could also be misaligned, pointing to the wrong thing, or outright dangling, but we assume they never are
604
584
ffi_res += if state. value_may_be_unchecked ( ) {
605
585
let has_nonnull_assumption = match indirection_type {
606
586
IndirectionType :: RawPtr => false ,
@@ -756,18 +736,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
756
736
757
737
if def. variants ( ) . is_empty ( ) {
758
738
// Empty enums are implicitely handled as the never type:
759
- // TODO think about the FFI-safety of functions that use that
739
+ // FIXME think about the FFI-safety of functions that use that
760
740
return FfiSafe ;
761
741
}
762
742
// Check for a repr() attribute to specify the size of the
763
743
// discriminant.
764
744
if !def. repr ( ) . c ( ) && !def. repr ( ) . transparent ( ) && def. repr ( ) . int . is_none ( ) {
765
745
// Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
766
- if let Some ( inner_ty) = repr_nullable_ptr (
767
- self . cx . tcx ,
768
- self . cx . typing_env ( ) ,
769
- ty,
770
- ) {
746
+ if let Some ( inner_ty) = repr_nullable_ptr ( self . cx . tcx , self . cx . typing_env ( ) , ty) {
771
747
return self . visit_type ( state, Some ( ty) , inner_ty) ;
772
748
}
773
749
@@ -801,7 +777,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
801
777
. iter ( )
802
778
. map ( |variant| {
803
779
self . visit_variant_fields ( state, ty, def, variant, args)
804
- // TODO : check that enums allow any (up to all) variants to be phantoms?
780
+ // FIXME : check that enums allow any (up to all) variants to be phantoms?
805
781
// (previous code says no, but I don't know why? the problem with phantoms is that they're ZSTs, right?)
806
782
. forbid_phantom ( )
807
783
} )
@@ -846,11 +822,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
846
822
}
847
823
match def. adt_kind ( ) {
848
824
AdtKind :: Struct | AdtKind :: Union => {
849
- // I thought CStr (not CString) could not be reached here :
850
- // - not using an indirection would cause a compile error prior to this lint
825
+ // I thought CStr (not CString) here could only be reached in non-compiling code :
826
+ // - not using an indirection would cause a compile error (this lint *currently* seems to not get triggered on such non-compiling code)
851
827
// - and using one would cause the lint to catch on the indirection before reaching its pointee
852
- // but for some reason one can just go and write function *pointers* like that:
853
- // `type Foo = extern "C" fn(::std::ffi::CStr);`
828
+ // but function *pointers* don't seem to have the same no-unsized-parameters requirement to compile
854
829
if let Some ( sym:: cstring_type | sym:: cstr_type) =
855
830
tcx. get_diagnostic_name ( def. did ( ) )
856
831
{
@@ -1097,10 +1072,7 @@ struct ImproperCTypesLint<'c, 'tcx> {
1097
1072
}
1098
1073
1099
1074
impl < ' c , ' tcx > ImproperCTypesLint < ' c , ' tcx > {
1100
- fn check_arg_for_power_alignment (
1101
- & mut self ,
1102
- ty : Ty < ' tcx > ,
1103
- ) -> bool {
1075
+ fn check_arg_for_power_alignment ( & mut self , ty : Ty < ' tcx > ) -> bool {
1104
1076
let tcx = self . cx . tcx ;
1105
1077
assert ! ( tcx. sess. target. os == "aix" ) ;
1106
1078
// Structs (under repr(C)) follow the power alignment rule if:
@@ -1131,10 +1103,7 @@ impl<'c, 'tcx> ImproperCTypesLint<'c, 'tcx> {
1131
1103
return false ;
1132
1104
}
1133
1105
1134
- fn check_struct_for_power_alignment (
1135
- & mut self ,
1136
- item : & ' tcx hir:: Item < ' tcx > ,
1137
- ) {
1106
+ fn check_struct_for_power_alignment ( & mut self , item : & ' tcx hir:: Item < ' tcx > ) {
1138
1107
let tcx = self . cx . tcx ;
1139
1108
let adt_def = tcx. adt_def ( item. owner_id . to_def_id ( ) ) ;
1140
1109
// repr(C) structs also with packed or aligned representation
@@ -1218,7 +1187,7 @@ impl<'c, 'tcx> ImproperCTypesLint<'c, 'tcx> {
1218
1187
( span, ffi_res)
1219
1188
} )
1220
1189
// even in function *definitions*, `FnPtr`s are always function declarations ...right?
1221
- // (TODO : we can't do that yet because one of rustc's crates can't compile if we do)
1190
+ // (FIXME : we can't do that yet because one of rustc's crates can't compile if we do)
1222
1191
. for_each ( |( span, ffi_res) | self . process_ffi_result ( span, ffi_res, fn_mode) ) ;
1223
1192
//.drain();
1224
1193
}
@@ -1306,12 +1275,8 @@ impl<'c, 'tcx> ImproperCTypesLint<'c, 'tcx> {
1306
1275
1307
1276
// this whole while block converts the arbitrarily-deep
1308
1277
// FfiResult stack to an ImproperCTypesLayer Vec
1309
- while let ControlFlow :: Continue ( FfiUnsafeReason {
1310
- ty,
1311
- reason,
1312
- help,
1313
- inner,
1314
- } ) = ffiresult_recursor
1278
+ while let ControlFlow :: Continue ( FfiUnsafeReason { ty, reason, help, inner } ) =
1279
+ ffiresult_recursor
1315
1280
{
1316
1281
if let Some ( layer) = cimproper_layers. last_mut ( ) {
1317
1282
layer. inner_ty = Some ( ty. clone ( ) ) ;
@@ -1374,7 +1339,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations {
1374
1339
1375
1340
match it. kind {
1376
1341
hir:: ForeignItemKind :: Fn ( sig, _, _) => {
1377
- if abi. is_rustic_abi ( ) {
1342
+ if abi. is_rustic_abi ( ) {
1378
1343
lint. check_fn_for_external_abi_fnptr (
1379
1344
CItemKind :: Declaration ,
1380
1345
it. owner_id . def_id ,
@@ -1416,7 +1381,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
1416
1381
// Structs are checked based on if they follow the power alignment
1417
1382
// rule (under repr(C)).
1418
1383
hir:: ItemKind :: Struct ( ..) => {
1419
- ImproperCTypesLint { cx } . check_struct_for_power_alignment ( item) ;
1384
+ ImproperCTypesLint { cx } . check_struct_for_power_alignment ( item) ;
1420
1385
}
1421
1386
// See `check_field_def`..
1422
1387
hir:: ItemKind :: Union ( ..) | hir:: ItemKind :: Enum ( ..) => { }
0 commit comments