about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2020-06-20 14:44:57 -0700
committerGitHub <noreply@github.com>2020-06-20 14:44:57 -0700
commit90030876558d9c9f8623210fd7861136d2bae4f7 (patch)
treee03d7f670d24de6ee72b7813d08e0fa4de4c6b60
parent45d6aefc6047652dd32a431c1a065a692545c082 (diff)
parent2e781ddacc126b24df93f7b547ced542262f12a2 (diff)
downloadrust-90030876558d9c9f8623210fd7861136d2bae4f7.tar.gz
rust-90030876558d9c9f8623210fd7861136d2bae4f7.zip
Rollup merge of #73287 - davidtwco:issue-73251-opaque-types-in-projections, r=estebank
lint: normalize projections using opaque types

Fixes #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).
-rw-r--r--src/librustc_lint/types.rs27
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-1.rs24
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-1.stderr15
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-2.rs32
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-2.stderr15
-rw-r--r--src/test/ui/lint/lint-ctypes-73251.rs22
6 files changed, 127 insertions, 8 deletions
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index d92c1131ff9..a19c9a35579 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -895,22 +895,33 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     }
 
     fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
-        struct ProhibitOpaqueTypes<'tcx> {
+        struct ProhibitOpaqueTypes<'a, 'tcx> {
+            cx: &'a LateContext<'a, 'tcx>,
             ty: Option<Ty<'tcx>>,
         };
 
-        impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'tcx> {
+        impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
             fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
-                if let ty::Opaque(..) = ty.kind {
-                    self.ty = Some(ty);
-                    true
-                } else {
-                    ty.super_visit_with(self)
+                match ty.kind {
+                    ty::Opaque(..) => {
+                        self.ty = Some(ty);
+                        true
+                    }
+                    // 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 a opaque type directly then `super_visit_with` won't invoke
+                        // this function again.
+                        if ty.has_opaque_types() { self.visit_ty(ty) } else { false }
+                    }
+                    _ => ty.super_visit_with(self),
                 }
             }
         }
 
-        let mut visitor = ProhibitOpaqueTypes { ty: None };
+        let mut visitor = ProhibitOpaqueTypes { cx: self.cx, ty: None };
         ty.visit_with(&mut visitor);
         if let Some(ty) = visitor.ty {
             self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None);
diff --git a/src/test/ui/lint/lint-ctypes-73251-1.rs b/src/test/ui/lint/lint-ctypes-73251-1.rs
new file mode 100644
index 00000000000..2ce80982f5c
--- /dev/null
+++ b/src/test/ui/lint/lint-ctypes-73251-1.rs
@@ -0,0 +1,24 @@
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Baz { }
+
+impl Baz for u32 { }
+
+type Qux = impl Baz;
+
+pub trait Foo {
+    type Assoc;
+}
+
+impl Foo for u32 {
+    type Assoc = Qux;
+}
+
+fn assign() -> Qux { 1 }
+
+extern "C" {
+    pub fn lint_me() -> <u32 as Foo>::Assoc; //~ ERROR: uses type `impl Baz`
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73251-1.stderr b/src/test/ui/lint/lint-ctypes-73251-1.stderr
new file mode 100644
index 00000000000..0b4237bb96f
--- /dev/null
+++ b/src/test/ui/lint/lint-ctypes-73251-1.stderr
@@ -0,0 +1,15 @@
+error: `extern` block uses type `impl Baz`, which is not FFI-safe
+  --> $DIR/lint-ctypes-73251-1.rs:21:25
+   |
+LL |     pub fn lint_me() -> <u32 as Foo>::Assoc;
+   |                         ^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-73251-1.rs:2:9
+   |
+LL | #![deny(improper_ctypes)]
+   |         ^^^^^^^^^^^^^^^
+   = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/lint-ctypes-73251-2.rs b/src/test/ui/lint/lint-ctypes-73251-2.rs
new file mode 100644
index 00000000000..3427c657b42
--- /dev/null
+++ b/src/test/ui/lint/lint-ctypes-73251-2.rs
@@ -0,0 +1,32 @@
+#![feature(type_alias_impl_trait)]
+#![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<Assoc = AliasA>;
+
+fn use_of_a() -> AliasA { 3 }
+
+fn use_of_b() -> AliasB { 3 }
+
+extern "C" {
+    pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `impl TraitA`
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73251-2.stderr b/src/test/ui/lint/lint-ctypes-73251-2.stderr
new file mode 100644
index 00000000000..43f7629b043
--- /dev/null
+++ b/src/test/ui/lint/lint-ctypes-73251-2.stderr
@@ -0,0 +1,15 @@
+error: `extern` block uses type `impl TraitA`, which is not FFI-safe
+  --> $DIR/lint-ctypes-73251-2.rs:29:25
+   |
+LL |     pub fn lint_me() -> <AliasB as TraitB>::Assoc;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-73251-2.rs:2:9
+   |
+LL | #![deny(improper_ctypes)]
+   |         ^^^^^^^^^^^^^^^
+   = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/lint-ctypes-73251.rs b/src/test/ui/lint/lint-ctypes-73251.rs
new file mode 100644
index 00000000000..ebc2ca77b67
--- /dev/null
+++ b/src/test/ui/lint/lint-ctypes-73251.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Foo {
+    type Assoc;
+}
+
+impl Foo for () {
+    type Assoc = u32;
+}
+
+type Bar = impl Foo<Assoc = u32>;
+
+fn assign() -> Bar {}
+
+extern "C" {
+    pub fn lint_me() -> <Bar as Foo>::Assoc;
+}
+
+fn main() {}