Skip to content

Commit 4def78a

Browse files
committed
test: add tests for impl Unpin for type aliases
1 parent 66e0e48 commit 4def78a

6 files changed

Lines changed: 149 additions & 18 deletions

File tree

compiler/rustc_hir_analysis/src/coherence/mod.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,18 +90,30 @@ fn enforce_trait_manually_implementable(
9090
return Err(err.emit());
9191
}
9292

93-
// Disallow explicit impls of the `Unpin` trait for structurally pinned types
94-
if tcx.features().pin_ergonomics()
95-
&& tcx.is_lang_item(trait_def_id, LangItem::Unpin)
96-
&& let Some(adt) =
97-
tcx.impl_trait_ref(impl_def_id).instantiate_identity().self_ty().ty_adt_def()
98-
&& adt.is_pin_project()
99-
{
100-
return Err(tcx.dcx().emit_err(crate::errors::ImplUnpinForPinProjectedType {
101-
span: impl_header_span,
102-
adt_span: tcx.def_span(adt.did()),
103-
adt_name: tcx.item_name(adt.did()),
104-
}));
93+
// Disallow explicit impls of the `Unpin` trait for structurally pinned types.
94+
// SAFETY: a type `T` annotated with `#[pin_v2]` is allowed to project
95+
// `Pin<&mut T>` to its field `Pin<&mut U>` safely (even if U: !Unpin).
96+
// If `T` is allowed to impl `Unpin` manually (note that `Unpin` is a safe trait,
97+
// which cannot carry safety properties), then `&mut U` could be obtained from
98+
// `&mut T` that dereferenced by `Pin<&mut T>`, which breaks the safety contract of
99+
// `Pin<&mut U>` for `U: !Unpin`.
100+
if tcx.features().pin_ergonomics() && tcx.is_lang_item(trait_def_id, LangItem::Unpin) {
101+
match tcx.impl_trait_ref(impl_def_id).instantiate_identity().self_ty().kind() {
102+
ty::Adt(adt, _) => {
103+
if adt.is_pin_project() {
104+
return Err(tcx.dcx().emit_err(crate::errors::ImplUnpinForPinProjectedType {
105+
span: impl_header_span,
106+
adt_span: tcx.def_span(adt.did()),
107+
adt_name: tcx.item_name(adt.did()),
108+
}));
109+
}
110+
}
111+
_ => {
112+
return Err(tcx
113+
.dcx()
114+
.span_delayed_bug(impl_header_span, "impl of `Unpin` for a non-adt type"));
115+
}
116+
}
105117
}
106118

107119
if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable = trait_def.specialization_kind

tests/ui/pin-ergonomics/impl-unpin.stderr renamed to tests/ui/pin-ergonomics/impl-unpin.adt.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error: explicit impls for the `Unpin` trait are not permitted for structurally pinned types
2-
--> $DIR/impl-unpin.rs:8:1
2+
--> $DIR/impl-unpin.rs:14:5
33
|
4-
LL | impl Unpin for Foo {}
5-
| ^^^^^^^^^^^^^^^^^^ impl of `Unpin` not allowed
4+
LL | impl Unpin for Foo {}
5+
| ^^^^^^^^^^^^^^^^^^ impl of `Unpin` not allowed
66
|
77
help: `Foo` is structurally pinned because it is marked as `#[pin_v2]`
8-
--> $DIR/impl-unpin.rs:5:1
8+
--> $DIR/impl-unpin.rs:7:1
99
|
1010
LL | struct Foo;
1111
| ^^^^^^^^^^
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0321]: cross-crate traits with a default impl, like `Unpin`, can only be implemented for a struct/enum type, not `<Foo as Identity>::Assoc`
2+
--> $DIR/impl-unpin.rs:68:5
3+
|
4+
LL | impl Unpin for <Foo as Identity>::Assoc {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
6+
7+
error[E0321]: cross-crate traits with a default impl, like `Unpin`, can only be implemented for a struct/enum type, not `<Bar as Identity>::Assoc`
8+
--> $DIR/impl-unpin.rs:70:5
9+
|
10+
LL | impl Unpin for <Bar as Identity>::Assoc {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0321`.
Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,74 @@
1+
//@ revisions: adt tait ty_alias assoc
12
#![feature(pin_ergonomics)]
3+
#![cfg_attr(tait, feature(type_alias_impl_trait))]
24
#![allow(incomplete_features)]
35

46
#[pin_v2]
57
struct Foo;
68
struct Bar;
79

8-
impl Unpin for Foo {} //~ ERROR explicit impls for the `Unpin` trait are not permitted for structurally pinned types
9-
impl Unpin for Bar {} // ok
10+
#[cfg(adt)]
11+
mod adt {
12+
use super::*;
13+
14+
impl Unpin for Foo {}
15+
//[adt]~^ ERROR explicit impls for the `Unpin` trait are not permitted for structurally pinned types
16+
impl Unpin for Bar {} // ok
17+
}
18+
19+
#[cfg(ty_alias)]
20+
mod ty_alias {
21+
use super::*;
22+
23+
type Identity<T> = T;
24+
25+
impl Unpin for Identity<Foo> {}
26+
//[ty_alias]~^ ERROR explicit impls for the `Unpin` trait are not permitted for structurally pinned types
27+
impl Unpin for Identity<Bar> {} // ok
28+
}
29+
30+
#[cfg(tait)]
31+
mod tait {
32+
use super::*;
33+
34+
trait Identity<T> {}
35+
36+
impl<T> Identity<T> for T {}
37+
38+
type FooAlias = impl Identity<Foo>;
39+
type BarAlias = impl Identity<Bar>;
40+
41+
#[define_opaque(FooAlias)]
42+
fn foo_alias() -> FooAlias {
43+
Foo
44+
}
45+
#[define_opaque(BarAlias)]
46+
fn bar_alias() -> BarAlias {
47+
Bar
48+
}
49+
50+
impl Unpin for FooAlias {}
51+
//[tait]~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
52+
impl Unpin for BarAlias {}
53+
//[tait]~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
54+
}
55+
56+
#[cfg(assoc)]
57+
mod assoc {
58+
use super::*;
59+
60+
trait Identity {
61+
type Assoc;
62+
}
63+
64+
impl<T> Identity for T {
65+
type Assoc = T;
66+
}
67+
68+
impl Unpin for <Foo as Identity>::Assoc {}
69+
//[assoc]~^ ERROR cross-crate traits with a default impl, like `Unpin`, can only be implemented for a struct/enum type, not `<Foo as Identity>::Assoc`
70+
impl Unpin for <Bar as Identity>::Assoc {}
71+
//[assoc]~^ ERROR cross-crate traits with a default impl, like `Unpin`, can only be implemented for a struct/enum type, not `<Bar as Identity>::Assoc`
72+
}
1073

1174
fn main() {}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
2+
--> $DIR/impl-unpin.rs:50:5
3+
|
4+
LL | impl Unpin for FooAlias {}
5+
| ^^^^^^^^^^^^^^^--------
6+
| |
7+
| type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate
8+
|
9+
= note: impl doesn't have any local type before any uncovered type parameters
10+
= note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
11+
= note: define and implement a trait or new type instead
12+
13+
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
14+
--> $DIR/impl-unpin.rs:52:5
15+
|
16+
LL | impl Unpin for BarAlias {}
17+
| ^^^^^^^^^^^^^^^--------
18+
| |
19+
| type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate
20+
|
21+
= note: impl doesn't have any local type before any uncovered type parameters
22+
= note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
23+
= note: define and implement a trait or new type instead
24+
25+
error: aborting due to 2 previous errors
26+
27+
For more information about this error, try `rustc --explain E0117`.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: explicit impls for the `Unpin` trait are not permitted for structurally pinned types
2+
--> $DIR/impl-unpin.rs:25:5
3+
|
4+
LL | impl Unpin for Identity<Foo> {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Unpin` not allowed
6+
|
7+
help: `Foo` is structurally pinned because it is marked as `#[pin_v2]`
8+
--> $DIR/impl-unpin.rs:7:1
9+
|
10+
LL | struct Foo;
11+
| ^^^^^^^^^^
12+
13+
error: aborting due to 1 previous error
14+

0 commit comments

Comments
 (0)