lint: polish code from the last few commits
This commit is contained in:
parent
7962a2de3a
commit
d857bc8fbb
1 changed files with 60 additions and 25 deletions
|
@ -740,35 +740,49 @@ enum FfiResult<'tcx> {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_unsized_because_foreign<'tcx, 'a>(
|
/// Determine if a type is sized or not, and wether it affects references/pointers/boxes to it
|
||||||
cx: &'a LateContext<'tcx>,
|
#[derive(Clone, Copy)]
|
||||||
ty: Ty<'tcx>,
|
enum TypeSizedness {
|
||||||
) -> Result<bool, ()> {
|
/// sized type (pointers are C-compatible)
|
||||||
|
Sized,
|
||||||
|
/// unsized type because it includes an opaque/foreign type (pointers are C-compatible)
|
||||||
|
UnsizedBecauseForeign,
|
||||||
|
/// unsized type for other reasons (slice, string, dyn Trait, closure, ...) (pointers are not C-compatible)
|
||||||
|
UnsizedWithMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is this type unsized because it contains (or is) a foreign type?
|
||||||
|
/// (Returns Err if the type happens to be sized after all)
|
||||||
|
fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> TypeSizedness {
|
||||||
let tcx = cx.tcx;
|
let tcx = cx.tcx;
|
||||||
|
|
||||||
if ty.is_sized(tcx, cx.typing_env()) {
|
if ty.is_sized(tcx, cx.typing_env()) {
|
||||||
Err(())
|
TypeSizedness::Sized
|
||||||
} else {
|
} else {
|
||||||
Ok(match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Slice(_) => false,
|
ty::Slice(_) => TypeSizedness::UnsizedWithMetadata,
|
||||||
ty::Str => false,
|
ty::Str => TypeSizedness::UnsizedWithMetadata,
|
||||||
ty::Dynamic(..) => false,
|
ty::Dynamic(..) => TypeSizedness::UnsizedWithMetadata,
|
||||||
ty::Foreign(..) => true,
|
ty::Foreign(..) => TypeSizedness::UnsizedBecauseForeign,
|
||||||
ty::Alias(ty::Opaque, ..) => todo!("why"),
|
// While opaque types are checked for earlier, if a projection in a struct field
|
||||||
|
// normalizes to an opaque type, then it will reach this branch.
|
||||||
|
ty::Alias(ty::Opaque, ..) => todo!("We... don't know enough about this type yet?"),
|
||||||
ty::Adt(def, args) => {
|
ty::Adt(def, args) => {
|
||||||
// for now assume: boxes and phantoms don't mess with this
|
// for now assume: boxes and phantoms don't mess with this
|
||||||
match def.adt_kind() {
|
match def.adt_kind() {
|
||||||
AdtKind::Union | AdtKind::Enum => true,
|
AdtKind::Union | AdtKind::Enum => {
|
||||||
|
bug!("unions and enums are necessarily sized")
|
||||||
|
}
|
||||||
AdtKind::Struct => {
|
AdtKind::Struct => {
|
||||||
if let Some(sym::cstring_type | sym::cstr_type) =
|
if let Some(sym::cstring_type | sym::cstr_type) =
|
||||||
tcx.get_diagnostic_name(def.did())
|
tcx.get_diagnostic_name(def.did())
|
||||||
{
|
{
|
||||||
return Ok(false);
|
return TypeSizedness::UnsizedWithMetadata;
|
||||||
}
|
}
|
||||||
// FIXME: how do we deal with non-exhaustive unsized structs/unions?
|
// FIXME: how do we deal with non-exhaustive unsized structs/unions?
|
||||||
|
|
||||||
if def.non_enum_variant().fields.is_empty() {
|
if def.non_enum_variant().fields.is_empty() {
|
||||||
bug!("empty unsized struct/union. what?");
|
bug!("an empty struct is necessarily sized");
|
||||||
}
|
}
|
||||||
|
|
||||||
let variant = def.non_enum_variant();
|
let variant = def.non_enum_variant();
|
||||||
|
@ -781,7 +795,13 @@ pub(crate) fn is_unsized_because_foreign<'tcx, 'a>(
|
||||||
.tcx
|
.tcx
|
||||||
.try_normalize_erasing_regions(cx.typing_env(), field_ty)
|
.try_normalize_erasing_regions(cx.typing_env(), field_ty)
|
||||||
.unwrap_or(field_ty);
|
.unwrap_or(field_ty);
|
||||||
return Ok(is_unsized_because_foreign(cx, field_ty).unwrap());
|
match get_type_sizedness(cx, field_ty) {
|
||||||
|
s @ (TypeSizedness::UnsizedWithMetadata
|
||||||
|
| TypeSizedness::UnsizedBecauseForeign) => s,
|
||||||
|
TypeSizedness::Sized => {
|
||||||
|
bug!("failed to find the reason why struct `{:?}` is unsized", ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -794,12 +814,21 @@ pub(crate) fn is_unsized_because_foreign<'tcx, 'a>(
|
||||||
.tcx
|
.tcx
|
||||||
.try_normalize_erasing_regions(cx.typing_env(), field_ty)
|
.try_normalize_erasing_regions(cx.typing_env(), field_ty)
|
||||||
.unwrap_or(field_ty);
|
.unwrap_or(field_ty);
|
||||||
is_unsized_because_foreign(cx, field_ty).unwrap()
|
match get_type_sizedness(cx, field_ty) {
|
||||||
|
s @ (TypeSizedness::UnsizedWithMetadata
|
||||||
|
| TypeSizedness::UnsizedBecauseForeign) => s,
|
||||||
|
TypeSizedness::Sized => {
|
||||||
|
bug!("failed to find the reason why tuple `{:?}` is unsized", ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
t => {
|
t => {
|
||||||
bug!("we shouldn't be looking if this is unsized for a reason or another: {:?}", t)
|
bug!(
|
||||||
|
"we shouldn't be trying to determine if this is unsized for a reason or another: `{:?}`",
|
||||||
|
t
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1106,8 +1135,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Adt(def, args) => {
|
ty::Adt(def, args) => {
|
||||||
if let Some(inner_ty) = ty.boxed_ty() {
|
if let Some(inner_ty) = ty.boxed_ty() {
|
||||||
if inner_ty.is_sized(tcx, self.cx.typing_env())
|
if let TypeSizedness::UnsizedBecauseForeign | TypeSizedness::Sized =
|
||||||
|| is_unsized_because_foreign(self.cx, inner_ty).unwrap()
|
get_type_sizedness(self.cx, inner_ty)
|
||||||
{
|
{
|
||||||
// discussion on declaration vs definition:
|
// discussion on declaration vs definition:
|
||||||
// see the `ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _)` arm
|
// see the `ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _)` arm
|
||||||
|
@ -1311,13 +1340,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _) => {
|
ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _) => {
|
||||||
if inner_ty.is_sized(tcx, self.cx.typing_env())
|
if let TypeSizedness::UnsizedBecauseForeign | TypeSizedness::Sized =
|
||||||
|| is_unsized_because_foreign(self.cx, inner_ty).unwrap()
|
get_type_sizedness(self.cx, inner_ty)
|
||||||
{
|
{
|
||||||
// there's a nuance on what this lint should do for function definitions
|
// there's a nuance on what this lint should do for function definitions
|
||||||
// (touched upon in https://github.com/rust-lang/rust/issues/66220 and https://github.com/rust-lang/rust/pull/72700)
|
|
||||||
//
|
|
||||||
// (`extern "C" fn fn_name(...) {...}`) versus declarations (`extern "C" {fn fn_name(...);}`).
|
// (`extern "C" fn fn_name(...) {...}`) versus declarations (`extern "C" {fn fn_name(...);}`).
|
||||||
|
// (this is touched upon in https://github.com/rust-lang/rust/issues/66220
|
||||||
|
// and https://github.com/rust-lang/rust/pull/72700)
|
||||||
|
//
|
||||||
// The big question is: what does "ABI safety" mean? if you have something translated to a C pointer
|
// The big question is: what does "ABI safety" mean? if you have something translated to a C pointer
|
||||||
// (which has a stable layout) but points to FFI-unsafe type, is it safe?
|
// (which has a stable layout) but points to FFI-unsafe type, is it safe?
|
||||||
// on one hand, the function's ABI will match that of a similar C-declared function API,
|
// on one hand, the function's ABI will match that of a similar C-declared function API,
|
||||||
|
@ -1609,7 +1639,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
let last_ty = last_ty.unwrap(); // populated by any run of the `while` block
|
let last_ty = match last_ty {
|
||||||
|
Some(last_ty) => last_ty,
|
||||||
|
None => bug!(
|
||||||
|
"This option should definitely have been filled by the loop that just finished"
|
||||||
|
),
|
||||||
|
};
|
||||||
self.emit_ffi_unsafe_type_lint(last_ty, sp, cimproper_layers);
|
self.emit_ffi_unsafe_type_lint(last_ty, sp, cimproper_layers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue