@@ -4,6 +4,7 @@ use std::iter;
4
4
use std:: ops:: ControlFlow ;
5
5
6
6
use rustc_abi:: 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 ;
@@ -422,33 +423,43 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
422
423
423
424
#[ allow( non_snake_case) ]
424
425
mod CTypesVisitorStateFlags {
425
- pub ( super ) const NO_FLAGS : u8 = 0b00000 ;
426
+ pub ( super ) const NO_FLAGS : u8 = 0b000000 ;
426
427
/// for use in (externally-linked) static variables
427
- pub ( super ) const STATIC : u8 = 0b00001 ;
428
+ pub ( super ) const STATIC : u8 = 0b000001 ;
428
429
/// for use in functions in general
429
- pub ( super ) const FUNC : u8 = 0b00010 ;
430
+ pub ( super ) const FUNC : u8 = 0b000010 ;
430
431
/// 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
435
436
/// (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 ;
437
441
}
438
442
439
443
#[ repr( u8 ) ]
440
444
#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
441
445
enum CTypesVisitorState {
442
446
None = CTypesVisitorStateFlags :: NO_FLAGS ,
443
447
// 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 ,
447
456
ReturnTyInDefinition = CTypesVisitorStateFlags :: FUNC
448
457
| CTypesVisitorStateFlags :: FN_RETURN
449
- | CTypesVisitorStateFlags :: FN_DEFINED ,
458
+ | CTypesVisitorStateFlags :: DEFINED ,
450
459
ArgumentTyInDeclaration = CTypesVisitorStateFlags :: FUNC ,
451
- ReturnTyInDeclaration = CTypesVisitorStateFlags :: FUNC | CTypesVisitorStateFlags :: FN_RETURN ,
460
+ ReturnTyInDeclaration = CTypesVisitorStateFlags :: FUNC
461
+ | CTypesVisitorStateFlags :: FN_RETURN
462
+ | CTypesVisitorStateFlags :: FOREIGN_VALUES ,
452
463
ArgumentTyInFnPtr = CTypesVisitorStateFlags :: FUNC | CTypesVisitorStateFlags :: THEORETICAL ,
453
464
ReturnTyInFnPtr = CTypesVisitorStateFlags :: FUNC
454
465
| CTypesVisitorStateFlags :: THEORETICAL
@@ -489,58 +500,35 @@ impl CTypesVisitorState {
489
500
/// to be treated as an opaque type on the other side of the FFI boundary
490
501
fn is_in_defined_function ( self ) -> bool {
491
502
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 ( )
503
+ ( ( self as u8 ) & DEFINED ) != 0 && self . is_in_function ( )
503
504
}
504
505
505
506
/// whether we can expect type parameters and co in a given type
506
507
fn can_expect_ty_params ( self ) -> bool {
507
508
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
- }
509
+ // rust-defined functions, as well as FnPtrs
510
+ ( ( self as u8 ) & THEORETICAL ) != 0 || self . is_in_defined_function ( )
514
511
}
515
512
516
513
/// whether the value for that type might come from the non-rust side of a FFI boundary
517
514
/// this is particularly useful for non-raw pointers, since rust assume they are non-null
518
515
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
- }
516
+ // function definitions are assumed to be maybe-not-rust-caller, rust-callee
517
+ // function declarations are assumed to be rust-caller, non-rust-callee
518
+ // 4 cases for function pointers:
519
+ // - rust caller, rust callee: everything comes from rust
520
+ // - non-rust-caller, non-rust callee: declaring invariants that are not valid
521
+ // is suboptimal, but ultimately not our problem
522
+ // - non-rust-caller, rust callee: there will be a function declaration somewhere,
523
+ // let's assume it will raise the appropriate warning in our stead
524
+ // - rust caller, non-rust callee: it's possible that the function is a callback,
525
+ // not something from a pre-declared API.
526
+ // so, in theory, we need to care about the function return being possibly non-rust-controlled.
527
+ // sadly, we need to ignore this because making pointers out of rust-defined functions
528
+ // would force to systematically cast or overwrap their return types...
529
+ // FIXME: is there anything better we can do here?
530
+ use CTypesVisitorStateFlags :: * ;
531
+ ( ( self as u8 ) & FOREIGN_VALUES ) != 0
544
532
}
545
533
}
546
534
@@ -1654,10 +1642,21 @@ impl ImproperCTypesLint {
1654
1642
}
1655
1643
1656
1644
/// Check that a `#[no_mangle]`/`#[export_name = _]` static variable is of a ffi-safe type
1657
- fn check_exported_static < ' tcx > ( & self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
1645
+ fn check_exported_static < ' tcx > (
1646
+ & self ,
1647
+ cx : & LateContext < ' tcx > ,
1648
+ id : hir:: OwnerId ,
1649
+ span : Span ,
1650
+ is_mut : bool ,
1651
+ ) {
1658
1652
let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
1659
1653
let visitor = ImproperCTypesVisitor :: new ( cx) ;
1660
- let ffi_res = visitor. check_for_type ( CTypesVisitorState :: ExportedStaticTy , ty) ;
1654
+ let state = if is_mut {
1655
+ CTypesVisitorState :: ExportedStaticMutTy
1656
+ } else {
1657
+ CTypesVisitorState :: ExportedStaticTy
1658
+ } ;
1659
+ let ffi_res = visitor. check_for_type ( state, ty) ;
1661
1660
self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ExportedStatic ) ;
1662
1661
}
1663
1662
@@ -1844,11 +1843,27 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1844
1843
cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ,
1845
1844
) ;
1846
1845
1847
- if matches ! ( item. kind, hir:: ItemKind :: Static ( ..) )
1848
- && ( cx. tcx . has_attr ( item. owner_id , sym:: no_mangle)
1849
- || cx. tcx . has_attr ( item. owner_id , sym:: export_name) )
1850
- {
1851
- self . check_exported_static ( cx, item. owner_id , ty. span ) ;
1846
+ // FIXME: cx.tcx.has_attr no worky
1847
+ // if let hir::ItemKind::Static(is_mut, _, _, _) = item.kind
1848
+ // && (cx.tcx.has_attr(item.owner_id, sym::no_mangle)
1849
+ // || cx.tcx.has_attr(item.owner_id, sym::export_name))
1850
+ if let hir:: ItemKind :: Static ( is_mut, _, _, _) = item. kind {
1851
+ let is_exported_static = cx. tcx . get_all_attrs ( item. owner_id ) . iter ( ) . any ( |x| {
1852
+ matches ! (
1853
+ x,
1854
+ hir:: Attribute :: Parsed (
1855
+ hir:: attrs:: AttributeKind :: NoMangle ( _)
1856
+ | hir:: attrs:: AttributeKind :: ExportName { .. }
1857
+ )
1858
+ )
1859
+ } ) ;
1860
+ if is_exported_static {
1861
+ let is_mut = match is_mut {
1862
+ Mutability :: Not => false ,
1863
+ Mutability :: Mut => true ,
1864
+ } ;
1865
+ self . check_exported_static ( cx, item. owner_id , ty. span , is_mut) ;
1866
+ }
1852
1867
}
1853
1868
}
1854
1869
// See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
0 commit comments