Rollup merge of #155358 - niacdoial:improperctypes-refactor2.1, r=petrochenkov

ImproperCTypes: Move erasing_region_normalisation into helper function

This is "part 1/3 of 2/3 of 1/2" of the original pull request https://github.com/rust-lang/rust/pull/134697 (refactor plus overhaul of the ImproperCTypes family of lints)
(all pulls of this series of pulls are supersets of the previous pulls. If this pull is "too small" to be worth the effort, you can instead look at the next in the series)

This pull is a small internal change among the efforts to refactor the ImproperCTypes lints, by moving some "unwrapping" code (`cx.tcx.try_normalize_erasing_regions`) into a helper function.

r? petrochenkov
This commit is contained in:
Stuart Cook
2026-04-17 16:17:55 +10:00
committed by GitHub
@@ -138,6 +138,17 @@
USES_POWER_ALIGNMENT
]);
/// Getting the (normalized) type out of a field (for, e.g., an enum variant or a tuple).
#[inline]
fn get_type_from_field<'tcx>(
cx: &LateContext<'tcx>,
field: &ty::FieldDef,
args: GenericArgsRef<'tcx>,
) -> Ty<'tcx> {
let field_ty = field.ty(cx.tcx, args);
cx.tcx.try_normalize_erasing_regions(cx.typing_env(), field_ty).unwrap_or(field_ty)
}
/// Check a variant of a non-exhaustive enum for improper ctypes
///
/// We treat `#[non_exhaustive] enum` as "ensure that code will compile if new variants are added".
@@ -365,22 +376,6 @@ fn new(cx: &'a LateContext<'tcx>, base_ty: Ty<'tcx>, base_fn_mode: CItemKind) ->
Self { cx, base_ty, base_fn_mode, cache: FxHashSet::default() }
}
/// Checks if the given field's type is "ffi-safe".
fn check_field_type_for_ffi(
&mut self,
state: VisitorState,
field: &ty::FieldDef,
args: GenericArgsRef<'tcx>,
) -> FfiResult<'tcx> {
let field_ty = field.ty(self.cx.tcx, args);
let field_ty = self
.cx
.tcx
.try_normalize_erasing_regions(self.cx.typing_env(), field_ty)
.unwrap_or(field_ty);
self.visit_type(state, field_ty)
}
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
fn check_variant_for_ffi(
&mut self,
@@ -394,7 +389,8 @@ fn check_variant_for_ffi(
let transparent_with_all_zst_fields = if def.repr().transparent() {
if let Some(field) = super::transparent_newtype_field(self.cx.tcx, variant) {
// Transparent newtypes have at most one non-ZST field which needs to be checked..
match self.check_field_type_for_ffi(state, field, args) {
let field_ty = get_type_from_field(self.cx, field, args);
match self.visit_type(state, field_ty) {
FfiUnsafe { ty, .. } if ty.is_unit() => (),
r => return r,
}
@@ -412,7 +408,8 @@ fn check_variant_for_ffi(
// We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
let mut all_phantom = !variant.fields.is_empty();
for field in &variant.fields {
all_phantom &= match self.check_field_type_for_ffi(state, field, args) {
let field_ty = get_type_from_field(self.cx, field, args);
all_phantom &= match self.visit_type(state, field_ty) {
FfiSafe => false,
// `()` fields are FFI-safe!
FfiUnsafe { ty, .. } if ty.is_unit() => false,
@@ -723,22 +720,11 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
}
}
if let Some(ty) = self
.cx
.tcx
.try_normalize_erasing_regions(self.cx.typing_env(), ty)
.unwrap_or(ty)
.visit_with(&mut ProhibitOpaqueTypes)
.break_value()
{
Some(FfiResult::FfiUnsafe {
ty,
reason: msg!("opaque types have no C equivalent"),
help: None,
})
} else {
None
}
ty.visit_with(&mut ProhibitOpaqueTypes).break_value().map(|ty| FfiResult::FfiUnsafe {
ty,
reason: msg!("opaque types have no C equivalent"),
help: None,
})
}
/// Check if the type is array and emit an unsafe type lint.
@@ -756,12 +742,11 @@ fn check_for_array_ty(&mut self, ty: Ty<'tcx>) -> PartialFfiResult<'tcx> {
/// Determine the FFI-safety of a single (MIR) type, given the context of how it is used.
fn check_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.typing_env(), ty).unwrap_or(ty);
if let Some(res) = self.visit_for_opaque_ty(ty) {
return res;
}
let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.typing_env(), ty).unwrap_or(ty);
// C doesn't really support passing arrays by value - the only way to pass an array by value
// is through a struct. So, first test that the top level isn't an array, and then
// recursively check the types inside.