Skip to content

Commit e96304b

Browse files
authored
Rollup merge of rust-lang#95973 - oli-obk:tait_ub3, r=compiler-errors
prevent opaque types from appearing in impl headers cc `@lqd` opaque types are not distinguishable from their hidden type at the codegen stage. So we could either end up with cases where the hidden type doesn't implement the trait (which will thus ICE) or where the hidden type does implement the trait (so we'd be using its impl instead of the one written for the opaque type). This can even lead to unsound behaviour without unsafe code. Fixes rust-lang#86411. Fixes rust-lang#84660. rebase of rust-lang#87382 plus some diagnostic tweaks
2 parents d63a46a + 6d0349d commit e96304b

18 files changed

+204
-48
lines changed

compiler/rustc_typeck/src/coherence/orphan.rs

+51-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_errors::ErrorGuaranteed;
77
use rustc_hir as hir;
88
use rustc_index::bit_set::GrowableBitSet;
99
use rustc_infer::infer::TyCtxtInferExt;
10+
use rustc_middle::ty::subst::GenericArgKind;
1011
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
1112
use rustc_middle::ty::{self, ImplPolarity, Ty, TyCtxt, TypeFoldable, TypeVisitor};
1213
use rustc_session::lint;
@@ -141,13 +142,56 @@ fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua
141142
}
142143
}
143144

144-
if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() {
145-
let reported = tcx
146-
.sess
147-
.struct_span_err(sp, "cannot implement trait on type alias impl trait")
148-
.span_note(tcx.def_span(def_id), "type alias impl trait defined here")
149-
.emit();
150-
return Err(reported);
145+
// Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples,
146+
// and #84660 where it would otherwise allow unsoundness.
147+
if trait_ref.has_opaque_types() {
148+
trace!("{:#?}", item);
149+
// First we find the opaque type in question.
150+
for ty in trait_ref.substs {
151+
for ty in ty.walk() {
152+
let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue };
153+
let ty::Opaque(def_id, _) = *ty.kind() else { continue };
154+
trace!(?def_id);
155+
156+
// Then we search for mentions of the opaque type's type alias in the HIR
157+
struct SpanFinder<'tcx> {
158+
sp: Span,
159+
def_id: DefId,
160+
tcx: TyCtxt<'tcx>,
161+
}
162+
impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> {
163+
#[instrument(level = "trace", skip(self, _id))]
164+
fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
165+
// You can't mention an opaque type directly, so we look for type aliases
166+
if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res {
167+
// And check if that type alias's type contains the opaque type we're looking for
168+
for arg in self.tcx.type_of(def_id).walk() {
169+
if let GenericArgKind::Type(ty) = arg.unpack() {
170+
if let ty::Opaque(def_id, _) = *ty.kind() {
171+
if def_id == self.def_id {
172+
// Finally we update the span to the mention of the type alias
173+
self.sp = path.span;
174+
return;
175+
}
176+
}
177+
}
178+
}
179+
}
180+
hir::intravisit::walk_path(self, path)
181+
}
182+
}
183+
184+
let mut visitor = SpanFinder { sp, def_id, tcx };
185+
hir::intravisit::walk_item(&mut visitor, item);
186+
let reported = tcx
187+
.sess
188+
.struct_span_err(visitor.sp, "cannot implement trait on type alias impl trait")
189+
.span_note(tcx.def_span(def_id), "type alias impl trait defined here")
190+
.emit();
191+
return Err(reported);
192+
}
193+
}
194+
span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
151195
}
152196

153197
Ok(())

src/test/ui/impl-trait/auto-trait.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ impl<T: Send> AnotherTrait for T {}
2020
// in the future.)
2121
impl AnotherTrait for D<OpaqueType> {
2222
//~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
23+
//~| ERROR cannot implement trait on type alias impl trait
2324
}
2425

2526
fn main() {}

