@@ -773,6 +773,8 @@ enum TypeSizedness {
773
773
UnsizedWithExternType ,
774
774
/// unsized type for other reasons (slice, string, dyn Trait, closure, ...) (pointers are not C-compatible)
775
775
UnsizedWithMetadata ,
776
+ /// not known, usually for placeholder types (Self in non-impl trait functions, type parameters, aliases, the like)
777
+ NotYetKnown ,
776
778
}
777
779
778
780
/// what type indirection points to a given type
@@ -791,17 +793,16 @@ enum IndirectionType {
791
793
fn get_type_sizedness < ' tcx , ' a > ( cx : & ' a LateContext < ' tcx > , ty : Ty < ' tcx > ) -> TypeSizedness {
792
794
let tcx = cx. tcx ;
793
795
796
+ // note that sizedness is unrelated to inhabitedness
794
797
if ty. is_sized ( tcx, cx. typing_env ( ) ) {
795
798
TypeSizedness :: Definite
796
799
} else {
800
+ // the overall type is !Sized or ?Sized
797
801
match ty. kind ( ) {
798
802
ty:: Slice ( _) => TypeSizedness :: UnsizedWithMetadata ,
799
803
ty:: Str => TypeSizedness :: UnsizedWithMetadata ,
800
804
ty:: Dynamic ( ..) => TypeSizedness :: UnsizedWithMetadata ,
801
805
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?" ) ,
805
806
ty:: Adt ( def, args) => {
806
807
// for now assume: boxes and phantoms don't mess with this
807
808
match def. adt_kind ( ) {
@@ -814,15 +815,21 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
814
815
{
815
816
return TypeSizedness :: UnsizedWithMetadata ;
816
817
}
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
+ }
818
825
819
826
if def. non_enum_variant ( ) . fields . is_empty ( ) {
820
827
bug ! ( "an empty struct is necessarily sized" ) ;
821
828
}
822
829
823
830
let variant = def. non_enum_variant ( ) ;
824
831
825
- // only the last field may be unsized
832
+ // only the last field may be !Sized (or ?Sized in the case of type params)
826
833
let n_fields = variant. fields . len ( ) ;
827
834
let last_field = & variant. fields [ ( n_fields - 1 ) . into ( ) ] ;
828
835
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
832
839
. unwrap_or ( field_ty) ;
833
840
match get_type_sizedness ( cx, field_ty) {
834
841
s @ ( TypeSizedness :: UnsizedWithMetadata
835
- | TypeSizedness :: UnsizedWithExternType ) => s,
842
+ | TypeSizedness :: UnsizedWithExternType
843
+ | TypeSizedness :: NotYetKnown ) => s,
836
844
TypeSizedness :: Definite => {
837
845
bug ! ( "failed to find the reason why struct `{:?}` is unsized" , ty)
838
846
}
@@ -841,7 +849,7 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
841
849
}
842
850
}
843
851
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)
845
853
let n_fields = tuple. len ( ) ;
846
854
let field_ty: Ty < ' tcx > = tuple[ n_fields - 1 ] ;
847
855
//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
851
859
. unwrap_or ( field_ty) ;
852
860
match get_type_sizedness ( cx, field_ty) {
853
861
s @ ( TypeSizedness :: UnsizedWithMetadata
854
- | TypeSizedness :: UnsizedWithExternType ) => s,
862
+ | TypeSizedness :: UnsizedWithExternType
863
+ | TypeSizedness :: NotYetKnown ) => s,
855
864
TypeSizedness :: Definite => {
856
865
bug ! ( "failed to find the reason why tuple `{:?}` is unsized" , ty)
857
866
}
858
867
}
859
868
}
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?
861
883
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 ,
864
886
)
865
887
}
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) ,
866
905
}
867
906
}
868
907
}
@@ -1193,6 +1232,26 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1193
1232
} ;
1194
1233
}
1195
1234
}
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
+ }
1196
1255
TypeSizedness :: UnsizedWithMetadata => {
1197
1256
let help = match inner_ty. kind ( ) {
1198
1257
ty:: Str => Some ( fluent:: lint_improper_ctypes_str_help) ,
@@ -1366,6 +1425,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1366
1425
help : Some ( fluent:: lint_improper_ctypes_pat_help) ,
1367
1426
} ,
1368
1427
1428
+ // FIXME: this should probably be architecture-dependant
1429
+ // same with some ty::Float variants.
1369
1430
ty:: Int ( ty:: IntTy :: I128 ) | ty:: Uint ( ty:: UintTy :: U128 ) => {
1370
1431
FfiUnsafe { ty, reason : fluent:: lint_improper_ctypes_128bit, help : None }
1371
1432
}
@@ -1411,6 +1472,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1411
1472
return self . check_indirection_for_ffi ( acc, ty, inner_ty, IndirectionType :: Ref ) ;
1412
1473
}
1413
1474
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.
1414
1478
ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( acc, inner_ty) ,
1415
1479
1416
1480
ty:: FnPtr ( sig_tys, hdr) => {
0 commit comments