diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2022-11-15 10:44:10 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-11-15 10:44:10 +0100 |
| commit | d8b416db0af5b26fb01db3a275f2f3c114b36c61 (patch) | |
| tree | b37c2fef9ccb3a94c050bc450ab6765a84a2e5ef | |
| parent | 34425c8c00e85d3480746ddc1eef466b6fc8a697 (diff) | |
| parent | d8bd153ba54ce2ad2d7f1a431f471504690e33b1 (diff) | |
| download | rust-d8b416db0af5b26fb01db3a275f2f3c114b36c61.tar.gz rust-d8b416db0af5b26fb01db3a275f2f3c114b36c61.zip | |
Rollup merge of #104296 - compiler-errors:opaque-ty-ffi-normalization-cycle, r=lcnr
Walk types more carefully in `ProhibitOpaqueTypes` visitor The visitor didn't account for the case where you could have `<TAIT as Trait>::Assoc` normalize to itself, in the case of a `type TAIT = impl Trait` with an unconstrained associated type. That causes the visitor to loop on the same type over and over. Fixes #104291
| -rw-r--r-- | compiler/rustc_lint/src/types.rs | 39 | ||||
| -rw-r--r-- | src/test/ui/lint/opaque-ty-ffi-normalization-cycle.rs | 41 | ||||
| -rw-r--r-- | src/test/ui/lint/opaque-ty-ffi-normalization-cycle.stderr | 15 |
3 files changed, 73 insertions, 22 deletions
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 3e2efb7d361..afc568f3a50 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1195,35 +1195,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { - struct ProhibitOpaqueTypes<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - } - - impl<'a, 'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { + struct ProhibitOpaqueTypes; + impl<'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueTypes { type BreakTy = Ty<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - match ty.kind() { - ty::Opaque(..) => ControlFlow::Break(ty), - // Consider opaque types within projections FFI-safe if they do not normalize - // to more opaque types. - ty::Projection(..) => { - let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty); - - // If `ty` is an opaque type directly then `super_visit_with` won't invoke - // this function again. - if ty.has_opaque_types() { - self.visit_ty(ty) - } else { - ControlFlow::CONTINUE - } - } - _ => ty.super_visit_with(self), + if !ty.has_opaque_types() { + return ControlFlow::CONTINUE; + } + + if let ty::Opaque(..) = ty.kind() { + ControlFlow::Break(ty) + } else { + ty.super_visit_with(self) } } } - if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() { + if let Some(ty) = self + .cx + .tcx + .normalize_erasing_regions(self.cx.param_env, ty) + .visit_with(&mut ProhibitOpaqueTypes) + .break_value() + { self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint_improper_ctypes_opaque, None); true } else { diff --git a/src/test/ui/lint/opaque-ty-ffi-normalization-cycle.rs b/src/test/ui/lint/opaque-ty-ffi-normalization-cycle.rs new file mode 100644 index 00000000000..c83bca4a4c5 --- /dev/null +++ b/src/test/ui/lint/opaque-ty-ffi-normalization-cycle.rs @@ -0,0 +1,41 @@ +#![feature(type_alias_impl_trait)] +#![allow(unused)] +#![deny(improper_ctypes)] + +pub trait TraitA { + type Assoc; +} + +impl TraitA for u32 { + type Assoc = u32; +} + +pub trait TraitB { + type Assoc; +} + +impl<T> TraitB for T +where + T: TraitA, +{ + type Assoc = <T as TraitA>::Assoc; +} + +type AliasA = impl TraitA<Assoc = u32>; + +type AliasB = impl TraitB; + +fn use_of_a() -> AliasA { + 3 +} + +fn use_of_b() -> AliasB { + 3 +} + +extern "C" { + fn lint_me() -> <AliasB as TraitB>::Assoc; + //~^ ERROR `extern` block uses type `AliasB`, which is not FFI-safe +} + +fn main() {} diff --git a/src/test/ui/lint/opaque-ty-ffi-normalization-cycle.stderr b/src/test/ui/lint/opaque-ty-ffi-normalization-cycle.stderr new file mode 100644 index 00000000000..e8d696477ad --- /dev/null +++ b/src/test/ui/lint/opaque-ty-ffi-normalization-cycle.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `AliasB`, which is not FFI-safe + --> $DIR/opaque-ty-ffi-normalization-cycle.rs:37:21 + | +LL | fn lint_me() -> <AliasB as TraitB>::Assoc; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = note: opaque types have no C equivalent +note: the lint level is defined here + --> $DIR/opaque-ty-ffi-normalization-cycle.rs:3:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + |
