@@ -12,6 +12,7 @@ use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
1212use rustc_middle:: span_bug;
1313use rustc_middle:: ty:: util:: CheckRegions ;
1414use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt , TypingMode } ;
15+ use rustc_span:: sym;
1516use rustc_trait_selection:: regions:: InferCtxtRegionExt ;
1617use rustc_trait_selection:: traits:: { self , ObligationCtxt } ;
1718
@@ -70,7 +71,11 @@ pub(crate) fn check_drop_impl(
7071 drop_impl_did,
7172 adt_def. did ( ) ,
7273 adt_to_impl_args,
73- )
74+ ) ?;
75+
76+ check_drop_xor_pin_drop ( tcx, adt_def. did ( ) , drop_impl_did) ?;
77+
78+ Ok ( ( ) )
7479 }
7580 _ => {
7681 span_bug ! ( tcx. def_span( drop_impl_did) , "incoherent impl of Drop" ) ;
@@ -291,3 +296,68 @@ fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>(
291296
292297 Ok ( ( ) )
293298}
299+
300+ /// This function checks at least and at most one of `Drop::drop` and `Drop::pin_drop` is implemented.
301+ /// It also checks that `Drop::pin_drop` must be implemented if `#[pin_v2]` is present on the type.
302+ fn check_drop_xor_pin_drop < ' tcx > (
303+ tcx : TyCtxt < ' tcx > ,
304+ adt_def_id : DefId ,
305+ drop_impl_did : LocalDefId ,
306+ ) -> Result < ( ) , ErrorGuaranteed > {
307+ let mut drop_span = None ;
308+ let mut pin_drop_span = None ;
309+ for item in tcx. associated_items ( drop_impl_did) . in_definition_order ( ) {
310+ match item. kind {
311+ ty:: AssocKind :: Fn { name : sym:: drop, .. } => {
312+ drop_span = Some ( tcx. def_span ( item. def_id ) )
313+ }
314+ ty:: AssocKind :: Fn { name : sym:: pin_drop, .. } => {
315+ pin_drop_span = Some ( tcx. def_span ( item. def_id ) )
316+ }
317+ _ => { }
318+ }
319+ }
320+
321+ match ( drop_span, pin_drop_span) {
322+ ( None , None ) => {
323+ if tcx. features ( ) . pin_ergonomics ( ) {
324+ return Err ( tcx. dcx ( ) . emit_err ( crate :: errors:: MissingOneOfTraitItem {
325+ span : tcx. def_span ( drop_impl_did) ,
326+ note : None ,
327+ missing_items_msg : "drop`, `pin_drop" . to_string ( ) ,
328+ } ) ) ;
329+ } else {
330+ return Err ( tcx
331+ . dcx ( )
332+ . span_delayed_bug ( tcx. def_span ( drop_impl_did) , "missing `Drop::drop`" ) ) ;
333+ }
334+ }
335+ ( Some ( span) , None ) => {
336+ if tcx. adt_def ( adt_def_id) . is_pin_project ( ) {
337+ let pin_v2_span = tcx. get_attr ( adt_def_id, sym:: pin_v2) . map ( |attr| attr. span ( ) ) ;
338+ let adt_name = tcx. item_name ( adt_def_id) ;
339+ return Err ( tcx. dcx ( ) . emit_err ( crate :: errors:: PinV2WithoutPinDrop {
340+ span,
341+ pin_v2_span,
342+ adt_name,
343+ } ) ) ;
344+ }
345+ }
346+ ( None , Some ( span) ) => {
347+ if !tcx. features ( ) . pin_ergonomics ( ) {
348+ return Err ( tcx. dcx ( ) . span_delayed_bug (
349+ span,
350+ "`Drop::pin_drop` should be guarded by the library feature gate" ,
351+ ) ) ;
352+ }
353+ }
354+ ( Some ( drop_span) , Some ( pin_drop_span) ) => {
355+ return Err ( tcx. dcx ( ) . emit_err ( crate :: errors:: ConflictImplDropAndPinDrop {
356+ span : tcx. def_span ( drop_impl_did) ,
357+ drop_span,
358+ pin_drop_span,
359+ } ) ) ;
360+ }
361+ }
362+ Ok ( ( ) )
363+ }
0 commit comments