mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Forbid manual Unpin impls for structurally pinned types
This commit is contained in:
@@ -224,6 +224,10 @@ hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a par
|
||||
hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
|
||||
.note = parent implementation is in crate `{$cname}`
|
||||
|
||||
hir_analysis_impl_unpin_for_pin_projected_type = explicit impls for the `Unpin` trait are not permitted for structurally pinned types
|
||||
.label = impl of `Unpin` not allowed
|
||||
.help = `{$adt_name}` is structurally pinned because it is marked as `#[pin_v2]`
|
||||
|
||||
hir_analysis_inherent_dyn = cannot define inherent `impl` for a dyn auto trait
|
||||
.label = impl requires at least one non-auto trait
|
||||
.note = define and implement a new trait or type instead
|
||||
|
||||
@@ -38,6 +38,7 @@ pub(super) fn check_trait<'tcx>(
|
||||
checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?;
|
||||
checker.check(lang_items.async_drop_trait(), visit_implementation_of_drop)?;
|
||||
checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?;
|
||||
checker.check(lang_items.unpin_trait(), visit_implementation_of_unpin)?;
|
||||
checker.check(lang_items.const_param_ty_trait(), |checker| {
|
||||
visit_implementation_of_const_param_ty(checker)
|
||||
})?;
|
||||
@@ -134,6 +135,41 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_implementation_of_unpin(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
|
||||
let tcx = checker.tcx;
|
||||
let impl_header = checker.impl_header;
|
||||
let impl_did = checker.impl_def_id;
|
||||
debug!("visit_implementation_of_unpin: impl_did={:?}", impl_did);
|
||||
|
||||
let self_type = impl_header.trait_ref.instantiate_identity().self_ty();
|
||||
debug!("visit_implementation_of_unpin: self_type={:?}", self_type);
|
||||
|
||||
let span = tcx.def_span(impl_did);
|
||||
|
||||
if tcx.features().pin_ergonomics() {
|
||||
match self_type.kind() {
|
||||
// Soundness concerns: a type `T` annotated with `#[pin_v2]` is allowed to project
|
||||
// `Pin<&mut T>` to its field `Pin<&mut U>` safely (even if `U: !Unpin`).
|
||||
// If `T` is allowed to impl `Unpin` manually (note that `Unpin` is a safe trait,
|
||||
// which cannot carry safety properties), then `&mut U` could be obtained from
|
||||
// `&mut T` that dereferenced by `Pin<&mut T>`, which breaks the safety contract of
|
||||
// `Pin<&mut U>` for `U: !Unpin`.
|
||||
ty::Adt(adt, _) if adt.is_pin_project() => {
|
||||
return Err(tcx.dcx().emit_err(crate::errors::ImplUnpinForPinProjectedType {
|
||||
span,
|
||||
adt_span: tcx.def_span(adt.did()),
|
||||
adt_name: tcx.item_name(adt.did()),
|
||||
}));
|
||||
}
|
||||
ty::Adt(_, _) => {}
|
||||
_ => {
|
||||
return Err(tcx.dcx().span_delayed_bug(span, "impl of `Unpin` for a non-adt type"));
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
|
||||
let tcx = checker.tcx;
|
||||
let header = checker.impl_header;
|
||||
|
||||
@@ -1690,3 +1690,14 @@ pub(crate) struct EiiWithGenerics {
|
||||
pub eii_name: Symbol,
|
||||
pub impl_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_impl_unpin_for_pin_projected_type)]
|
||||
pub(crate) struct ImplUnpinForPinProjectedType {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[help]
|
||||
pub adt_span: Span,
|
||||
pub adt_name: Symbol,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
error: explicit impls for the `Unpin` trait are not permitted for structurally pinned types
|
||||
--> $DIR/impl-unpin.rs:14:5
|
||||
|
|
||||
LL | impl Unpin for Foo {}
|
||||
| ^^^^^^^^^^^^^^^^^^ impl of `Unpin` not allowed
|
||||
|
|
||||
help: `Foo` is structurally pinned because it is marked as `#[pin_v2]`
|
||||
--> $DIR/impl-unpin.rs:7:1
|
||||
|
|
||||
LL | struct Foo;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
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`
|
||||
--> $DIR/impl-unpin.rs:68:5
|
||||
|
|
||||
LL | impl Unpin for <Foo as Identity>::Assoc {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
|
||||
|
||||
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`
|
||||
--> $DIR/impl-unpin.rs:70:5
|
||||
|
|
||||
LL | impl Unpin for <Bar as Identity>::Assoc {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0321`.
|
||||
@@ -0,0 +1,74 @@
|
||||
//@ revisions: adt tait ty_alias assoc
|
||||
#![feature(pin_ergonomics)]
|
||||
#![cfg_attr(tait, feature(type_alias_impl_trait))]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
#[pin_v2]
|
||||
struct Foo;
|
||||
struct Bar;
|
||||
|
||||
#[cfg(adt)]
|
||||
mod adt {
|
||||
use super::*;
|
||||
|
||||
impl Unpin for Foo {}
|
||||
//[adt]~^ ERROR explicit impls for the `Unpin` trait are not permitted for structurally pinned types
|
||||
impl Unpin for Bar {} // ok
|
||||
}
|
||||
|
||||
#[cfg(ty_alias)]
|
||||
mod ty_alias {
|
||||
use super::*;
|
||||
|
||||
type Identity<T> = T;
|
||||
|
||||
impl Unpin for Identity<Foo> {}
|
||||
//[ty_alias]~^ ERROR explicit impls for the `Unpin` trait are not permitted for structurally pinned types
|
||||
impl Unpin for Identity<Bar> {} // ok
|
||||
}
|
||||
|
||||
#[cfg(tait)]
|
||||
mod tait {
|
||||
use super::*;
|
||||
|
||||
trait Identity<T> {}
|
||||
|
||||
impl<T> Identity<T> for T {}
|
||||
|
||||
type FooAlias = impl Identity<Foo>;
|
||||
type BarAlias = impl Identity<Bar>;
|
||||
|
||||
#[define_opaque(FooAlias)]
|
||||
fn foo_alias() -> FooAlias {
|
||||
Foo
|
||||
}
|
||||
#[define_opaque(BarAlias)]
|
||||
fn bar_alias() -> BarAlias {
|
||||
Bar
|
||||
}
|
||||
|
||||
impl Unpin for FooAlias {}
|
||||
//[tait]~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
|
||||
impl Unpin for BarAlias {}
|
||||
//[tait]~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
|
||||
}
|
||||
|
||||
#[cfg(assoc)]
|
||||
mod assoc {
|
||||
use super::*;
|
||||
|
||||
trait Identity {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<T> Identity for T {
|
||||
type Assoc = T;
|
||||
}
|
||||
|
||||
impl Unpin for <Foo as Identity>::Assoc {}
|
||||
//[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`
|
||||
impl Unpin for <Bar as Identity>::Assoc {}
|
||||
//[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`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,27 @@
|
||||
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
|
||||
--> $DIR/impl-unpin.rs:50:5
|
||||
|
|
||||
LL | impl Unpin for FooAlias {}
|
||||
| ^^^^^^^^^^^^^^^--------
|
||||
| |
|
||||
| type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate
|
||||
|
|
||||
= note: impl doesn't have any local type before any uncovered type parameters
|
||||
= note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
|
||||
= note: define and implement a trait or new type instead
|
||||
|
||||
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
|
||||
--> $DIR/impl-unpin.rs:52:5
|
||||
|
|
||||
LL | impl Unpin for BarAlias {}
|
||||
| ^^^^^^^^^^^^^^^--------
|
||||
| |
|
||||
| type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate
|
||||
|
|
||||
= note: impl doesn't have any local type before any uncovered type parameters
|
||||
= note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
|
||||
= note: define and implement a trait or new type instead
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0117`.
|
||||
@@ -0,0 +1,14 @@
|
||||
error: explicit impls for the `Unpin` trait are not permitted for structurally pinned types
|
||||
--> $DIR/impl-unpin.rs:25:5
|
||||
|
|
||||
LL | impl Unpin for Identity<Foo> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Unpin` not allowed
|
||||
|
|
||||
help: `Foo` is structurally pinned because it is marked as `#[pin_v2]`
|
||||
--> $DIR/impl-unpin.rs:7:1
|
||||
|
|
||||
LL | struct Foo;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
Reference in New Issue
Block a user