|
7 | 7 | use rustc_data_structures::fx::FxHashSet; |
8 | 8 | use rustc_errors::codes::*; |
9 | 9 | use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; |
| 10 | +use rustc_hir as hir; |
10 | 11 | use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; |
11 | 12 | use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; |
12 | 13 | use rustc_middle::span_bug; |
13 | 14 | use rustc_middle::ty::util::CheckRegions; |
14 | 15 | use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode}; |
| 16 | +use rustc_span::sym; |
15 | 17 | use rustc_trait_selection::regions::InferCtxtRegionExt; |
16 | 18 | use rustc_trait_selection::traits::{self, ObligationCtxt}; |
17 | 19 |
|
@@ -70,7 +72,11 @@ pub(crate) fn check_drop_impl( |
70 | 72 | drop_impl_did, |
71 | 73 | adt_def.did(), |
72 | 74 | adt_to_impl_args, |
73 | | - ) |
| 75 | + )?; |
| 76 | + |
| 77 | + check_drop_xor_pin_drop(tcx, drop_impl_did)?; |
| 78 | + |
| 79 | + Ok(()) |
74 | 80 | } |
75 | 81 | _ => { |
76 | 82 | span_bug!(tcx.def_span(drop_impl_did), "incoherent impl of Drop"); |
@@ -294,3 +300,58 @@ fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>( |
294 | 300 |
|
295 | 301 | Ok(()) |
296 | 302 | } |
| 303 | + |
| 304 | +/// This function checks at least and at most one of `Drop::drop` and `Drop::pin_drop` is implemented. |
| 305 | +fn check_drop_xor_pin_drop<'tcx>( |
| 306 | + tcx: TyCtxt<'tcx>, |
| 307 | + drop_impl_did: LocalDefId, |
| 308 | +) -> Result<(), ErrorGuaranteed> { |
| 309 | + let item_impl = tcx.hir_expect_item(drop_impl_did).expect_impl(); |
| 310 | + let mut drop_span = None; |
| 311 | + let mut pin_drop_span = None; |
| 312 | + for &impl_item_id in item_impl.items { |
| 313 | + let impl_item = tcx.hir_impl_item(impl_item_id); |
| 314 | + if let hir::ImplItemKind::Fn(fn_sig, _) = impl_item.kind { |
| 315 | + match impl_item.ident.name { |
| 316 | + sym::drop => drop_span = Some(fn_sig.span), |
| 317 | + sym::pin_drop => pin_drop_span = Some(fn_sig.span), |
| 318 | + _ => {} |
| 319 | + } |
| 320 | + } |
| 321 | + } |
| 322 | + |
| 323 | + match (drop_span, pin_drop_span) { |
| 324 | + (None, None) => { |
| 325 | + if tcx.features().pin_ergonomics() { |
| 326 | + return Err(tcx.dcx().emit_err(crate::errors::MissingOneOfTraitItem { |
| 327 | + span: tcx.def_span(drop_impl_did), |
| 328 | + note: None, |
| 329 | + missing_items_msg: "drop`, `pin_drop".to_string(), |
| 330 | + })); |
| 331 | + } else { |
| 332 | + return Err(tcx |
| 333 | + .dcx() |
| 334 | + .span_delayed_bug(tcx.def_span(drop_impl_did), "missing `Drop::drop`")); |
| 335 | + } |
| 336 | + } |
| 337 | + // FIXME(pin_ergonomics): reject `Drop::drop` for types that support pin-projection. |
| 338 | + (Some(_span), None) => {} |
| 339 | + (None, Some(span)) => { |
| 340 | + if !tcx.features().pin_ergonomics() { |
| 341 | + return Err(tcx.dcx().span_delayed_bug( |
| 342 | + span, |
| 343 | + "`Drop::pin_drop` should be guarded by the library feature gate", |
| 344 | + )); |
| 345 | + } |
| 346 | + // FIXME(pin_ergonomics): reject `Drop::pin_drop` for types that don't support pin-projection. |
| 347 | + } |
| 348 | + (Some(drop_span), Some(pin_drop_span)) => { |
| 349 | + return Err(tcx.dcx().emit_err(crate::errors::ConflictImplDropAndPinDrop { |
| 350 | + span: tcx.def_span(drop_impl_did), |
| 351 | + drop_span, |
| 352 | + pin_drop_span, |
| 353 | + })); |
| 354 | + } |
| 355 | + } |
| 356 | + Ok(()) |
| 357 | +} |
0 commit comments