From 09434a2575cee12b241c516ad91f21d4b4f9c3fd Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 21 Jul 2023 15:42:25 +0100 Subject: [PATCH] lint/ctypes: only try normalize Now that this lint runs on any external-ABI fn-ptr, normalization won't always succeed, so use `try_normalize_erasing_regions` instead. Signed-off-by: David Wood --- compiler/rustc_lint/src/types.rs | 21 +++++++++------------ tests/ui/lint/lint-ctypes-113900.rs | 12 ++++++++++++ 2 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 tests/ui/lint/lint-ctypes-113900.rs diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index cc8a34080040a..3379479b1742d 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -966,12 +966,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { args: GenericArgsRef<'tcx>, ) -> FfiResult<'tcx> { let field_ty = field.ty(self.cx.tcx, args); - if field_ty.has_opaque_types() { - self.check_type_for_ffi(cache, field_ty) - } else { - let field_ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, field_ty); - self.check_type_for_ffi(cache, field_ty) - } + let field_ty = self + .cx + .tcx + .try_normalize_erasing_regions(self.cx.param_env, field_ty) + .unwrap_or(field_ty); + self.check_type_for_ffi(cache, field_ty) } /// Checks if the given `VariantDef`'s field types are "ffi-safe". @@ -1320,7 +1320,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if let Some(ty) = self .cx .tcx - .normalize_erasing_regions(self.cx.param_env, ty) + .try_normalize_erasing_regions(self.cx.param_env, ty) + .unwrap_or(ty) .visit_with(&mut ProhibitOpaqueTypes) .break_value() { @@ -1338,16 +1339,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { is_static: bool, is_return_type: bool, ) { - // We have to check for opaque types before `normalize_erasing_regions`, - // which will replace opaque types with their underlying concrete type. if self.check_for_opaque_ty(sp, ty) { // We've already emitted an error due to an opaque type. return; } - // it is only OK to use this function because extern fns cannot have - // any generic types right now: - let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty); + let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.param_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 diff --git a/tests/ui/lint/lint-ctypes-113900.rs b/tests/ui/lint/lint-ctypes-113900.rs new file mode 100644 index 0000000000000..ac4ff1ae2dfd0 --- /dev/null +++ b/tests/ui/lint/lint-ctypes-113900.rs @@ -0,0 +1,12 @@ +// check-pass + +// Extending `improper_ctypes` to check external-ABI fn-ptrs means that it can encounter +// projections which cannot be normalized - unsurprisingly, this shouldn't crash the compiler. + +trait Bar { + type Assoc; +} + +type Foo = extern "C" fn() -> ::Assoc; + +fn main() {}