Skip to content

Commit b2a98b2

Browse files
authored
Rollup merge of rust-lang#73287 - davidtwco:issue-73251-opaque-types-in-projections, r=estebank
lint: normalize projections using opaque types Fixes rust-lang#73251. This PR normalizes projections which use opaque types (opaque types are otherwise linted against, which is would have previously made the test cases added in this PR fail).
2 parents 9688319 + 4ff1678 commit b2a98b2

6 files changed

+127
-8
lines changed

src/librustc_lint/types.rs

+19-8
Original file line numberDiff line numberDiff line change
@@ -927,22 +927,33 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
927927
fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
928928
use rustc_middle::ty::TypeFoldable;
929929

930-
struct ProhibitOpaqueTypes<'tcx> {
930+
struct ProhibitOpaqueTypes<'a, 'tcx> {
931+
cx: &'a LateContext<'a, 'tcx>,
931932
ty: Option<Ty<'tcx>>,
932933
};
933934

934-
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'tcx> {
935+
impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
935936
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
936-
if let ty::Opaque(..) = ty.kind {
937-
self.ty = Some(ty);
938-
true
939-
} else {
940-
ty.super_visit_with(self)
937+
match ty.kind {
938+
ty::Opaque(..) => {
939+
self.ty = Some(ty);
940+
true
941+
}
942+
// Consider opaque types within projections FFI-safe if they do not normalize
943+
// to more opaque types.
944+
ty::Projection(..) => {
945+
let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
946+
947+
// If `ty` is a opaque type directly then `super_visit_with` won't invoke
948+
// this function again.
949+
if ty.has_opaque_types() { self.visit_ty(ty) } else { false }
950+
}
951+
_ => ty.super_visit_with(self),
941952
}
942953
}
943954
}
944955

945-
let mut visitor = ProhibitOpaqueTypes { ty: None };
956+
let mut visitor = ProhibitOpaqueTypes { cx: self.cx, ty: None };
946957
ty.visit_with(&mut visitor);
947958
if let Some(ty) = visitor.ty {
948959
self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None);
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(type_alias_impl_trait)]
2+
#![deny(improper_ctypes)]
3+
4+
pub trait Baz { }
5+
6+
impl Baz for u32 { }
7+
8+
type Qux = impl Baz;
9+
10+
pub trait Foo {
11+
type Assoc;
12+
}
13+
14+
impl Foo for u32 {
15+
type Assoc = Qux;
16+
}
17+
18+
fn assign() -> Qux { 1 }
19+
20+
extern "C" {
21+
pub fn lint_me() -> <u32 as Foo>::Assoc; //~ ERROR: uses type `Qux`
22+
}
23+
24+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: `extern` block uses type `Qux`, which is not FFI-safe
2+
--> $DIR/lint-ctypes-73251-1.rs:21:25
3+
|
4+
LL | pub fn lint_me() -> <u32 as Foo>::Assoc;
5+
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/lint-ctypes-73251-1.rs:2:9
9+
|
10+
LL | #![deny(improper_ctypes)]
11+
| ^^^^^^^^^^^^^^^
12+
= note: opaque types have no C equivalent
13+
14+
error: aborting due to previous error
15+
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#![feature(type_alias_impl_trait)]
2+
#![deny(improper_ctypes)]
3+
4+
pub trait TraitA {
5+
type Assoc;
6+
}
7+
8+
impl TraitA for u32 {
9+
type Assoc = u32;
10+
}
11+
12+
pub trait TraitB {
13+
type Assoc;
14+
}
15+
16+
impl<T> TraitB for T where T: TraitA {
17+
type Assoc = <T as TraitA>::Assoc;
18+
}
19+
20+
type AliasA = impl TraitA<Assoc = u32>;
21+
22+
type AliasB = impl TraitB<Assoc = AliasA>;
23+
24+
fn use_of_a() -> AliasA { 3 }
25+
26+
fn use_of_b() -> AliasB { 3 }
27+
28+
extern "C" {
29+
pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `AliasA`
30+
}
31+
32+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: `extern` block uses type `AliasA`, which is not FFI-safe
2+
--> $DIR/lint-ctypes-73251-2.rs:29:25
3+
|
4+
LL | pub fn lint_me() -> <AliasB as TraitB>::Assoc;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/lint-ctypes-73251-2.rs:2:9
9+
|
10+
LL | #![deny(improper_ctypes)]
11+
| ^^^^^^^^^^^^^^^
12+
= note: opaque types have no C equivalent
13+
14+
error: aborting due to previous error
15+

src/test/ui/lint/lint-ctypes-73251.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// check-pass
2+
3+
#![feature(type_alias_impl_trait)]
4+
#![deny(improper_ctypes)]
5+
6+
pub trait Foo {
7+
type Assoc;
8+
}
9+
10+
impl Foo for () {
11+
type Assoc = u32;
12+
}
13+
14+
type Bar = impl Foo<Assoc = u32>;
15+
16+
fn assign() -> Bar {}
17+
18+
extern "C" {
19+
pub fn lint_me() -> <Bar as Foo>::Assoc;
20+
}
21+
22+
fn main() {}

0 commit comments

Comments
 (0)