@@ -4,6 +4,7 @@ use std::iter;
4
4
use std:: ops:: ControlFlow ;
5
5
6
6
use rustc_abi:: { Integer , IntegerType , VariantIdx } ;
7
+ use rustc_ast:: Mutability ;
7
8
use rustc_data_structures:: fx:: FxHashSet ;
8
9
use rustc_errors:: DiagMessage ;
9
10
use rustc_hir:: def:: CtorKind ;
@@ -423,33 +424,43 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
423
424
424
425
#[ allow( non_snake_case) ]
425
426
mod CTypesVisitorStateFlags {
426
- pub ( super ) const NO_FLAGS : u8 = 0b00000 ;
427
+ pub ( super ) const NO_FLAGS : u8 = 0b000000 ;
427
428
/// for use in (externally-linked) static variables
428
- pub ( super ) const STATIC : u8 = 0b00001 ;
429
+ pub ( super ) const STATIC : u8 = 0b000001 ;
429
430
/// for use in functions in general
430
- pub ( super ) const FUNC : u8 = 0b00010 ;
431
+ pub ( super ) const FUNC : u8 = 0b000010 ;
431
432
/// 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
436
437
/// (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 ;
438
442
}
439
443
440
444
#[ repr( u8 ) ]
441
445
#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
442
446
enum CTypesVisitorState {
443
447
None = CTypesVisitorStateFlags :: NO_FLAGS ,
444
448
// 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 ,
448
457
ReturnTyInDefinition = CTypesVisitorStateFlags :: FUNC
449
458
| CTypesVisitorStateFlags :: FN_RETURN
450
- | CTypesVisitorStateFlags :: FN_DEFINED ,
459
+ | CTypesVisitorStateFlags :: DEFINED ,
451
460
ArgumentTyInDeclaration = CTypesVisitorStateFlags :: FUNC ,
452
- ReturnTyInDeclaration = CTypesVisitorStateFlags :: FUNC | CTypesVisitorStateFlags :: FN_RETURN ,
461
+ ReturnTyInDeclaration = CTypesVisitorStateFlags :: FUNC
462
+ | CTypesVisitorStateFlags :: FN_RETURN
463
+ | CTypesVisitorStateFlags :: FOREIGN_VALUES ,
453
464
ArgumentTyInFnPtr = CTypesVisitorStateFlags :: FUNC | CTypesVisitorStateFlags :: THEORETICAL ,
454
465
ReturnTyInFnPtr = CTypesVisitorStateFlags :: FUNC
455
466
| CTypesVisitorStateFlags :: THEORETICAL
@@ -490,58 +501,35 @@ impl CTypesVisitorState {
490
501
/// to be treated as an opaque type on the other side of the FFI boundary
491
502
fn is_in_defined_function ( self ) -> bool {
492
503
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 ( )
504
505
}
505
506
506
507
/// whether we can expect type parameters and co in a given type
507
508
fn can_expect_ty_params ( self ) -> bool {
508
509
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 ( )
515
512
}
516
513
517
514
/// whether the value for that type might come from the non-rust side of a FFI boundary
518
515
/// this is particularly useful for non-raw pointers, since rust assume they are non-null
519
516
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
545
533
}
546
534
}
547
535
@@ -1662,10 +1650,21 @@ impl ImproperCTypesLint {
1662
1650
}
1663
1651
1664
1652
/// 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
+ ) {
1666
1660
let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
1667
1661
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) ;
1669
1668
self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ExportedStatic ) ;
1670
1669
}
1671
1670
@@ -1852,11 +1851,15 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1852
1851
cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ,
1853
1852
) ;
1854
1853
1855
- if matches ! ( item . kind , hir:: ItemKind :: Static ( .. ) )
1854
+ if let hir:: ItemKind :: Static ( _ , _ , is_mut , _ ) = item . kind
1856
1855
&& ( cx. tcx . has_attr ( item. owner_id , sym:: no_mangle)
1857
1856
|| cx. tcx . has_attr ( item. owner_id , sym:: export_name) )
1858
1857
{
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) ;
1860
1863
}
1861
1864
}
1862
1865
// See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
0 commit comments