1
Fork 0

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
This commit is contained in:
Matthias Krüger 2022-11-15 10:44:10 +01:00 committed by GitHub
commit d8b416db0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 21 deletions

View file

@ -1195,35 +1195,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
} }
fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
struct ProhibitOpaqueTypes<'a, 'tcx> { struct ProhibitOpaqueTypes;
cx: &'a LateContext<'tcx>, impl<'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueTypes {
}
impl<'a, 'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
type BreakTy = Ty<'tcx>; type BreakTy = Ty<'tcx>;
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match ty.kind() { if !ty.has_opaque_types() {
ty::Opaque(..) => ControlFlow::Break(ty), return ControlFlow::CONTINUE;
// 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 if let ty::Opaque(..) = ty.kind() {
// this function again. ControlFlow::Break(ty)
if ty.has_opaque_types() { } else {
self.visit_ty(ty) ty.super_visit_with(self)
} else {
ControlFlow::CONTINUE
}
}
_ => 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); self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint_improper_ctypes_opaque, None);
true true
} else { } else {

View file

@ -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() {}

View file

@ -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