Skip to content

Commit e7db8b8

Browse files
committed
ImproperCTypes: refactor handling opaque aliases
Put the handling of opaque aliases in the actual `visit___` methods instead of awkwardly pre-checking for them
1 parent 67ff00c commit e7db8b8

File tree

1 file changed

+58
-17
lines changed

1 file changed

+58
-17
lines changed

compiler/rustc_lint/src/types/improper_ctypes.rs

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,23 @@ declare_lint_pass!(ImproperCTypesLint => [
171171

172172
type Sig<'tcx> = Binder<'tcx, FnSig<'tcx>>;
173173

174+
// FIXME(ctypes): it seems that tests/ui/lint/opaque-ty-ffi-normalization-cycle.rs relies this:
175+
// we consider opaque aliases that normalise to something else to be unsafe.
176+
// ...is it the behaviour we want?
177+
/// a modified version of cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty).unwrap_or(ty)
178+
/// so that opaque types prevent normalisation once region erasure occurs
179+
fn erase_and_maybe_normalize<'tcx>(cx: &LateContext<'tcx>, value: Ty<'tcx>) -> Ty<'tcx> {
180+
if (!value.has_aliases()) || value.has_opaque_types() {
181+
cx.tcx.erase_regions(value)
182+
} else {
183+
cx.tcx.try_normalize_erasing_regions(cx.typing_env(), value).unwrap_or(value)
184+
// note: the code above ^^^ would only cause a call to the commented code below vvv
185+
//let value = cx.tcx.erase_regions(value);
186+
//let mut folder = TryNormalizeAfterErasingRegionsFolder::new(cx.tcx, cx.typing_env());
187+
//value.try_fold_with(&mut folder).unwrap_or(value)
188+
}
189+
}
190+
174191
/// Getting the (normalized) type out of a field (for, e.g., an enum variant or a tuple).
175192
#[inline]
176193
fn get_type_from_field<'tcx>(
@@ -179,7 +196,7 @@ fn get_type_from_field<'tcx>(
179196
args: GenericArgsRef<'tcx>,
180197
) -> Ty<'tcx> {
181198
let field_ty = field.ty(cx.tcx, args);
182-
cx.tcx.try_normalize_erasing_regions(cx.typing_env(), field_ty).unwrap_or(field_ty)
199+
erase_and_maybe_normalize(cx, field_ty)
183200
}
184201

185202
/// Check a variant of a non-exhaustive enum for improper ctypes.
@@ -569,7 +586,7 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
569586
Some(item_ty) => *item_ty,
570587
None => bug!("Empty tuple (AKA unit type) should be Sized, right?"),
571588
};
572-
let item_ty = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), item_ty).unwrap_or(item_ty);
589+
let item_ty = erase_and_maybe_normalize(cx, item_ty);
573590
match get_type_sizedness(cx, item_ty) {
574591
s @ (TypeSizedness::UnsizedWithMetadata
575592
| TypeSizedness::UnsizedWithExternType
@@ -1479,25 +1496,52 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14791496

14801497
ty::Never => self.visit_uninhabited(state, ty),
14811498

1482-
// While opaque types are checked for earlier, if a projection in a struct field
1483-
// normalizes to an opaque type, then it will reach this branch.
1499+
// This is only half of the checking-for-opaque-aliases story:
1500+
// since they are liable to vanish on normalisation, we need a specific to find them through
1501+
// other aliases, which is called in the next branch of this `match ty.kind()` statement
14841502
ty::Alias(ty::Opaque, ..) => {
14851503
FfiResult::new_with_reason(ty, fluent::lint_improper_ctypes_opaque, None)
14861504
}
14871505

1488-
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
1506+
// `extern "C" fn` function definitions can have type parameters, which may or may not be FFI-safe,
14891507
// so they are currently ignored for the purposes of this lint.
1490-
ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent, ..)
1491-
if state.can_expect_ty_params() =>
1492-
{
1493-
FfiSafe
1508+
// function pointers can do the same
1509+
//
1510+
// however, these ty_kind:s can also be encountered because the type isn't normalized yet.
1511+
ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..) => {
1512+
if ty.has_opaque_types() {
1513+
// FIXME(ctypes): this is suboptimal because we give up
1514+
// on reporting anything *else* than the opaque part of the type
1515+
// but this is better than not reporting anything, or crashing
1516+
self.visit_for_opaque_ty(ty).unwrap()
1517+
} else {
1518+
// in theory, thanks to erase_and_maybe_normalize,
1519+
// normalisation has already occurred
1520+
debug_assert_eq!(
1521+
self.cx
1522+
.tcx
1523+
.try_normalize_erasing_regions(self.cx.typing_env(), ty,)
1524+
.unwrap_or(ty),
1525+
ty,
1526+
);
1527+
1528+
if matches!(
1529+
ty.kind(),
1530+
ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent, ..)
1531+
) && state.can_expect_ty_params()
1532+
{
1533+
FfiSafe
1534+
} else {
1535+
// ty::Alias(ty::Free), and all params/aliases for something
1536+
// defined beyond the FFI boundary
1537+
bug!("unexpected type in foreign function: {:?}", ty)
1538+
}
1539+
}
14941540
}
14951541

14961542
ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
14971543

1498-
ty::Param(..)
1499-
| ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
1500-
| ty::Infer(..)
1544+
ty::Infer(..)
15011545
| ty::Bound(..)
15021546
| ty::Error(_)
15031547
| ty::Closure(..)
@@ -1533,17 +1577,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
15331577
}
15341578

15351579
fn check_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
1536-
let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.typing_env(), ty).unwrap_or(ty);
1537-
if let Some(res) = self.visit_for_opaque_ty(ty) {
1538-
return res;
1539-
}
1580+
let ty = erase_and_maybe_normalize(self.cx, ty);
15401581
self.visit_type(state, ty)
15411582
}
15421583

15431584
/// Checks the FFI-safety of a callback (`extern "ABI"` FnPtr)
15441585
/// that is found in a no-FFI-safety-needed context.
15451586
fn check_fnptr(&mut self, depth: usize, ty: Ty<'tcx>) -> FfiResult<'tcx> {
1546-
let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.typing_env(), ty).unwrap_or(ty);
1587+
let ty = erase_and_maybe_normalize(self.cx, ty);
15471588

15481589
match *ty.kind() {
15491590
ty::FnPtr(sig_tys, hdr) => {

0 commit comments

Comments
 (0)