@@ -828,6 +828,8 @@ enum TypeSizedness {
828
828
UnsizedWithExternType ,
829
829
/// unsized type for other reasons (slice, string, dyn Trait, closure, ...) (pointers are not C-compatible)
830
830
UnsizedWithMetadata ,
831
+ /// not known, usually for placeholder types (Self in non-impl trait functions, type parameters, aliases, the like)
832
+ NotYetKnown ,
831
833
}
832
834
833
835
/// what type indirection points to a given type
@@ -846,17 +848,16 @@ enum IndirectionType {
846
848
fn get_type_sizedness < ' tcx , ' a > ( cx : & ' a LateContext < ' tcx > , ty : Ty < ' tcx > ) -> TypeSizedness {
847
849
let tcx = cx. tcx ;
848
850
851
+ // note that sizedness is unrelated to inhabitedness
849
852
if ty. is_sized ( tcx, cx. typing_env ( ) ) {
850
853
TypeSizedness :: Definite
851
854
} else {
855
+ // the overall type is !Sized or ?Sized
852
856
match ty. kind ( ) {
853
857
ty:: Slice ( _) => TypeSizedness :: UnsizedWithMetadata ,
854
858
ty:: Str => TypeSizedness :: UnsizedWithMetadata ,
855
859
ty:: Dynamic ( ..) => TypeSizedness :: UnsizedWithMetadata ,
856
860
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?" ) ,
860
861
ty:: Adt ( def, args) => {
861
862
// for now assume: boxes and phantoms don't mess with this
862
863
match def. adt_kind ( ) {
@@ -869,15 +870,21 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
869
870
{
870
871
return TypeSizedness :: UnsizedWithMetadata ;
871
872
}
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
+ }
873
880
874
881
if def. non_enum_variant ( ) . fields . is_empty ( ) {
875
882
bug ! ( "an empty struct is necessarily sized" ) ;
876
883
}
877
884
878
885
let variant = def. non_enum_variant ( ) ;
879
886
880
- // only the last field may be unsized
887
+ // only the last field may be !Sized (or ?Sized in the case of type params)
881
888
let n_fields = variant. fields . len ( ) ;
882
889
let last_field = & variant. fields [ ( n_fields - 1 ) . into ( ) ] ;
883
890
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
887
894
. unwrap_or ( field_ty) ;
888
895
match get_type_sizedness ( cx, field_ty) {
889
896
s @ ( TypeSizedness :: UnsizedWithMetadata
890
- | TypeSizedness :: UnsizedWithExternType ) => s,
897
+ | TypeSizedness :: UnsizedWithExternType
898
+ | TypeSizedness :: NotYetKnown ) => s,
891
899
TypeSizedness :: Definite => {
892
900
bug ! ( "failed to find the reason why struct `{:?}` is unsized" , ty)
893
901
}
@@ -896,7 +904,7 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
896
904
}
897
905
}
898
906
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)
900
908
let n_fields = tuple. len ( ) ;
901
909
let field_ty: Ty < ' tcx > = tuple[ n_fields - 1 ] ;
902
910
//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
906
914
. unwrap_or ( field_ty) ;
907
915
match get_type_sizedness ( cx, field_ty) {
908
916
s @ ( TypeSizedness :: UnsizedWithMetadata
909
- | TypeSizedness :: UnsizedWithExternType ) => s,
917
+ | TypeSizedness :: UnsizedWithExternType
918
+ | TypeSizedness :: NotYetKnown ) => s,
910
919
TypeSizedness :: Definite => {
911
920
bug ! ( "failed to find the reason why tuple `{:?}` is unsized" , ty)
912
921
}
913
922
}
914
923
}
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?
916
938
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 ,
919
941
)
920
942
}
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) ,
921
960
}
922
961
}
923
962
}
@@ -1248,6 +1287,26 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1248
1287
} ;
1249
1288
}
1250
1289
}
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
+ }
1251
1310
TypeSizedness :: UnsizedWithMetadata => {
1252
1311
let help = match inner_ty. kind ( ) {
1253
1312
ty:: Str => Some ( fluent:: lint_improper_ctypes_str_help) ,
@@ -1421,6 +1480,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1421
1480
help : Some ( fluent:: lint_improper_ctypes_pat_help) ,
1422
1481
} ,
1423
1482
1483
+ // FIXME: this should probably be architecture-dependant
1484
+ // same with some ty::Float variants.
1424
1485
ty:: Int ( ty:: IntTy :: I128 ) | ty:: Uint ( ty:: UintTy :: U128 ) => {
1425
1486
FfiUnsafe { ty, reason : fluent:: lint_improper_ctypes_128bit, help : None }
1426
1487
}
@@ -1466,6 +1527,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1466
1527
return self . check_indirection_for_ffi ( acc, ty, inner_ty, IndirectionType :: Ref ) ;
1467
1528
}
1468
1529
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.
1469
1533
ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( acc, inner_ty) ,
1470
1534
1471
1535
ty:: FnPtr ( sig_tys, hdr) => {
0 commit comments