@@ -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
0 commit comments