@@ -3,6 +3,7 @@ use std::iter;
3
3
use std:: ops:: ControlFlow ;
4
4
5
5
use rustc_abi:: { Integer , IntegerType , VariantIdx } ;
6
+ use rustc_ast:: Mutability ;
6
7
use rustc_data_structures:: fx:: FxHashSet ;
7
8
use rustc_errors:: DiagMessage ;
8
9
use rustc_hir:: def:: CtorKind ;
@@ -422,49 +423,50 @@ 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
455
466
| CTypesVisitorStateFlags :: FN_RETURN ,
456
467
}
457
468
458
469
impl 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
- }
468
470
/// whether the type is used in a function
469
471
fn is_in_function ( self ) -> bool {
470
472
use CTypesVisitorStateFlags :: * ;
@@ -489,58 +491,35 @@ impl CTypesVisitorState {
489
491
/// to be treated as an opaque type on the other side of the FFI boundary
490
492
fn is_in_defined_function ( self ) -> bool {
491
493
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 ( )
503
495
}
504
496
505
497
/// whether we can expect type parameters and co in a given type
506
498
fn can_expect_ty_params ( self ) -> bool {
507
499
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 ( )
514
502
}
515
503
516
504
/// whether the value for that type might come from the non-rust side of a FFI boundary
517
505
/// this is particularly useful for non-raw pointers, since rust assume they are non-null
518
506
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
544
523
}
545
524
}
546
525
@@ -1620,10 +1599,16 @@ impl ImproperCTypesLint {
1620
1599
cx : & LateContext < ' tcx > ,
1621
1600
id : hir:: OwnerId ,
1622
1601
span : Span ,
1602
+ is_mut : bool ,
1623
1603
) {
1624
1604
let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
1625
1605
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) ;
1627
1612
self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ExportedStatic ) ;
1628
1613
}
1629
1614
@@ -1810,11 +1795,15 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1810
1795
cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ,
1811
1796
) ;
1812
1797
1813
- if matches ! ( item . kind , hir:: ItemKind :: Static ( .. ) )
1798
+ if let hir:: ItemKind :: Static ( _ , _ , is_mut , _ ) = item . kind
1814
1799
&& ( cx. tcx . has_attr ( item. owner_id , sym:: no_mangle)
1815
1800
|| cx. tcx . has_attr ( item. owner_id , sym:: export_name) )
1816
1801
{
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) ;
1818
1807
}
1819
1808
}
1820
1809
// See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
0 commit comments