@@ -847,6 +847,8 @@ enum TypeSizedness {
847
847
UnsizedWithExternType ,
848
848
/// unsized type for other reasons (slice, string, dyn Trait, closure, ...) (pointers are not C-compatible)
849
849
UnsizedWithMetadata ,
850
+ /// not known, usually for placeholder types (Self in non-impl trait functions, type parameters, aliases, the like)
851
+ NotYetKnown ,
850
852
}
851
853
852
854
/// what type indirection points to a given type
@@ -865,17 +867,16 @@ enum IndirectionType {
865
867
fn get_type_sizedness < ' tcx , ' a > ( cx : & ' a LateContext < ' tcx > , ty : Ty < ' tcx > ) -> TypeSizedness {
866
868
let tcx = cx. tcx ;
867
869
870
+ // note that sizedness is unrelated to inhabitedness
868
871
if ty. is_sized ( tcx, cx. typing_env ( ) ) {
869
872
TypeSizedness :: Definite
870
873
} else {
874
+ // the overall type is !Sized or ?Sized
871
875
match ty. kind ( ) {
872
876
ty:: Slice ( _) => TypeSizedness :: UnsizedWithMetadata ,
873
877
ty:: Str => TypeSizedness :: UnsizedWithMetadata ,
874
878
ty:: Dynamic ( ..) => TypeSizedness :: UnsizedWithMetadata ,
875
879
ty:: Foreign ( ..) => TypeSizedness :: UnsizedWithExternType ,
876
- // While opaque types are checked for earlier, if a projection in a struct field
877
- // normalizes to an opaque type, then it will reach this branch.
878
- ty:: Alias ( ty:: Opaque , ..) => todo ! ( "We... don't know enough about this type yet?" ) ,
879
880
ty:: Adt ( def, args) => {
880
881
// for now assume: boxes and phantoms don't mess with this
881
882
match def. adt_kind ( ) {
@@ -888,15 +889,21 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
888
889
{
889
890
return TypeSizedness :: UnsizedWithMetadata ;
890
891
}
891
- // FIXME: how do we deal with non-exhaustive unsized structs/unions?
892
+
893
+ // FIXME: double-check: non-exhaustive structs from other crates are assumed to be ?Sized, right?
894
+ let is_non_exhaustive =
895
+ def. non_enum_variant ( ) . is_field_list_non_exhaustive ( ) ;
896
+ if is_non_exhaustive && !def. did ( ) . is_local ( ) {
897
+ return TypeSizedness :: NotYetKnown ;
898
+ }
892
899
893
900
if def. non_enum_variant ( ) . fields . is_empty ( ) {
894
901
bug ! ( "an empty struct is necessarily sized" ) ;
895
902
}
896
903
897
904
let variant = def. non_enum_variant ( ) ;
898
905
899
- // only the last field may be unsized
906
+ // only the last field may be !Sized (or ?Sized in the case of type params)
900
907
// (also since !ty.is_sized(), we have at least one field)
901
908
let last_field_i = variant. fields . last_index ( ) . unwrap ( ) ;
902
909
let last_field = & variant. fields [ last_field_i] ;
@@ -907,7 +914,8 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
907
914
. unwrap_or ( field_ty) ;
908
915
match get_type_sizedness ( cx, field_ty) {
909
916
s @ ( TypeSizedness :: UnsizedWithMetadata
910
- | TypeSizedness :: UnsizedWithExternType ) => s,
917
+ | TypeSizedness :: UnsizedWithExternType
918
+ | TypeSizedness :: NotYetKnown ) => s,
911
919
TypeSizedness :: Definite => {
912
920
bug ! ( "failed to find the reason why struct `{:?}` is unsized" , ty)
913
921
}
@@ -916,7 +924,7 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
916
924
}
917
925
}
918
926
ty:: Tuple ( tuple) => {
919
- // only the last field may be unsized
927
+ // only the last field may be !Sized (or ?Sized in the case of type params)
920
928
let n_fields = tuple. len ( ) ;
921
929
let field_ty: Ty < ' tcx > = tuple[ n_fields - 1 ] ;
922
930
//let field_ty = last_field.ty(cx.tcx, args);
@@ -926,18 +934,51 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
926
934
. unwrap_or ( field_ty) ;
927
935
match get_type_sizedness ( cx, field_ty) {
928
936
s @ ( TypeSizedness :: UnsizedWithMetadata
929
- | TypeSizedness :: UnsizedWithExternType ) => s,
937
+ | TypeSizedness :: UnsizedWithExternType
938
+ | TypeSizedness :: NotYetKnown ) => s,
930
939
TypeSizedness :: Definite => {
931
940
bug ! ( "failed to find the reason why tuple `{:?}` is unsized" , ty)
932
941
}
933
942
}
934
943
}
935
- ty => {
944
+
945
+ ty_kind @ ( ty:: Bool
946
+ | ty:: Char
947
+ | ty:: Int ( _)
948
+ | ty:: Uint ( _)
949
+ | ty:: Float ( _)
950
+ | ty:: Array ( ..)
951
+ | ty:: RawPtr ( ..)
952
+ | ty:: Ref ( ..)
953
+ | ty:: FnPtr ( ..)
954
+ | ty:: Never
955
+ | ty:: Pat ( ..) // these are (for now) numeric types with a range-based restriction
956
+ ) => {
957
+ // those types are all sized, right?
936
958
bug ! (
937
- "we shouldn't be trying to determine if this is unsized for a reason or another: `{:?}` " ,
938
- ty
959
+ "This ty_kind (`{:?}`) should be sized, yet we are in a branch of code that deals with unsized types. " ,
960
+ ty_kind ,
939
961
)
940
962
}
963
+
964
+ // While opaque types are checked for earlier, if a projection in a struct field
965
+ // normalizes to an opaque type, then it will reach ty::Alias(ty::Opaque) here.
966
+ ty:: Param ( ..) | ty:: Alias ( ty:: Opaque | ty:: Projection | ty:: Inherent , ..) => {
967
+ return TypeSizedness :: NotYetKnown ;
968
+ }
969
+
970
+ ty:: UnsafeBinder ( _) => todo ! ( "FIXME(unsafe_binder)" ) ,
971
+
972
+ ty:: Alias ( ty:: Free , ..)
973
+ | ty:: Infer ( ..)
974
+ | ty:: Bound ( ..)
975
+ | ty:: Error ( _)
976
+ | ty:: Closure ( ..)
977
+ | ty:: CoroutineClosure ( ..)
978
+ | ty:: Coroutine ( ..)
979
+ | ty:: CoroutineWitness ( ..)
980
+ | ty:: Placeholder ( ..)
981
+ | ty:: FnDef ( ..) => bug ! ( "unexpected type in foreign function: {:?}" , ty) ,
941
982
}
942
983
}
943
984
}
@@ -1317,6 +1358,26 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1317
1358
} ;
1318
1359
}
1319
1360
}
1361
+ TypeSizedness :: NotYetKnown => {
1362
+ // types with sizedness NotYetKnown:
1363
+ // - Type params (with `variable: impl Trait` shorthand or not)
1364
+ // (function definitions only, let's see how this interacts with monomorphisation)
1365
+ // - Self in trait functions/methods
1366
+ // (FIXME note: function 'declarations' there should be treated as definitions)
1367
+ // - Opaque return types
1368
+ // (always FFI-unsafe)
1369
+ // - non-exhaustive structs/enums/unions from other crates
1370
+ // (always FFI-unsafe)
1371
+ // (for the three first, this is unless there is a `+Sized` bound involved)
1372
+ //
1373
+ // FIXME: on a side note, we should separate 'true' declarations (non-rust code),
1374
+ // 'fake' declarations (in traits, needed to be implemented elsewhere), and definitions.
1375
+ // (for instance, definitions should worry about &self with Self:?Sized, but fake declarations shouldn't)
1376
+
1377
+ // wether they are FFI-safe or not does not depend on the indirections involved (&Self, &T, Box<impl Trait>),
1378
+ // so let's not wrap the current context around a potential FfiUnsafe type param.
1379
+ return self . check_type_for_ffi ( acc, inner_ty) ;
1380
+ }
1320
1381
TypeSizedness :: UnsizedWithMetadata => {
1321
1382
let help = match inner_ty. kind ( ) {
1322
1383
ty:: Str => Some ( fluent:: lint_improper_ctypes_str_help) ,
@@ -1525,6 +1586,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1525
1586
return self . check_indirection_for_ffi ( acc, ty, inner_ty, IndirectionType :: Ref ) ;
1526
1587
}
1527
1588
1589
+ // having arrays as arguments / return values themselves is not FFI safe,
1590
+ // but that is checked elsewhere
1591
+ // if we reach this, we can assume the array is inside a struct, behind an indirection, etc.
1528
1592
ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( acc, inner_ty) ,
1529
1593
1530
1594
ty:: FnPtr ( sig_tys, hdr) => {
0 commit comments