@@ -773,6 +773,8 @@ enum TypeSizedness {
773773 UnsizedWithExternType ,
774774 /// unsized type for other reasons (slice, string, dyn Trait, closure, ...) (pointers are not C-compatible)
775775 UnsizedWithMetadata ,
776+ /// not known, usually for placeholder types (Self in non-impl trait functions, type parameters, aliases, the like)
777+ NotYetKnown ,
776778}
777779
778780/// what type indirection points to a given type
@@ -791,17 +793,16 @@ enum IndirectionType {
791793fn get_type_sizedness < ' tcx , ' a > ( cx : & ' a LateContext < ' tcx > , ty : Ty < ' tcx > ) -> TypeSizedness {
792794 let tcx = cx. tcx ;
793795
796+ // note that sizedness is unrelated to inhabitedness
794797 if ty. is_sized ( tcx, cx. typing_env ( ) ) {
795798 TypeSizedness :: Definite
796799 } else {
800+ // the overall type is !Sized or ?Sized
797801 match ty. kind ( ) {
798802 ty:: Slice ( _) => TypeSizedness :: UnsizedWithMetadata ,
799803 ty:: Str => TypeSizedness :: UnsizedWithMetadata ,
800804 ty:: Dynamic ( ..) => TypeSizedness :: UnsizedWithMetadata ,
801805 ty:: Foreign ( ..) => TypeSizedness :: UnsizedWithExternType ,
802- // While opaque types are checked for earlier, if a projection in a struct field
803- // normalizes to an opaque type, then it will reach this branch.
804- ty:: Alias ( ty:: Opaque , ..) => todo ! ( "We... don't know enough about this type yet?" ) ,
805806 ty:: Adt ( def, args) => {
806807 // for now assume: boxes and phantoms don't mess with this
807808 match def. adt_kind ( ) {
@@ -814,15 +815,21 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
814815 {
815816 return TypeSizedness :: UnsizedWithMetadata ;
816817 }
817- // FIXME: how do we deal with non-exhaustive unsized structs/unions?
818+
819+ // FIXME: double-check: non-exhaustive structs from other crates are assumed to be ?Sized, right?
820+ let is_non_exhaustive =
821+ def. non_enum_variant ( ) . is_field_list_non_exhaustive ( ) ;
822+ if is_non_exhaustive && !def. did ( ) . is_local ( ) {
823+ return TypeSizedness :: NotYetKnown ;
824+ }
818825
819826 if def. non_enum_variant ( ) . fields . is_empty ( ) {
820827 bug ! ( "an empty struct is necessarily sized" ) ;
821828 }
822829
823830 let variant = def. non_enum_variant ( ) ;
824831
825- // only the last field may be unsized
832+ // only the last field may be !Sized (or ?Sized in the case of type params)
826833 let n_fields = variant. fields . len ( ) ;
827834 let last_field = & variant. fields [ ( n_fields - 1 ) . into ( ) ] ;
828835 let field_ty = last_field. ty ( cx. tcx , args) ;
@@ -832,7 +839,8 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
832839 . unwrap_or ( field_ty) ;
833840 match get_type_sizedness ( cx, field_ty) {
834841 s @ ( TypeSizedness :: UnsizedWithMetadata
835- | TypeSizedness :: UnsizedWithExternType ) => s,
842+ | TypeSizedness :: UnsizedWithExternType
843+ | TypeSizedness :: NotYetKnown ) => s,
836844 TypeSizedness :: Definite => {
837845 bug ! ( "failed to find the reason why struct `{:?}` is unsized" , ty)
838846 }
@@ -841,7 +849,7 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
841849 }
842850 }
843851 ty:: Tuple ( tuple) => {
844- // only the last field may be unsized
852+ // only the last field may be !Sized (or ?Sized in the case of type params)
845853 let n_fields = tuple. len ( ) ;
846854 let field_ty: Ty < ' tcx > = tuple[ n_fields - 1 ] ;
847855 //let field_ty = last_field.ty(cx.tcx, args);
@@ -851,18 +859,49 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
851859 . unwrap_or ( field_ty) ;
852860 match get_type_sizedness ( cx, field_ty) {
853861 s @ ( TypeSizedness :: UnsizedWithMetadata
854- | TypeSizedness :: UnsizedWithExternType ) => s,
862+ | TypeSizedness :: UnsizedWithExternType
863+ | TypeSizedness :: NotYetKnown ) => s,
855864 TypeSizedness :: Definite => {
856865 bug ! ( "failed to find the reason why tuple `{:?}` is unsized" , ty)
857866 }
858867 }
859868 }
860- ty => {
869+
870+ ty_kind @ ( ty:: Bool
871+ | ty:: Char
872+ | ty:: Int ( _)
873+ | ty:: Uint ( _)
874+ | ty:: Float ( _)
875+ | ty:: Array ( ..)
876+ | ty:: RawPtr ( ..)
877+ | ty:: Ref ( ..)
878+ | ty:: FnPtr ( ..)
879+ | ty:: Never
880+ | ty:: Pat ( ..) // these are (for now) numeric types with a range-based restriction
881+ ) => {
882+ // those types are all sized, right?
861883 bug ! (
862- "we shouldn't be trying to determine if this is unsized for a reason or another: `{:?}` " ,
863- ty
884+ "This ty_kind (`{:?}`) should be sized, yet we are in a branch of code that deals with unsized types. " ,
885+ ty_kind ,
864886 )
865887 }
888+
889+ // While opaque types are checked for earlier, if a projection in a struct field
890+ // normalizes to an opaque type, then it will reach ty::Alias(ty::Opaque) here.
891+ ty:: Param ( ..) | ty:: Alias ( ty:: Opaque | ty:: Projection | ty:: Inherent , ..) => {
892+ return TypeSizedness :: NotYetKnown ;
893+ }
894+
895+ ty:: Alias ( ty:: Weak , ..)
896+ | ty:: Infer ( ..)
897+ | ty:: Bound ( ..)
898+ | ty:: Error ( _)
899+ | ty:: Closure ( ..)
900+ | ty:: CoroutineClosure ( ..)
901+ | ty:: Coroutine ( ..)
902+ | ty:: CoroutineWitness ( ..)
903+ | ty:: Placeholder ( ..)
904+ | ty:: FnDef ( ..) => bug ! ( "unexpected type in foreign function: {:?}" , ty) ,
866905 }
867906 }
868907}
@@ -1193,6 +1232,26 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11931232 } ;
11941233 }
11951234 }
1235+ TypeSizedness :: NotYetKnown => {
1236+ // types with sizedness NotYetKnown:
1237+ // - Type params (with `variable: impl Trait` shorthand or not)
1238+ // (function definitions only, let's see how this interacts with monomorphisation)
1239+ // - Self in trait functions/methods
1240+ // (FIXME note: function 'declarations' there should be treated as definitions)
1241+ // - Opaque return types
1242+ // (always FFI-unsafe)
1243+ // - non-exhaustive structs/enums/unions from other crates
1244+ // (always FFI-unsafe)
1245+ // (for the three first, this is unless there is a `+Sized` bound involved)
1246+ //
1247+ // FIXME: on a side note, we should separate 'true' declarations (non-rust code),
1248+ // 'fake' declarations (in traits, needed to be implemented elsewhere), and definitions.
1249+ // (for instance, definitions should worry about &self with Self:?Sized, but fake declarations shouldn't)
1250+
1251+ // wether they are FFI-safe or not does not depend on the indirections involved (&Self, &T, Box<impl Trait>),
1252+ // so let's not wrap the current context around a potential FfiUnsafe type param.
1253+ return self . check_type_for_ffi ( acc, inner_ty) ;
1254+ }
11961255 TypeSizedness :: UnsizedWithMetadata => {
11971256 let help = match inner_ty. kind ( ) {
11981257 ty:: Str => Some ( fluent:: lint_improper_ctypes_str_help) ,
@@ -1366,6 +1425,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13661425 help : Some ( fluent:: lint_improper_ctypes_pat_help) ,
13671426 } ,
13681427
1428+ // FIXME: this should probably be architecture-dependant
1429+ // same with some ty::Float variants.
13691430 ty:: Int ( ty:: IntTy :: I128 ) | ty:: Uint ( ty:: UintTy :: U128 ) => {
13701431 FfiUnsafe { ty, reason : fluent:: lint_improper_ctypes_128bit, help : None }
13711432 }
@@ -1411,6 +1472,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14111472 return self . check_indirection_for_ffi ( acc, ty, inner_ty, IndirectionType :: Ref ) ;
14121473 }
14131474
1475+ // having arrays as arguments / return values themselves is not FFI safe,
1476+ // but that is checked elsewhere
1477+ // if we reach this, we can assume the array is inside a struct, behind an indirection, etc.
14141478 ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( acc, inner_ty) ,
14151479
14161480 ty:: FnPtr ( sig_tys, hdr) => {
0 commit comments