Skip to content

Commit e843e7a

Browse files
committed
lint ImproperCTypes: fix TypeSizedness code
1 parent 40eb231 commit e843e7a

File tree

1 file changed

+75
-11
lines changed

1 file changed

+75
-11
lines changed

compiler/rustc_lint/src/types.rs

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {
846848
fn 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

Comments
 (0)