Skip to content

Commit

Permalink
Rollup merge of rust-lang#73287 - davidtwco:issue-73251-opaque-types-…
Browse files Browse the repository at this point in the history
…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).
  • Loading branch information
Manishearth authored Jun 20, 2020
2 parents 42be0f9 + 2e781dd commit e9ad00a
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 8 deletions.
27 changes: 19 additions & 8 deletions src/librustc_lint/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
24 changes: 24 additions & 0 deletions src/test/ui/lint/lint-ctypes-73251-1.rs
Original file line number Diff line number Diff line change
@@ -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() {}
15 changes: 15 additions & 0 deletions src/test/ui/lint/lint-ctypes-73251-1.stderr
Original file line number Diff line number Diff line change
@@ -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

32 changes: 32 additions & 0 deletions src/test/ui/lint/lint-ctypes-73251-2.rs
Original file line number Diff line number Diff line change
@@ -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() {}
15 changes: 15 additions & 0 deletions src/test/ui/lint/lint-ctypes-73251-2.stderr
Original file line number Diff line number Diff line change
@@ -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

22 changes: 22 additions & 0 deletions src/test/ui/lint/lint-ctypes-73251.rs
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit e9ad00a

Please sign in to comment.