@@ -740,35 +740,49 @@ enum FfiResult<'tcx> {
740740 } ,
741741}
742742
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 {
747757 let tcx = cx. tcx ;
748758
749759 if ty. is_sized ( tcx, cx. typing_env ( ) ) {
750- Err ( ( ) )
760+ TypeSizedness :: Sized
751761 } 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?" ) ,
758770 ty:: Adt ( def, args) => {
759771 // for now assume: boxes and phantoms don't mess with this
760772 match def. adt_kind ( ) {
761- AdtKind :: Union | AdtKind :: Enum => true ,
773+ AdtKind :: Union | AdtKind :: Enum => {
774+ bug ! ( "unions and enums are necessarily sized" )
775+ }
762776 AdtKind :: Struct => {
763777 if let Some ( sym:: cstring_type | sym:: cstr_type) =
764778 tcx. get_diagnostic_name ( def. did ( ) )
765779 {
766- return Ok ( false ) ;
780+ return TypeSizedness :: UnsizedWithMetadata ;
767781 }
768782 // FIXME: how do we deal with non-exhaustive unsized structs/unions?
769783
770784 if def. non_enum_variant ( ) . fields . is_empty ( ) {
771- bug ! ( "empty unsized struct/union. what? " ) ;
785+ bug ! ( "an empty struct is necessarily sized " ) ;
772786 }
773787
774788 let variant = def. non_enum_variant ( ) ;
@@ -781,7 +795,13 @@ pub(crate) fn is_unsized_because_foreign<'tcx, 'a>(
781795 . tcx
782796 . try_normalize_erasing_regions ( cx. typing_env ( ) , field_ty)
783797 . 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+ }
785805 }
786806 }
787807 }
@@ -794,12 +814,21 @@ pub(crate) fn is_unsized_because_foreign<'tcx, 'a>(
794814 . tcx
795815 . try_normalize_erasing_regions ( cx. typing_env ( ) , field_ty)
796816 . 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+ }
798824 }
799825 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+ )
801830 }
802- } )
831+ }
803832 }
804833}
805834
@@ -1106,8 +1135,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11061135 match * ty. kind ( ) {
11071136 ty:: Adt ( def, args) => {
11081137 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)
11111140 {
11121141 // discussion on declaration vs definition:
11131142 // see the `ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _)` arm
@@ -1311,13 +1340,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13111340 }
13121341
13131342 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)
13161345 {
13171346 // 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- //
13201347 // (`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+ //
13211351 // The big question is: what does "ABI safety" mean? if you have something translated to a C pointer
13221352 // (which has a stable layout) but points to FFI-unsafe type, is it safe?
13231353 // 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> {
16091639 }
16101640 } ;
16111641 }
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+ } ;
16131648 self . emit_ffi_unsafe_type_lint ( last_ty, sp, cimproper_layers) ;
16141649 }
16151650 }
0 commit comments