@@ -740,35 +740,49 @@ enum FfiResult<'tcx> {
740
740
} ,
741
741
}
742
742
743
- pub ( crate ) fn is_unsized_because_foreign < ' tcx , ' a > (
744
- cx : & ' a LateContext < ' tcx > ,
745
- ty : Ty < ' tcx > ,
746
- ) -> Result < bool , ( ) > {
743
+ /// Determine if a type is sized or not, and wether it affects references/pointers/boxes to it
744
+ #[ derive( Clone , Copy ) ]
745
+ enum TypeSizedness {
746
+ /// sized type (pointers are C-compatible)
747
+ Sized ,
748
+ /// unsized type because it includes an opaque/foreign type (pointers are C-compatible)
749
+ UnsizedBecauseForeign ,
750
+ /// unsized type for other reasons (slice, string, dyn Trait, closure, ...) (pointers are not C-compatible)
751
+ UnsizedWithMetadata ,
752
+ }
753
+
754
+ /// Is this type unsized because it contains (or is) a foreign type?
755
+ /// (Returns Err if the type happens to be sized after all)
756
+ fn get_type_sizedness < ' tcx , ' a > ( cx : & ' a LateContext < ' tcx > , ty : Ty < ' tcx > ) -> TypeSizedness {
747
757
let tcx = cx. tcx ;
748
758
749
759
if ty. is_sized ( tcx, cx. typing_env ( ) ) {
750
- Err ( ( ) )
760
+ TypeSizedness :: Sized
751
761
} else {
752
- Ok ( match ty. kind ( ) {
753
- ty:: Slice ( _) => false ,
754
- ty:: Str => false ,
755
- ty:: Dynamic ( ..) => false ,
756
- ty:: Foreign ( ..) => true ,
757
- ty:: Alias ( ty:: Opaque , ..) => todo ! ( "why" ) ,
762
+ match ty. kind ( ) {
763
+ ty:: Slice ( _) => TypeSizedness :: UnsizedWithMetadata ,
764
+ ty:: Str => TypeSizedness :: UnsizedWithMetadata ,
765
+ ty:: Dynamic ( ..) => TypeSizedness :: UnsizedWithMetadata ,
766
+ ty:: Foreign ( ..) => TypeSizedness :: UnsizedBecauseForeign ,
767
+ // While opaque types are checked for earlier, if a projection in a struct field
768
+ // normalizes to an opaque type, then it will reach this branch.
769
+ ty:: Alias ( ty:: Opaque , ..) => todo ! ( "We... don't know enough about this type yet?" ) ,
758
770
ty:: Adt ( def, args) => {
759
771
// for now assume: boxes and phantoms don't mess with this
760
772
match def. adt_kind ( ) {
761
- AdtKind :: Union | AdtKind :: Enum => true ,
773
+ AdtKind :: Union | AdtKind :: Enum => {
774
+ bug ! ( "unions and enums are necessarily sized" )
775
+ }
762
776
AdtKind :: Struct => {
763
777
if let Some ( sym:: cstring_type | sym:: cstr_type) =
764
778
tcx. get_diagnostic_name ( def. did ( ) )
765
779
{
766
- return Ok ( false ) ;
780
+ return TypeSizedness :: UnsizedWithMetadata ;
767
781
}
768
782
// FIXME: how do we deal with non-exhaustive unsized structs/unions?
769
783
770
784
if def. non_enum_variant ( ) . fields . is_empty ( ) {
771
- bug ! ( "empty unsized struct/union. what? " ) ;
785
+ bug ! ( "an empty struct is necessarily sized " ) ;
772
786
}
773
787
774
788
let variant = def. non_enum_variant ( ) ;
@@ -781,7 +795,13 @@ pub(crate) fn is_unsized_because_foreign<'tcx, 'a>(
781
795
. tcx
782
796
. try_normalize_erasing_regions ( cx. typing_env ( ) , field_ty)
783
797
. unwrap_or ( field_ty) ;
784
- return Ok ( is_unsized_because_foreign ( cx, field_ty) . unwrap ( ) ) ;
798
+ match get_type_sizedness ( cx, field_ty) {
799
+ s @ ( TypeSizedness :: UnsizedWithMetadata
800
+ | TypeSizedness :: UnsizedBecauseForeign ) => s,
801
+ TypeSizedness :: Sized => {
802
+ bug ! ( "failed to find the reason why struct `{:?}` is unsized" , ty)
803
+ }
804
+ }
785
805
}
786
806
}
787
807
}
@@ -794,12 +814,21 @@ pub(crate) fn is_unsized_because_foreign<'tcx, 'a>(
794
814
. tcx
795
815
. try_normalize_erasing_regions ( cx. typing_env ( ) , field_ty)
796
816
. unwrap_or ( field_ty) ;
797
- is_unsized_because_foreign ( cx, field_ty) . unwrap ( )
817
+ match get_type_sizedness ( cx, field_ty) {
818
+ s @ ( TypeSizedness :: UnsizedWithMetadata
819
+ | TypeSizedness :: UnsizedBecauseForeign ) => s,
820
+ TypeSizedness :: Sized => {
821
+ bug ! ( "failed to find the reason why tuple `{:?}` is unsized" , ty)
822
+ }
823
+ }
798
824
}
799
825
t => {
800
- bug ! ( "we shouldn't be looking if this is unsized for a reason or another: {:?}" , t)
826
+ bug ! (
827
+ "we shouldn't be trying to determine if this is unsized for a reason or another: `{:?}`" ,
828
+ t
829
+ )
801
830
}
802
- } )
831
+ }
803
832
}
804
833
}
805
834
@@ -1106,8 +1135,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1106
1135
match * ty. kind ( ) {
1107
1136
ty:: Adt ( def, args) => {
1108
1137
if let Some ( inner_ty) = ty. boxed_ty ( ) {
1109
- if inner_ty . is_sized ( tcx , self . cx . typing_env ( ) )
1110
- || is_unsized_because_foreign ( self . cx , inner_ty) . unwrap ( )
1138
+ if let TypeSizedness :: UnsizedBecauseForeign | TypeSizedness :: Sized =
1139
+ get_type_sizedness ( self . cx , inner_ty)
1111
1140
{
1112
1141
// discussion on declaration vs definition:
1113
1142
// see the `ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _)` arm
@@ -1311,13 +1340,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1311
1340
}
1312
1341
1313
1342
ty:: RawPtr ( inner_ty, _) | ty:: Ref ( _, inner_ty, _) => {
1314
- if inner_ty . is_sized ( tcx , self . cx . typing_env ( ) )
1315
- || is_unsized_because_foreign ( self . cx , inner_ty) . unwrap ( )
1343
+ if let TypeSizedness :: UnsizedBecauseForeign | TypeSizedness :: Sized =
1344
+ get_type_sizedness ( self . cx , inner_ty)
1316
1345
{
1317
1346
// there's a nuance on what this lint should do for function definitions
1318
- // (touched upon in https://github.com/rust-lang/rust/issues/66220 and https://github.com/rust-lang/rust/pull/72700)
1319
- //
1320
1347
// (`extern "C" fn fn_name(...) {...}`) versus declarations (`extern "C" {fn fn_name(...);}`).
1348
+ // (this is touched upon in https://github.com/rust-lang/rust/issues/66220
1349
+ // and https://github.com/rust-lang/rust/pull/72700)
1350
+ //
1321
1351
// The big question is: what does "ABI safety" mean? if you have something translated to a C pointer
1322
1352
// (which has a stable layout) but points to FFI-unsafe type, is it safe?
1323
1353
// on one hand, the function's ABI will match that of a similar C-declared function API,
@@ -1609,7 +1639,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1609
1639
}
1610
1640
} ;
1611
1641
}
1612
- let last_ty = last_ty. unwrap ( ) ; // populated by any run of the `while` block
1642
+ let last_ty = match last_ty {
1643
+ Some ( last_ty) => last_ty,
1644
+ None => bug ! (
1645
+ "This option should definitely have been filled by the loop that just finished"
1646
+ ) ,
1647
+ } ;
1613
1648
self . emit_ffi_unsafe_type_lint ( last_ty, sp, cimproper_layers) ;
1614
1649
}
1615
1650
}
0 commit comments