Skip to content

Commit 4ff1678

Browse files
committed
lint: normalize projections using opaque types
This commit normalizes projections which contain opaque types (opaque types are otherwise linted against, which is would have previously made the test cases added in this commit fail). Signed-off-by: David Wood <[email protected]>
1 parent 50c0192 commit 4ff1678

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)