@@ -4,6 +4,7 @@ use std::iter;
44use std:: ops:: ControlFlow ;
55
66use rustc_abi:: { Integer , IntegerType , VariantIdx } ;
7+ use rustc_ast:: Mutability ;
78use rustc_data_structures:: fx:: FxHashSet ;
89use rustc_errors:: DiagMessage ;
910use rustc_hir:: def:: CtorKind ;
@@ -423,33 +424,43 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
423424
424425#[ allow( non_snake_case) ]
425426mod CTypesVisitorStateFlags {
426- pub ( super ) const NO_FLAGS : u8 = 0b00000 ;
427+ pub ( super ) const NO_FLAGS : u8 = 0b000000 ;
427428 /// for use in (externally-linked) static variables
428- pub ( super ) const STATIC : u8 = 0b00001 ;
429+ pub ( super ) const STATIC : u8 = 0b000001 ;
429430 /// for use in functions in general
430- pub ( super ) const FUNC : u8 = 0b00010 ;
431+ pub ( super ) const FUNC : u8 = 0b000010 ;
431432 /// for variables in function returns (implicitly: not for static variables)
432- pub ( super ) const FN_RETURN : u8 = 0b00100 ;
433- /// for variables in functions which are defined in rust (implicitly: not for static variables)
434- pub ( super ) const FN_DEFINED : u8 = 0b01000 ;
435- /// for time where we are only defining the type of something
433+ pub ( super ) const FN_RETURN : u8 = 0b000100 ;
434+ /// for variables in functions/variables which are defined in rust
435+ pub ( super ) const DEFINED : u8 = 0b001000 ;
436+ /// for times where we are only defining the type of something
436437 /// (struct/enum/union definitions, FnPtrs)
437- pub ( super ) const THEORETICAL : u8 = 0b10000 ;
438+ pub ( super ) const THEORETICAL : u8 = 0b010000 ;
439+ /// if we are looking at an interface where the value can be set by the non-rust side
440+ /// (important for e.g. nonzero assumptions)
441+ pub ( super ) const FOREIGN_VALUES : u8 = 0b100000 ;
438442}
439443
440444#[ repr( u8 ) ]
441445#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
442446enum CTypesVisitorState {
443447 None = CTypesVisitorStateFlags :: NO_FLAGS ,
444448 // uses bitflags from CTypesVisitorStateFlags
445- StaticTy = CTypesVisitorStateFlags :: STATIC ,
446- ExportedStaticTy = CTypesVisitorStateFlags :: STATIC | CTypesVisitorStateFlags :: FN_DEFINED ,
447- ArgumentTyInDefinition = CTypesVisitorStateFlags :: FUNC | CTypesVisitorStateFlags :: FN_DEFINED ,
449+ StaticTy = CTypesVisitorStateFlags :: STATIC | CTypesVisitorStateFlags :: FOREIGN_VALUES ,
450+ ExportedStaticTy = CTypesVisitorStateFlags :: STATIC | CTypesVisitorStateFlags :: DEFINED ,
451+ ExportedStaticMutTy = CTypesVisitorStateFlags :: STATIC
452+ | CTypesVisitorStateFlags :: DEFINED
453+ | CTypesVisitorStateFlags :: FOREIGN_VALUES ,
454+ ArgumentTyInDefinition = CTypesVisitorStateFlags :: FUNC
455+ | CTypesVisitorStateFlags :: DEFINED
456+ | CTypesVisitorStateFlags :: FOREIGN_VALUES ,
448457 ReturnTyInDefinition = CTypesVisitorStateFlags :: FUNC
449458 | CTypesVisitorStateFlags :: FN_RETURN
450- | CTypesVisitorStateFlags :: FN_DEFINED ,
459+ | CTypesVisitorStateFlags :: DEFINED ,
451460 ArgumentTyInDeclaration = CTypesVisitorStateFlags :: FUNC ,
452- ReturnTyInDeclaration = CTypesVisitorStateFlags :: FUNC | CTypesVisitorStateFlags :: FN_RETURN ,
461+ ReturnTyInDeclaration = CTypesVisitorStateFlags :: FUNC
462+ | CTypesVisitorStateFlags :: FN_RETURN
463+ | CTypesVisitorStateFlags :: FOREIGN_VALUES ,
453464 ArgumentTyInFnPtr = CTypesVisitorStateFlags :: FUNC | CTypesVisitorStateFlags :: THEORETICAL ,
454465 ReturnTyInFnPtr = CTypesVisitorStateFlags :: FUNC
455466 | CTypesVisitorStateFlags :: THEORETICAL
@@ -490,58 +501,35 @@ impl CTypesVisitorState {
490501 /// to be treated as an opaque type on the other side of the FFI boundary
491502 fn is_in_defined_function ( self ) -> bool {
492503 use CTypesVisitorStateFlags :: * ;
493- let ret = ( ( self as u8 ) & FN_DEFINED ) != 0 ;
494- #[ cfg( debug_assertions) ]
495- if ret {
496- assert ! ( self . is_in_function( ) ) ;
497- }
498- ret
499- }
500- /// whether we the type is used (directly or not) in a function pointer type
501- fn is_in_fn_ptr ( self ) -> bool {
502- use CTypesVisitorStateFlags :: * ;
503- ( ( self as u8 ) & THEORETICAL ) != 0 && self . is_in_function ( )
504+ ( ( self as u8 ) & DEFINED ) != 0 && self . is_in_function ( )
504505 }
505506
506507 /// whether we can expect type parameters and co in a given type
507508 fn can_expect_ty_params ( self ) -> bool {
508509 use CTypesVisitorStateFlags :: * ;
509- // rust-defined functions, as well as FnPtrs and ADT definitions
510- if ( ( self as u8 ) & THEORETICAL ) != 0 {
511- true
512- } else {
513- ( ( self as u8 ) & FN_DEFINED ) != 0 && ( ( self as u8 ) & STATIC ) == 0
514- }
510+ // rust-defined functions, as well as FnPtrs
511+ ( ( self as u8 ) & THEORETICAL ) != 0 || self . is_in_defined_function ( )
515512 }
516513
517514 /// whether the value for that type might come from the non-rust side of a FFI boundary
518515 /// this is particularly useful for non-raw pointers, since rust assume they are non-null
519516 fn value_may_be_unchecked ( self ) -> bool {
520- if self . is_in_static ( ) {
521- // FIXME: this is evidently untrue for non-mut static variables
522- // (assuming the cross-FFI code respects this)
523- true
524- } else if self . is_in_defined_function ( ) {
525- // function definitions are assumed to be maybe-not-rust-caller, rust-callee
526- !self . is_in_function_return ( )
527- } else if self . is_in_fn_ptr ( ) {
528- // 4 cases for function pointers:
529- // - rust caller, rust callee: everything comes from rust
530- // - non-rust-caller, non-rust callee: declaring invariants that are not valid
531- // is suboptimal, but ultimately not our problem
532- // - non-rust-caller, rust callee: there will be a function declaration somewhere,
533- // let's assume it will raise the appropriate warning in our stead
534- // - rust caller, non-rust callee: it's possible that the function is a callback,
535- // not something from a pre-declared API.
536- // so, in theory, we need to care about the function return being possibly non-rust-controlled.
537- // sadly, we need to ignore this because making pointers out of rust-defined functions
538- // would force to systematically cast or overwrap their return types...
539- // FIXME: is there anything better we can do here?
540- false
541- } else {
542- // function declarations are assumed to be rust-caller, non-rust-callee
543- self . is_in_function_return ( )
544- }
517+ // function definitions are assumed to be maybe-not-rust-caller, rust-callee
518+ // function declarations are assumed to be rust-caller, non-rust-callee
519+ // 4 cases for function pointers:
520+ // - rust caller, rust callee: everything comes from rust
521+ // - non-rust-caller, non-rust callee: declaring invariants that are not valid
522+ // is suboptimal, but ultimately not our problem
523+ // - non-rust-caller, rust callee: there will be a function declaration somewhere,
524+ // let's assume it will raise the appropriate warning in our stead
525+ // - rust caller, non-rust callee: it's possible that the function is a callback,
526+ // not something from a pre-declared API.
527+ // so, in theory, we need to care about the function return being possibly non-rust-controlled.
528+ // sadly, we need to ignore this because making pointers out of rust-defined functions
529+ // would force to systematically cast or overwrap their return types...
530+ // FIXME: is there anything better we can do here?
531+ use CTypesVisitorStateFlags :: * ;
532+ ( ( self as u8 ) & FOREIGN_VALUES ) != 0
545533 }
546534}
547535
@@ -1662,10 +1650,21 @@ impl ImproperCTypesLint {
16621650 }
16631651
16641652 /// Check that a `#[no_mangle]`/`#[export_name = _]` static variable is of a ffi-safe type
1665- fn check_exported_static < ' tcx > ( & self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
1653+ fn check_exported_static < ' tcx > (
1654+ & self ,
1655+ cx : & LateContext < ' tcx > ,
1656+ id : hir:: OwnerId ,
1657+ span : Span ,
1658+ is_mut : bool ,
1659+ ) {
16661660 let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
16671661 let visitor = ImproperCTypesVisitor :: new ( cx) ;
1668- let ffi_res = visitor. check_for_type ( CTypesVisitorState :: ExportedStaticTy , ty) ;
1662+ let state = if is_mut {
1663+ CTypesVisitorState :: ExportedStaticMutTy
1664+ } else {
1665+ CTypesVisitorState :: ExportedStaticTy
1666+ } ;
1667+ let ffi_res = visitor. check_for_type ( state, ty) ;
16691668 self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ExportedStatic ) ;
16701669 }
16711670
@@ -1852,11 +1851,15 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
18521851 cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ,
18531852 ) ;
18541853
1855- if matches ! ( item . kind , hir:: ItemKind :: Static ( .. ) )
1854+ if let hir:: ItemKind :: Static ( _ , _ , is_mut , _ ) = item . kind
18561855 && ( cx. tcx . has_attr ( item. owner_id , sym:: no_mangle)
18571856 || cx. tcx . has_attr ( item. owner_id , sym:: export_name) )
18581857 {
1859- self . check_exported_static ( cx, item. owner_id , ty. span ) ;
1858+ let is_mut = match is_mut {
1859+ Mutability :: Not => false ,
1860+ Mutability :: Mut => true ,
1861+ } ;
1862+ self . check_exported_static ( cx, item. owner_id , ty. span , is_mut) ;
18601863 }
18611864 }
18621865 // See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
0 commit comments