src/test/ui/impl-trait/auto-trait.stderr

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
error: cannot implement trait on type alias impl trait
2+
--> $DIR/auto-trait.rs:21:25
3+
|
4+
LL | impl AnotherTrait for D<OpaqueType> {
5+
| ^^^^^^^^^^
6+
|
7+
note: type alias impl trait defined here
8+
--> $DIR/auto-trait.rs:7:19
9+
|
10+
LL | type OpaqueType = impl OpaqueTrait;
11+
| ^^^^^^^^^^^^^^^^
12+
113
error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
214
--> $DIR/auto-trait.rs:21:1
315
|
@@ -7,6 +19,6 @@ LL | impl<T: Send> AnotherTrait for T {}
719
LL | impl AnotherTrait for D<OpaqueType> {
820
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
921

10-
error: aborting due to previous error
22+
error: aborting due to 2 previous errors
1123

1224
For more information about this error, try `rustc --explain E0119`.

src/test/ui/impl-trait/negative-reasoning.rs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ impl<T: std::fmt::Debug> AnotherTrait for T {}
1818
// This is in error, because we cannot assume that `OpaqueType: !Debug`
1919
impl AnotherTrait for D<OpaqueType> {
2020
//~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
21+
//~| ERROR cannot implement trait on type alias impl trait
2122
}
2223

2324
fn main() {}

src/test/ui/impl-trait/negative-reasoning.stderr

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
error: cannot implement trait on type alias impl trait
2+
--> $DIR/negative-reasoning.rs:19:25
3+
|
4+
LL | impl AnotherTrait for D<OpaqueType> {
5+
| ^^^^^^^^^^
6+
|
7+
note: type alias impl trait defined here
8+
--> $DIR/negative-reasoning.rs:7:19
9+
|
10+
LL | type OpaqueType = impl OpaqueTrait;
11+
| ^^^^^^^^^^^^^^^^
12+
113
error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
214
--> $DIR/negative-reasoning.rs:19:1
315
|
@@ -9,6 +21,6 @@ LL | impl AnotherTrait for D<OpaqueType> {
921
|
1022
= note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
1123

12-
error: aborting due to previous error
24+
error: aborting due to 2 previous errors
1325

1426
For more information about this error, try `rustc --explain E0119`.

src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ type Foo = impl PartialEq<(Foo, i32)>;
55
struct Bar;
66

77
impl PartialEq<(Foo, i32)> for Bar {
8+
//~^ ERROR cannot implement trait on type alias impl trait
89
fn eq(&self, _other: &(Foo, i32)) -> bool {
910
true
1011
}
1112
}
1213

1314
fn foo() -> Foo {
14-
Bar //~ ERROR can't compare `Bar` with `(Bar, i32)`
15+
Bar
1516
}
1617

1718
fn main() {}

src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
error[E0277]: can't compare `Bar` with `(Bar, i32)`
2-
--> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:14:5
1+
error: cannot implement trait on type alias impl trait
2+
--> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:7:17
33
|
4-
LL | Bar
5-
| ^^^ no implementation for `Bar == (Bar, i32)`
4+
LL | impl PartialEq<(Foo, i32)> for Bar {
5+
| ^^^
66
|
7-
= help: the trait `PartialEq<(Bar, i32)>` is not implemented for `Bar`
8-
= help: the trait `PartialEq<(Foo, i32)>` is implemented for `Bar`
7+
note: type alias impl trait defined here
8+
--> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:3:12
9+
|
10+
LL | type Foo = impl PartialEq<(Foo, i32)>;
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
912

1013
error: aborting due to previous error
1114

12-
For more information about this error, try `rustc --explain E0277`.

src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
mod a {
44
type Foo = impl PartialEq<(Foo, i32)>;
5-
//~^ ERROR unconstrained opaque type
65

76
struct Bar;
87

@@ -15,13 +14,12 @@ mod a {
1514

1615
mod b {
1716
type Foo = impl PartialEq<(Foo, i32)>;
18-
//~^ ERROR unconstrained opaque type
1917

2018
struct Bar;
2119

2220
impl PartialEq<(Foo, i32)> for Bar {
21+
//~^ ERROR cannot implement trait on type alias impl trait
2322
fn eq(&self, _other: &(Bar, i32)) -> bool {
24-
//~^ ERROR impl has stricter requirements than trait
2523
true
2624
}
2725
}
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,14 @@
1-
error: unconstrained opaque type
2-
--> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16
1+
error: cannot implement trait on type alias impl trait
2+
--> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:20:21
33
|
4-
LL | type Foo = impl PartialEq<(Foo, i32)>;
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
LL | impl PartialEq<(Foo, i32)> for Bar {
5+
| ^^^
66
|
7-
= note: `Foo` must be used in combination with a concrete type within the same module
8-
9-
error: unconstrained opaque type
10-
--> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:17:16
7+
note: type alias impl trait defined here
8+
--> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:16:16
119
|
1210
LL | type Foo = impl PartialEq<(Foo, i32)>;
1311
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
14-
|
15-
= note: `Foo` must be used in combination with a concrete type within the same module
16-
17-
error[E0276]: impl has stricter requirements than trait
18-
--> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:23:9
19-
|
20-
LL | fn eq(&self, _other: &(Bar, i32)) -> bool {
21-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `b::Bar: PartialEq<(b::Bar, i32)>`
2212

23-
error: aborting due to 3 previous errors
13+
error: aborting due to previous error
2414

25-
For more information about this error, try `rustc --explain E0276`.

src/test/ui/traits/alias/issue-83613.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: cannot implement trait on type alias impl trait
2-
--> $DIR/issue-83613.rs:10:1
2+
--> $DIR/issue-83613.rs:10:23
33
|
44
LL | impl AnotherTrait for OpaqueType {}
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5+
| ^^^^^^^^^^
66
|
77
note: type alias impl trait defined here
88
--> $DIR/issue-83613.rs:4:19

src/test/ui/type-alias-impl-trait/issue-65384.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: cannot implement trait on type alias impl trait
2-
--> $DIR/issue-65384.rs:10:1
2+
--> $DIR/issue-65384.rs:10:18
33
|
44
LL | impl MyTrait for Bar {}
5-
| ^^^^^^^^^^^^^^^^^^^^
5+
| ^^^
66
|
77
note: type alias impl trait defined here
88
--> $DIR/issue-65384.rs:8:12

src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: cannot implement trait on type alias impl trait
2-
--> $DIR/issue-76202-trait-impl-for-tait.rs:16:1
2+
--> $DIR/issue-76202-trait-impl-for-tait.rs:16:15
33
|
44
LL | impl Test for F {
5-
| ^^^^^^^^^^^^^^^
5+
| ^
66
|
77
note: type alias impl trait defined here
88
--> $DIR/issue-76202-trait-impl-for-tait.rs:9:10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Regression test for issues #84660 and #86411: both are variations on #76202.
2+
// Tests that we don't ICE when we have an opaque type appearing anywhere in an impl header.
3+
4+
#![feature(type_alias_impl_trait)]
5+
6+
trait Foo {}
7+
impl Foo for () {}
8+
type Bar = impl Foo;
9+
fn _defining_use() -> Bar {}
10+
11+
trait TraitArg<T> {
12+
fn f();
13+
}
14+
15+
impl TraitArg<Bar> for () { //~ ERROR cannot implement trait
16+
fn f() {
17+
println!("ho");
18+
}
19+
}
20+
21+
fn main() {
22+
<() as TraitArg<Bar>>::f();
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: cannot implement trait on type alias impl trait
2+
--> $DIR/issue-84660-trait-impl-for-tait.rs:15:15
3+
|
4+
LL | impl TraitArg<Bar> for () {
5+
| ^^^
6+
|
7+
note: type alias impl trait defined here
8+
--> $DIR/issue-84660-trait-impl-for-tait.rs:8:12
9+
|
10+
LL | type Bar = impl Foo;
11+
| ^^^^^^^^
12+
13+
error: aborting due to previous error
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Another example from issue #84660, this time weaponized as a safe transmute: an opaque type in an
2+
// impl header being accepted was used to create unsoundness.
3+
4+
#![feature(type_alias_impl_trait)]
5+
6+
trait Foo {}
7+
impl Foo for () {}
8+
type Bar = impl Foo;
9+
fn _defining_use() -> Bar {}
10+
11+
trait Trait<T, In> {
12+
type Out;
13+
fn convert(i: In) -> Self::Out;
14+
}
15+
16+
impl<In, Out> Trait<Bar, In> for Out { //~ ERROR cannot implement trait
17+
type Out = Out;
18+
fn convert(_i: In) -> Self::Out {
19+
unreachable!();
20+
}
21+
}
22+
23+
impl<In, Out> Trait<(), In> for Out {
24+
type Out = In;
25+
fn convert(i: In) -> Self::Out {
26+
i
27+
}
28+
}
29+
30+
fn transmute<In, Out>(i: In) -> Out {
31+
<Out as Trait<Bar, In>>::convert(i)
32+
}
33+
34+
fn main() {
35+
let d;
36+
{
37+
let x = "Hello World".to_string();
38+
d = transmute::<&String, &String>(&x);
39+
}
40+
println!("{}", d);
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: cannot implement trait on type alias impl trait
2+
--> $DIR/issue-84660-unsoundness.rs:16:21
3+
|
4+
LL | impl<In, Out> Trait<Bar, In> for Out {
5+
| ^^^
6+
|
7+
note: type alias impl trait defined here
8+
--> $DIR/issue-84660-unsoundness.rs:8:12
9+
|
10+
LL | type Bar = impl Foo;
11+
| ^^^^^^^^
12+
13+
error: aborting due to previous error
14+

src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
use std::fmt::Debug;
55

66
type FooX = impl Debug;
7-
//~^ unconstrained opaque type
87

98
trait Foo<A> { }
109

1110
impl Foo<FooX> for () { }
11+
//~^ cannot implement trait on type alias impl trait
1212

1313
fn foo() -> impl Foo<FooX> {
1414
()
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
error: unconstrained opaque type
1+
error: cannot implement trait on type alias impl trait
2+
--> $DIR/nested-tait-inference3.rs:10:10
3+
|
4+
LL | impl Foo<FooX> for () { }
5+
| ^^^^
6+
|
7+
note: type alias impl trait defined here
28
--> $DIR/nested-tait-inference3.rs:6:13
39
|
410
LL | type FooX = impl Debug;
511
| ^^^^^^^^^^
6-
|
7-
= note: `FooX` must be used in combination with a concrete type within the same module
812

913
error: aborting due to previous error
1014

0 commit comments

Comments
 (0)