@@ -828,6 +828,8 @@ enum TypeSizedness {
828828 UnsizedWithExternType ,
829829 /// unsized type for other reasons (slice, string, dyn Trait, closure, ...) (pointers are not C-compatible)
830830 UnsizedWithMetadata ,
831+ /// not known, usually for placeholder types (Self in non-impl trait functions, type parameters, aliases, the like)
832+ NotYetKnown ,
831833}
832834
833835/// what type indirection points to a given type
@@ -846,17 +848,16 @@ enum IndirectionType {
846848fn get_type_sizedness < ' tcx , ' a > ( cx : & ' a LateContext < ' tcx > , ty : Ty < ' tcx > ) -> TypeSizedness {
847849 let tcx = cx. tcx ;
848850
851+ // note that sizedness is unrelated to inhabitedness
849852 if ty. is_sized ( tcx, cx. typing_env ( ) ) {
850853 TypeSizedness :: Definite
851854 } else {
855+ // the overall type is !Sized or ?Sized
852856 match ty. kind ( ) {
853857 ty:: Slice ( _) => TypeSizedness :: UnsizedWithMetadata ,
854858 ty:: Str => TypeSizedness :: UnsizedWithMetadata ,
855859 ty:: Dynamic ( ..) => TypeSizedness :: UnsizedWithMetadata ,
856860 ty:: Foreign ( ..) => TypeSizedness :: UnsizedWithExternType ,
857- // While opaque types are checked for earlier, if a projection in a struct field
858- // normalizes to an opaque type, then it will reach this branch.
859- ty:: Alias ( ty:: Opaque , ..) => todo ! ( "We... don't know enough about this type yet?" ) ,
860861 ty:: Adt ( def, args) => {
861862 // for now assume: boxes and phantoms don't mess with this
862863 match def. adt_kind ( ) {
@@ -869,15 +870,21 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
869870 {
870871 return TypeSizedness :: UnsizedWithMetadata ;
871872 }
872- // FIXME: how do we deal with non-exhaustive unsized structs/unions?
873+
874+ // FIXME: double-check: non-exhaustive structs from other crates are assumed to be ?Sized, right?
875+ let is_non_exhaustive =
876+ def. non_enum_variant ( ) . is_field_list_non_exhaustive ( ) ;
877+ if is_non_exhaustive && !def. did ( ) . is_local ( ) {
878+ return TypeSizedness :: NotYetKnown ;
879+ }
873880
874881 if def. non_enum_variant ( ) . fields . is_empty ( ) {
875882 bug ! ( "an empty struct is necessarily sized" ) ;
876883 }
877884
878885 let variant = def. non_enum_variant ( ) ;
879886
880- // only the last field may be unsized
887+ // only the last field may be !Sized (or ?Sized in the case of type params)
881888 let n_fields = variant. fields . len ( ) ;
882889 let last_field = & variant. fields [ ( n_fields - 1 ) . into ( ) ] ;
883890 let field_ty = last_field. ty ( cx. tcx , args) ;
@@ -887,7 +894,8 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
887894 . unwrap_or ( field_ty) ;
888895 match get_type_sizedness ( cx, field_ty) {
889896 s @ ( TypeSizedness :: UnsizedWithMetadata
890- | TypeSizedness :: UnsizedWithExternType ) => s,
897+ | TypeSizedness :: UnsizedWithExternType
898+ | TypeSizedness :: NotYetKnown ) => s,
891899 TypeSizedness :: Definite => {
892900 bug ! ( "failed to find the reason why struct `{:?}` is unsized" , ty)
893901 }
@@ -896,7 +904,7 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
896904 }
897905 }
898906 ty:: Tuple ( tuple) => {
899- // only the last field may be unsized
907+ // only the last field may be !Sized (or ?Sized in the case of type params)
900908 let n_fields = tuple. len ( ) ;
901909 let field_ty: Ty < ' tcx > = tuple[ n_fields - 1 ] ;
902910 //let field_ty = last_field.ty(cx.tcx, args);
@@ -906,18 +914,49 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
906914 . unwrap_or ( field_ty) ;
907915 match get_type_sizedness ( cx, field_ty) {
908916 s @ ( TypeSizedness :: UnsizedWithMetadata
909- | TypeSizedness :: UnsizedWithExternType ) => s,
917+ | TypeSizedness :: UnsizedWithExternType
918+ | TypeSizedness :: NotYetKnown ) => s,
910919 TypeSizedness :: Definite => {
911920 bug ! ( "failed to find the reason why tuple `{:?}` is unsized" , ty)
912921 }
913922 }
914923 }
915- ty => {
924+
925+ ty_kind @ ( ty:: Bool
926+ | ty:: Char
927+ | ty:: Int ( _)
928+ | ty:: Uint ( _)
929+ | ty:: Float ( _)
930+ | ty:: Array ( ..)
931+ | ty:: RawPtr ( ..)
932+ | ty:: Ref ( ..)
933+ | ty:: FnPtr ( ..)
934+ | ty:: Never
935+ | ty:: Pat ( ..) // these are (for now) numeric types with a range-based restriction
936+ ) => {
937+ // those types are all sized, right?
916938 bug ! (
917- "we shouldn't be trying to determine if this is unsized for a reason or another: `{:?}` " ,
918- ty
939+ "This ty_kind (`{:?}`) should be sized, yet we are in a branch of code that deals with unsized types. " ,
940+ ty_kind ,
919941 )
920942 }
943+
944+ // While opaque types are checked for earlier, if a projection in a struct field
945+ // normalizes to an opaque type, then it will reach ty::Alias(ty::Opaque) here.
946+ ty:: Param ( ..) | ty:: Alias ( ty:: Opaque | ty:: Projection | ty:: Inherent , ..) => {
947+ return TypeSizedness :: NotYetKnown ;
948+ }
949+
950+ ty:: Alias ( ty:: Weak , ..)
951+ | ty:: Infer ( ..)
952+ | ty:: Bound ( ..)
953+ | ty:: Error ( _)
954+ | ty:: Closure ( ..)
955+ | ty:: CoroutineClosure ( ..)
956+ | ty:: Coroutine ( ..)
957+ | ty:: CoroutineWitness ( ..)
958+ | ty:: Placeholder ( ..)
959+ | ty:: FnDef ( ..) => bug ! ( "unexpected type in foreign function: {:?}" , ty) ,
921960 }
922961 }
923962}
@@ -1248,6 +1287,26 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12481287 } ;
12491288 }
12501289 }
1290+ TypeSizedness :: NotYetKnown => {
1291+ // types with sizedness NotYetKnown:
1292+ // - Type params (with `variable: impl Trait` shorthand or not)
1293+ // (function definitions only, let's see how this interacts with monomorphisation)
1294+ // - Self in trait functions/methods
1295+ // (FIXME note: function 'declarations' there should be treated as definitions)
1296+ // - Opaque return types
1297+ // (always FFI-unsafe)
1298+ // - non-exhaustive structs/enums/unions from other crates
1299+ // (always FFI-unsafe)
1300+ // (for the three first, this is unless there is a `+Sized` bound involved)
1301+ //
1302+ // FIXME: on a side note, we should separate 'true' declarations (non-rust code),
1303+ // 'fake' declarations (in traits, needed to be implemented elsewhere), and definitions.
1304+ // (for instance, definitions should worry about &self with Self:?Sized, but fake declarations shouldn't)
1305+
1306+ // wether they are FFI-safe or not does not depend on the indirections involved (&Self, &T, Box<impl Trait>),
1307+ // so let's not wrap the current context around a potential FfiUnsafe type param.
1308+ return self . check_type_for_ffi ( acc, inner_ty) ;
1309+ }
12511310 TypeSizedness :: UnsizedWithMetadata => {
12521311 let help = match inner_ty. kind ( ) {
12531312 ty:: Str => Some ( fluent:: lint_improper_ctypes_str_help) ,
@@ -1421,6 +1480,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14211480 help : Some ( fluent:: lint_improper_ctypes_pat_help) ,
14221481 } ,
14231482
1483+ // FIXME: this should probably be architecture-dependant
1484+ // same with some ty::Float variants.
14241485 ty:: Int ( ty:: IntTy :: I128 ) | ty:: Uint ( ty:: UintTy :: U128 ) => {
14251486 FfiUnsafe { ty, reason : fluent:: lint_improper_ctypes_128bit, help : None }
14261487 }
@@ -1466,6 +1527,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14661527 return self . check_indirection_for_ffi ( acc, ty, inner_ty, IndirectionType :: Ref ) ;
14671528 }
14681529
1530+ // having arrays as arguments / return values themselves is not FFI safe,
1531+ // but that is checked elsewhere
1532+ // if we reach this, we can assume the array is inside a struct, behind an indirection, etc.
14691533 ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( acc, inner_ty) ,
14701534
14711535 ty:: FnPtr ( sig_tys, hdr) => {
0 commit comments