diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index 05932427bcf7a..4bff51adeeb9b 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -5,7 +5,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, fold::BottomUpFolder, TyCtxt, TypeFoldable}; use rustc_trait_selection::traits; pub fn check(tcx: TyCtxt<'_>) { @@ -233,13 +233,26 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { } } - if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() { - self.tcx - .sess - .struct_span_err(sp, "cannot implement trait on type alias impl trait") - .span_note(self.tcx.def_span(def_id), "type alias impl trait defined here") - .emit(); - } + // Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples, + // and #84660 where it would otherwise allow unsoundness. + trait_ref.substs.fold_with(&mut BottomUpFolder { + tcx: self.tcx, + ty_op: |ty| { + if let ty::Opaque(def_id, _) = *ty.kind() { + self.tcx + .sess + .struct_span_err(sp, "cannot implement trait on type alias impl trait") + .span_note( + self.tcx.def_span(def_id), + "type alias impl trait defined here", + ) + .emit(); + } + ty + }, + lt_op: |lt| lt, + ct_op: |ct| ct, + }); } } diff --git a/src/test/ui/impl-trait/auto-trait.full_tait.stderr b/src/test/ui/impl-trait/auto-trait.full_tait.stderr index 314617748b0ba..5eac112c65431 100644 --- a/src/test/ui/impl-trait/auto-trait.full_tait.stderr +++ b/src/test/ui/impl-trait/auto-trait.full_tait.stderr @@ -16,6 +16,18 @@ LL | impl AnotherTrait for T {} LL | impl AnotherTrait for D { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D` -error: aborting due to previous error; 1 warning emitted +error: cannot implement trait on type alias impl trait + --> $DIR/auto-trait.rs:24:1 + | +LL | impl AnotherTrait for D { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here + --> $DIR/auto-trait.rs:10:19 + | +LL | type OpaqueType = impl OpaqueTrait; + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/impl-trait/auto-trait.min_tait.stderr b/src/test/ui/impl-trait/auto-trait.min_tait.stderr index 75a5b0cb87db1..a1958cca14947 100644 --- a/src/test/ui/impl-trait/auto-trait.min_tait.stderr +++ b/src/test/ui/impl-trait/auto-trait.min_tait.stderr @@ -7,6 +7,18 @@ LL | impl AnotherTrait for T {} LL | impl AnotherTrait for D { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D` -error: aborting due to previous error +error: cannot implement trait on type alias impl trait + --> $DIR/auto-trait.rs:24:1 + | +LL | impl AnotherTrait for D { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here + --> $DIR/auto-trait.rs:10:19 + | +LL | type OpaqueType = impl OpaqueTrait; + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/impl-trait/auto-trait.rs b/src/test/ui/impl-trait/auto-trait.rs index c965a34c12b32..a094c34049ef8 100644 --- a/src/test/ui/impl-trait/auto-trait.rs +++ b/src/test/ui/impl-trait/auto-trait.rs @@ -21,7 +21,7 @@ impl AnotherTrait for T {} // This is in error, because we cannot assume that `OpaqueType: !Send`. // (We treat opaque types as "foreign types" that could grow more impls // in the future.) -impl AnotherTrait for D { +impl AnotherTrait for D { //~ ERROR cannot implement trait //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D` } diff --git a/src/test/ui/impl-trait/negative-reasoning.full_tait.stderr b/src/test/ui/impl-trait/negative-reasoning.full_tait.stderr index bccbc8cb36b15..2cfba380222ba 100644 --- a/src/test/ui/impl-trait/negative-reasoning.full_tait.stderr +++ b/src/test/ui/impl-trait/negative-reasoning.full_tait.stderr @@ -18,6 +18,18 @@ LL | impl AnotherTrait for D { | = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `impl OpaqueTrait` in future versions -error: aborting due to previous error; 1 warning emitted +error: cannot implement trait on type alias impl trait + --> $DIR/negative-reasoning.rs:22:1 + | +LL | impl AnotherTrait for D { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here + --> $DIR/negative-reasoning.rs:10:19 + | +LL | type OpaqueType = impl OpaqueTrait; + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/impl-trait/negative-reasoning.min_tait.stderr b/src/test/ui/impl-trait/negative-reasoning.min_tait.stderr index 5727a372ddbe8..ed778b99c813c 100644 --- a/src/test/ui/impl-trait/negative-reasoning.min_tait.stderr +++ b/src/test/ui/impl-trait/negative-reasoning.min_tait.stderr @@ -9,6 +9,18 @@ LL | impl AnotherTrait for D { | = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `impl OpaqueTrait` in future versions -error: aborting due to previous error +error: cannot implement trait on type alias impl trait + --> $DIR/negative-reasoning.rs:22:1 + | +LL | impl AnotherTrait for D { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here + --> $DIR/negative-reasoning.rs:10:19 + | +LL | type OpaqueType = impl OpaqueTrait; + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/impl-trait/negative-reasoning.rs b/src/test/ui/impl-trait/negative-reasoning.rs index 7f608cc99db15..21c2b212a3676 100644 --- a/src/test/ui/impl-trait/negative-reasoning.rs +++ b/src/test/ui/impl-trait/negative-reasoning.rs @@ -19,7 +19,7 @@ trait AnotherTrait {} impl AnotherTrait for T {} // This is in error, because we cannot assume that `OpaqueType: !Debug` -impl AnotherTrait for D { +impl AnotherTrait for D { //~ ERROR cannot implement trait //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D` } diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs new file mode 100644 index 0000000000000..1a0acca7881d1 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs @@ -0,0 +1,23 @@ +// Regression test for issues #84660 and #86411: both are variations on #76202. +// Tests that we don't ICE when we have an opaque type appearing anywhere in an impl header. + +#![feature(min_type_alias_impl_trait)] + +trait Foo {} +impl Foo for () {} +type Bar = impl Foo; +fn _defining_use() -> Bar {} + +trait TraitArg { + fn f(); +} + +impl TraitArg for () { //~ ERROR cannot implement trait + fn f() { + println!("ho"); + } +} + +fn main() { + <() as TraitArg>::f(); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr new file mode 100644 index 0000000000000..1b8eee407178c --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr @@ -0,0 +1,14 @@ +error: cannot implement trait on type alias impl trait + --> $DIR/issue-84660-trait-impl-for-tait.rs:15:1 + | +LL | impl TraitArg for () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here + --> $DIR/issue-84660-trait-impl-for-tait.rs:8:12 + | +LL | type Bar = impl Foo; + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs new file mode 100644 index 0000000000000..18213dfbe5bf7 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs @@ -0,0 +1,41 @@ +// Another example from issue #84660, this time weaponized as a safe transmut: an opaque type in an +// impl header being accepted was used to create unsoundness. + +#![feature(min_type_alias_impl_trait)] + +trait Foo {} +impl Foo for () {} +type Bar = impl Foo; +fn _defining_use() -> Bar {} + +trait Trait { + type Out; + fn convert(i: In) -> Self::Out; +} + +impl Trait for Out { //~ ERROR cannot implement trait + type Out = Out; + fn convert(_i: In) -> Self::Out { + unreachable!(); + } +} + +impl Trait<(), In> for Out { + type Out = In; + fn convert(i: In) -> Self::Out { + i + } +} + +fn transmute(i: In) -> Out { + >::convert(i) +} + +fn main() { + let d; + { + let x = "Hello World".to_string(); + d = transmute::<&String, &String>(&x); + } + println!("{}", d); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr new file mode 100644 index 0000000000000..b1128d830f967 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr @@ -0,0 +1,14 @@ +error: cannot implement trait on type alias impl trait + --> $DIR/issue-84660-unsoundness.rs:16:1 + | +LL | impl Trait for Out { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here + --> $DIR/issue-84660-unsoundness.rs:8:12 + | +LL | type Bar = impl Foo; + | ^^^^^^^^ + +error: aborting due to previous error +