@@ -3,6 +3,7 @@ use std::iter;
33use std:: ops:: ControlFlow ;
44
55use rustc_abi:: { Integer , IntegerType , VariantIdx } ;
6+ use rustc_ast:: Mutability ;
67use rustc_data_structures:: fx:: FxHashSet ;
78use rustc_errors:: DiagMessage ;
89use rustc_hir:: def:: CtorKind ;
@@ -422,49 +423,50 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
422423
423424#[ allow( non_snake_case) ]
424425mod CTypesVisitorStateFlags {
425- pub ( super ) const NO_FLAGS : u8 = 0b00000 ;
426+ pub ( super ) const NO_FLAGS : u8 = 0b000000 ;
426427 /// for use in (externally-linked) static variables
427- pub ( super ) const STATIC : u8 = 0b00001 ;
428+ pub ( super ) const STATIC : u8 = 0b000001 ;
428429 /// for use in functions in general
429- pub ( super ) const FUNC : u8 = 0b00010 ;
430+ pub ( super ) const FUNC : u8 = 0b000010 ;
430431 /// for variables in function returns (implicitly: not for static variables)
431- pub ( super ) const FN_RETURN : u8 = 0b00100 ;
432- /// for variables in functions which are defined in rust (implicitly: not for static variables)
433- pub ( super ) const FN_DEFINED : u8 = 0b01000 ;
434- /// for time where we are only defining the type of something
432+ pub ( super ) const FN_RETURN : u8 = 0b000100 ;
433+ /// for variables in functions/variables which are defined in rust
434+ pub ( super ) const DEFINED : u8 = 0b001000 ;
435+ /// for times where we are only defining the type of something
435436 /// (struct/enum/union definitions, FnPtrs)
436- pub ( super ) const THEORETICAL : u8 = 0b10000 ;
437+ pub ( super ) const THEORETICAL : u8 = 0b010000 ;
438+ /// if we are looking at an interface where the value can be set by the non-rust side
439+ /// (important for e.g. nonzero assumptions)
440+ pub ( super ) const FOREIGN_VALUES : u8 = 0b100000 ;
437441}
438442
439443#[ repr( u8 ) ]
440444#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
441445enum CTypesVisitorState {
442446 None = CTypesVisitorStateFlags :: NO_FLAGS ,
443447 // uses bitflags from CTypesVisitorStateFlags
444- StaticTy = CTypesVisitorStateFlags :: STATIC ,
445- ExportedStaticTy = CTypesVisitorStateFlags :: STATIC | CTypesVisitorStateFlags :: FN_DEFINED ,
446- ArgumentTyInDefinition = CTypesVisitorStateFlags :: FUNC | CTypesVisitorStateFlags :: FN_DEFINED ,
448+ StaticTy = CTypesVisitorStateFlags :: STATIC | CTypesVisitorStateFlags :: FOREIGN_VALUES ,
449+ ExportedStaticTy = CTypesVisitorStateFlags :: STATIC | CTypesVisitorStateFlags :: DEFINED ,
450+ ExportedStaticMutTy = CTypesVisitorStateFlags :: STATIC
451+ | CTypesVisitorStateFlags :: DEFINED
452+ | CTypesVisitorStateFlags :: FOREIGN_VALUES ,
453+ ArgumentTyInDefinition = CTypesVisitorStateFlags :: FUNC
454+ | CTypesVisitorStateFlags :: DEFINED
455+ | CTypesVisitorStateFlags :: FOREIGN_VALUES ,
447456 ReturnTyInDefinition = CTypesVisitorStateFlags :: FUNC
448457 | CTypesVisitorStateFlags :: FN_RETURN
449- | CTypesVisitorStateFlags :: FN_DEFINED ,
458+ | CTypesVisitorStateFlags :: DEFINED ,
450459 ArgumentTyInDeclaration = CTypesVisitorStateFlags :: FUNC ,
451- ReturnTyInDeclaration = CTypesVisitorStateFlags :: FUNC | CTypesVisitorStateFlags :: FN_RETURN ,
460+ ReturnTyInDeclaration = CTypesVisitorStateFlags :: FUNC
461+ | CTypesVisitorStateFlags :: FN_RETURN
462+ | CTypesVisitorStateFlags :: FOREIGN_VALUES ,
452463 ArgumentTyInFnPtr = CTypesVisitorStateFlags :: FUNC | CTypesVisitorStateFlags :: THEORETICAL ,
453464 ReturnTyInFnPtr = CTypesVisitorStateFlags :: FUNC
454465 | CTypesVisitorStateFlags :: THEORETICAL
455466 | CTypesVisitorStateFlags :: FN_RETURN ,
456467}
457468
458469impl CTypesVisitorState {
459- /// whether the type is used in a static variable
460- fn is_in_static ( self ) -> bool {
461- use CTypesVisitorStateFlags :: * ;
462- let ret = ( ( self as u8 ) & STATIC ) != 0 ;
463- if ret {
464- assert ! ( ( ( self as u8 ) & FUNC ) == 0 ) ;
465- }
466- ret
467- }
468470 /// whether the type is used in a function
469471 fn is_in_function ( self ) -> bool {
470472 use CTypesVisitorStateFlags :: * ;
@@ -489,58 +491,35 @@ impl CTypesVisitorState {
489491 /// to be treated as an opaque type on the other side of the FFI boundary
490492 fn is_in_defined_function ( self ) -> bool {
491493 use CTypesVisitorStateFlags :: * ;
492- let ret = ( ( self as u8 ) & FN_DEFINED ) != 0 ;
493- #[ cfg( debug_assertions) ]
494- if ret {
495- assert ! ( self . is_in_function( ) ) ;
496- }
497- ret
498- }
499- /// whether we the type is used (directly or not) in a function pointer type
500- fn is_in_fn_ptr ( self ) -> bool {
501- use CTypesVisitorStateFlags :: * ;
502- ( ( self as u8 ) & THEORETICAL ) != 0 && self . is_in_function ( )
494+ ( ( self as u8 ) & DEFINED ) != 0 && self . is_in_function ( )
503495 }
504496
505497 /// whether we can expect type parameters and co in a given type
506498 fn can_expect_ty_params ( self ) -> bool {
507499 use CTypesVisitorStateFlags :: * ;
508- // rust-defined functions, as well as FnPtrs and ADT definitions
509- if ( ( self as u8 ) & THEORETICAL ) != 0 {
510- true
511- } else {
512- ( ( self as u8 ) & FN_DEFINED ) != 0 && ( ( self as u8 ) & STATIC ) == 0
513- }
500+ // rust-defined functions, as well as FnPtrs
501+ ( ( self as u8 ) & THEORETICAL ) != 0 || self . is_in_defined_function ( )
514502 }
515503
516504 /// whether the value for that type might come from the non-rust side of a FFI boundary
517505 /// this is particularly useful for non-raw pointers, since rust assume they are non-null
518506 fn value_may_be_unchecked ( self ) -> bool {
519- if self . is_in_static ( ) {
520- // FIXME: this is evidently untrue for non-mut static variables
521- // (assuming the cross-FFI code respects this)
522- true
523- } else if self . is_in_defined_function ( ) {
524- // function definitions are assumed to be maybe-not-rust-caller, rust-callee
525- !self . is_in_function_return ( )
526- } else if self . is_in_fn_ptr ( ) {
527- // 4 cases for function pointers:
528- // - rust caller, rust callee: everything comes from rust
529- // - non-rust-caller, non-rust callee: declaring invariants that are not valid
530- // is suboptimal, but ultimately not our problem
531- // - non-rust-caller, rust callee: there will be a function declaration somewhere,
532- // let's assume it will raise the appropriate warning in our stead
533- // - rust caller, non-rust callee: it's possible that the function is a callback,
534- // not something from a pre-declared API.
535- // so, in theory, we need to care about the function return being possibly non-rust-controlled.
536- // sadly, we need to ignore this because making pointers out of rust-defined functions
537- // would force to systematically cast or overwrap their return types...
538- // FIXME: is there anything better we can do here?
539- false
540- } else {
541- // function declarations are assumed to be rust-caller, non-rust-callee
542- self . is_in_function_return ( )
543- }
507+ // function definitions are assumed to be maybe-not-rust-caller, rust-callee
508+ // function declarations are assumed to be rust-caller, non-rust-callee
509+ // 4 cases for function pointers:
510+ // - rust caller, rust callee: everything comes from rust
511+ // - non-rust-caller, non-rust callee: declaring invariants that are not valid
512+ // is suboptimal, but ultimately not our problem
513+ // - non-rust-caller, rust callee: there will be a function declaration somewhere,
514+ // let's assume it will raise the appropriate warning in our stead
515+ // - rust caller, non-rust callee: it's possible that the function is a callback,
516+ // not something from a pre-declared API.
517+ // so, in theory, we need to care about the function return being possibly non-rust-controlled.
518+ // sadly, we need to ignore this because making pointers out of rust-defined functions
519+ // would force to systematically cast or overwrap their return types...
520+ // FIXME: is there anything better we can do here?
521+ use CTypesVisitorStateFlags :: * ;
522+ ( ( self as u8 ) & FOREIGN_VALUES ) != 0
544523 }
545524}
546525
@@ -1620,10 +1599,16 @@ impl ImproperCTypesLint {
16201599 cx : & LateContext < ' tcx > ,
16211600 id : hir:: OwnerId ,
16221601 span : Span ,
1602+ is_mut : bool ,
16231603 ) {
16241604 let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
16251605 let mut visitor = ImproperCTypesVisitor :: new ( cx) ;
1626- let ffi_res = visitor. check_for_type ( CTypesVisitorState :: ExportedStaticTy , ty) ;
1606+ let state = if is_mut {
1607+ CTypesVisitorState :: ExportedStaticMutTy
1608+ } else {
1609+ CTypesVisitorState :: ExportedStaticTy
1610+ } ;
1611+ let ffi_res = visitor. check_for_type ( state, ty) ;
16271612 self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ExportedStatic ) ;
16281613 }
16291614
@@ -1810,11 +1795,15 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
18101795 cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ,
18111796 ) ;
18121797
1813- if matches ! ( item . kind , hir:: ItemKind :: Static ( .. ) )
1798+ if let hir:: ItemKind :: Static ( _ , _ , is_mut , _ ) = item . kind
18141799 && ( cx. tcx . has_attr ( item. owner_id , sym:: no_mangle)
18151800 || cx. tcx . has_attr ( item. owner_id , sym:: export_name) )
18161801 {
1817- self . check_exported_static ( cx, item. owner_id , ty. span ) ;
1802+ let is_mut = match is_mut {
1803+ Mutability :: Not => false ,
1804+ Mutability :: Mut => true ,
1805+ } ;
1806+ self . check_exported_static ( cx, item. owner_id , ty. span , is_mut) ;
18181807 }
18191808 }
18201809 // See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
0 commit comments