@@ -25,7 +25,7 @@ use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
25
25
26
26
type Sig < ' tcx > = Binder < TyCtxt < ' tcx > , FnSig < TyCtxt < ' tcx > > > ;
27
27
28
- /// for a given `extern "ABI"`, tell wether that ABI is *not* considered a FFI boundary
28
+ /// for a given `extern "ABI"`, tell whether that ABI is *not* considered a FFI boundary
29
29
fn fn_abi_is_internal ( abi : ExternAbi ) -> bool {
30
30
matches ! (
31
31
abi,
@@ -168,57 +168,21 @@ impl<'tcx> std::ops::AddAssign<FfiResult<'tcx>> for FfiResult<'tcx> {
168
168
// note: we shouldn't really encounter FfiPhantoms here, they should be dealt with beforehand
169
169
// still, this function deals with them in a reasonable way, I think
170
170
171
- // this function is awful to look but that's because matching mutable references consumes them (?!)
172
- // the function itself imitates the following piece of non-compiling code:
173
-
174
- // match (self, other) {
175
- // (Self::FfiUnsafe(_), _) => {
176
- // // nothing to do
177
- // },
178
- // (_, Self::FfiUnsafe(_)) => {
179
- // *self = other;
180
- // },
181
- // (Self::FfiPhantom(ref ty1),Self::FfiPhantom(ty2)) => {
182
- // println!("whoops, both FfiPhantom: self({:?}) += other({:?})", ty1, ty2);
183
- // },
184
- // (Self::FfiSafe,Self::FfiPhantom(_)) => {
185
- // *self = other;
186
- // },
187
- // (_, Self::FfiSafe) => {
188
- // // nothing to do
189
- // },
190
- // }
191
-
192
- let s_disc = std:: mem:: discriminant ( self ) ;
193
- let o_disc = std:: mem:: discriminant ( & other) ;
194
- if s_disc == o_disc {
195
- match ( self , & mut other) {
196
- ( Self :: FfiUnsafe ( ref mut s_inner) , Self :: FfiUnsafe ( ref mut o_inner) ) => {
197
- s_inner. append ( o_inner) ;
198
- }
199
- ( Self :: FfiPhantom ( ref ty1) , Self :: FfiPhantom ( ty2) ) => {
200
- debug ! ( "whoops: both FfiPhantom, self({:?}) += other({:?})" , ty1, ty2) ;
201
- }
202
- ( Self :: FfiSafe , Self :: FfiSafe ) => { }
203
- _ => unreachable ! ( ) ,
171
+ match ( self , other) {
172
+ ( Self :: FfiUnsafe ( _) , _) => {
173
+ // nothing to do
204
174
}
205
- } else {
206
- if let Self :: FfiUnsafe ( _) = self {
207
- return ;
175
+ ( myself, other @ Self :: FfiUnsafe ( _) ) => {
176
+ * myself = other;
208
177
}
209
- match other {
210
- Self :: FfiUnsafe ( o_inner) => {
211
- // self is Safe or Phantom: Unsafe wins
212
- * self = Self :: FfiUnsafe ( o_inner) ;
213
- }
214
- Self :: FfiSafe => {
215
- // self is always "wins"
216
- return ;
217
- }
218
- Self :: FfiPhantom ( o_inner) => {
219
- // self is Safe: Phantom wins
220
- * self = Self :: FfiPhantom ( o_inner) ;
221
- }
178
+ ( Self :: FfiPhantom ( ref ty1) , Self :: FfiPhantom ( ty2) ) => {
179
+ debug ! ( "whoops, both FfiPhantom: self({:?}) += other({:?})" , ty1, ty2) ;
180
+ }
181
+ ( myself @ Self :: FfiSafe , other @ Self :: FfiPhantom ( _) ) => {
182
+ * myself = other;
183
+ }
184
+ ( _, Self :: FfiSafe ) => {
185
+ // nothing to do
222
186
}
223
187
}
224
188
}
@@ -231,7 +195,7 @@ impl<'tcx> std::ops::Add<FfiResult<'tcx>> for FfiResult<'tcx> {
231
195
}
232
196
}
233
197
234
- /// Determine if a type is sized or not, and wether it affects references/pointers/boxes to it
198
+ /// Determine if a type is sized or not, and whether it affects references/pointers/boxes to it
235
199
#[ derive( Clone , Copy ) ]
236
200
enum TypeSizedness {
237
201
/// type of definite size (pointers are C-compatible)
@@ -370,51 +334,59 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
370
334
}
371
335
}
372
336
337
+ mod CTypesVisitorStateFlags {
338
+ pub ( super ) const NO_FLAGS : isize = 0b0000 ;
339
+ /// for static variables (not used in functions)
340
+ pub ( super ) const STATIC : isize = 0b0010 ;
341
+ /// for variables in function returns (implicitly: not for static variables)
342
+ pub ( super ) const FN_RETURN : isize = 0b0100 ;
343
+ /// for variables in functions which are defined in rust (implicitly: not for static variables)
344
+ pub ( super ) const FN_DECLARED : isize = 0b1000 ;
345
+ }
346
+
373
347
#[ repr( u8 ) ]
374
348
#[ derive( Clone , Copy , Debug ) ]
375
349
enum CTypesVisitorState {
376
- // bitflags:
377
- // 0010: static
378
- // 0100: function return
379
- // 1000: used in declared function
380
- StaticTy = 0b0010 ,
381
- ArgumentTyInDefinition = 0b1000 ,
382
- ReturnTyInDefinition = 0b1100 ,
383
- ArgumentTyInDeclaration = 0b0000 ,
384
- ReturnTyInDeclaration = 0b0100 ,
350
+ // uses bitflags from CTypesVisitorStateFlags
351
+ StaticTy = CTypesVisitorStateFlags :: STATIC ,
352
+ ArgumentTyInDefinition = CTypesVisitorStateFlags :: FN_DECLARED ,
353
+ ReturnTyInDefinition = CTypesVisitorStateFlags :: FN_DECLARED |CTypesVisitorStateFlags :: FN_RETURN ,
354
+ ArgumentTyInDeclaration = CTypesVisitorStateFlags :: NO_FLAGS ,
355
+ ReturnTyInDeclaration = CTypesVisitorStateFlags :: FN_RETURN ,
385
356
}
386
357
387
358
impl CTypesVisitorState {
388
- /// wether the type is used (directly or not) in a static variable
359
+ use CTypesVisitorStateFlags :: * ;
360
+ /// whether the type is used (directly or not) in a static variable
389
361
fn is_in_static ( self ) -> bool {
390
- ( ( self as u8 ) & 0b0010 ) != 0
362
+ ( ( self as u8 ) & STATIC ) != 0
391
363
}
392
- /// wether the type is used (directly or not) in a function, in return position
364
+ /// whether the type is used (directly or not) in a function, in return position
393
365
fn is_in_function_return ( self ) -> bool {
394
- let ret = ( ( self as u8 ) & 0b0100 ) != 0 ;
366
+ let ret = ( ( self as u8 ) & FN_RETURN ) != 0 ;
395
367
#[ cfg( debug_assertions) ]
396
368
if ret {
397
369
assert ! ( !self . is_in_static( ) ) ;
398
370
}
399
371
ret
400
372
}
401
- /// wether the type is used (directly or not) in a defined function
402
- /// in other words, wether or not we allow non-FFI-safe types behind a C pointer,
373
+ /// whether the type is used (directly or not) in a defined function
374
+ /// in other words, whether or not we allow non-FFI-safe types behind a C pointer,
403
375
/// to be treated as an opaque type on the other side of the FFI boundary
404
376
fn is_in_defined_function ( self ) -> bool {
405
- let ret = ( ( self as u8 ) & 0b1000 ) != 0 ;
377
+ let ret = ( ( self as u8 ) & FN_DECLARED ) != 0 ;
406
378
#[ cfg( debug_assertions) ]
407
379
if ret {
408
380
assert ! ( !self . is_in_static( ) ) ;
409
381
}
410
382
ret
411
383
}
412
384
413
- /// wether the value for that type might come from the non-rust side of a FFI boundary
385
+ /// whether the value for that type might come from the non-rust side of a FFI boundary
414
386
fn value_may_be_unchecked ( self ) -> bool {
415
387
// function declarations are assumed to be rust-caller, non-rust-callee
416
388
// function definitions are assumed to be maybe-not-rust-caller, rust-callee
417
- // FnPtrs are... well, nothing's certain about anything. (TODO need more flags in enum?)
389
+ // FnPtrs are... well, nothing's certain about anything. (FIXME need more flags in enum?)
418
390
// Same with statics.
419
391
if self . is_in_static ( ) {
420
392
true
@@ -427,7 +399,7 @@ impl CTypesVisitorState {
427
399
}
428
400
429
401
impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
430
- /// Checks wether an `extern "ABI" fn` function pointer is indeed FFI-safe to call
402
+ /// Checks whether an `extern "ABI" fn` function pointer is indeed FFI-safe to call
431
403
fn visit_fnptr ( & mut self , mode : CItemKind , ty : Ty < ' tcx > , sig : Sig < ' tcx > ) -> FfiResult < ' tcx > {
432
404
use FfiResult :: * ;
433
405
debug_assert ! ( !fn_abi_is_internal( sig. abi( ) ) ) ;
@@ -550,7 +522,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
550
522
// there are three remaining concerns with the pointer:
551
523
// - is the pointer compatible with a C pointer in the first place? (if not, only send that error message)
552
524
// - is the pointee FFI-safe? (it might not matter, see mere lines below)
553
- // - does the pointer type contain a non-zero assumption, but a value given by non-rust code?
525
+ // - does the pointer type contain a non-zero assumption, but has a value given by non-rust code?
554
526
// this block deals with the first two.
555
527
let mut ffi_res = match get_type_sizedness ( self . cx , inner_ty) {
556
528
TypeSizedness :: UnsizedWithExternType | TypeSizedness :: Definite => {
@@ -599,7 +571,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
599
571
// 'fake' declarations (in traits, needed to be implemented elsewhere), and definitions.
600
572
// (for instance, definitions should worry about &self with Self:?Sized, but fake declarations shouldn't)
601
573
602
- // wether they are FFI-safe or not does not depend on the indirections involved (&Self, &T, Box<impl Trait>),
574
+ // whether they are FFI-safe or not does not depend on the indirections involved (&Self, &T, Box<impl Trait>),
603
575
// so let's not wrap the current context around a potential FfiUnsafe type param.
604
576
self . visit_type ( state, Some ( ty) , inner_ty)
605
577
}
@@ -619,6 +591,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
619
591
} ;
620
592
621
593
// and now the third concern (does the pointer type contain a non-zero assumption, and is the value given by non-rust code?)
594
+ // 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
622
595
ffi_res += if state. value_may_be_unchecked ( ) {
623
596
let has_nonnull_assumption = match indirection_type {
624
597
IndirectionType :: RawPtr => false ,
@@ -775,7 +748,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
775
748
776
749
if def. variants ( ) . is_empty ( ) {
777
750
// Empty enums are implicitely handled as the never type:
778
- // TODO think about the FFI-safety of functions that use that
751
+ // FIXME think about the FFI-safety of functions that use that
779
752
return FfiSafe ;
780
753
}
781
754
// Check for a repr() attribute to specify the size of the
@@ -820,7 +793,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
820
793
. iter ( )
821
794
. map ( |variant| {
822
795
self . visit_variant_fields ( state, ty, def, variant, args)
823
- // TODO : check that enums allow any (up to all) variants to be phantoms?
796
+ // FIXME : check that enums allow any (up to all) variants to be phantoms?
824
797
// (previous code says no, but I don't know why? the problem with phantoms is that they're ZSTs, right?)
825
798
. forbid_phantom ( )
826
799
} )
@@ -865,11 +838,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
865
838
}
866
839
match def. adt_kind ( ) {
867
840
AdtKind :: Struct | AdtKind :: Union => {
868
- // I thought CStr (not CString) could not be reached here :
869
- // - not using an indirection would cause a compile error prior to this lint
841
+ // I thought CStr (not CString) here could only be reached in non-compiling code :
842
+ // - not using an indirection would cause a compile error (this lint *currently* seems to not get triggered on such non-compiling code)
870
843
// - and using one would cause the lint to catch on the indirection before reaching its pointee
871
- // but for some reason one can just go and write function *pointers* like that:
872
- // `type Foo = extern "C" fn(::std::ffi::CStr);`
844
+ // but function *pointers* don't seem to have the same no-unsized-parameters requirement to compile
873
845
if let Some ( sym:: cstring_type | sym:: cstr_type) =
874
846
tcx. get_diagnostic_name ( def. did ( ) )
875
847
{
@@ -1116,10 +1088,7 @@ struct ImproperCTypesLint<'c, 'tcx> {
1116
1088
}
1117
1089
1118
1090
impl < ' c , ' tcx > ImproperCTypesLint < ' c , ' tcx > {
1119
- fn check_arg_for_power_alignment (
1120
- & mut self ,
1121
- ty : Ty < ' tcx > ,
1122
- ) -> bool {
1091
+ fn check_arg_for_power_alignment ( & mut self , ty : Ty < ' tcx > ) -> bool {
1123
1092
// Structs (under repr(C)) follow the power alignment rule if:
1124
1093
// - the first field of the struct is a floating-point type that
1125
1094
// is greater than 4-bytes, or
@@ -1149,10 +1118,7 @@ impl<'c, 'tcx> ImproperCTypesLint<'c, 'tcx> {
1149
1118
return false ;
1150
1119
}
1151
1120
1152
- fn check_struct_for_power_alignment (
1153
- & mut self ,
1154
- item : & ' tcx hir:: Item < ' tcx > ,
1155
- ) {
1121
+ fn check_struct_for_power_alignment ( & mut self , item : & ' tcx hir:: Item < ' tcx > ) {
1156
1122
let tcx = self . cx . tcx ;
1157
1123
let adt_def = tcx. adt_def ( item. owner_id . to_def_id ( ) ) ;
1158
1124
if adt_def. repr ( ) . c ( )
@@ -1236,7 +1202,7 @@ impl<'c, 'tcx> ImproperCTypesLint<'c, 'tcx> {
1236
1202
( span, ffi_res)
1237
1203
} )
1238
1204
// even in function *definitions*, `FnPtr`s are always function declarations ...right?
1239
- // (TODO : we can't do that yet because one of rustc's crates can't compile if we do)
1205
+ // (FIXME : we can't do that yet because one of rustc's crates can't compile if we do)
1240
1206
. for_each ( |( span, ffi_res) | self . process_ffi_result ( span, ffi_res, fn_mode) ) ;
1241
1207
//.drain();
1242
1208
}
@@ -1434,7 +1400,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
1434
1400
// Structs are checked based on if they follow the power alignment
1435
1401
// rule (under repr(C)).
1436
1402
hir:: ItemKind :: Struct ( ..) => {
1437
- ImproperCTypesLint { cx } . check_struct_for_power_alignment ( item) ;
1403
+ ImproperCTypesLint { cx } . check_struct_for_power_alignment ( item) ;
1438
1404
}
1439
1405
// See `check_field_def`..
1440
1406
hir:: ItemKind :: Union ( ..) | hir:: ItemKind :: Enum ( ..) => { }
0 commit comments