about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicholas Nethercote <n.nethercote@gmail.com>2024-02-20 09:36:28 +1100
committerNicholas Nethercote <n.nethercote@gmail.com>2024-02-21 10:35:54 +1100
commit2903bbbc156fb9707b43038af6723844fd4ccf29 (patch)
tree390101b18fd0e9ef81ab70d788653e96b991f8e5
parent010f3944e0f0baac8d738da49772fd06acd3701b (diff)
downloadrust-2903bbbc156fb9707b43038af6723844fd4ccf29.tar.gz
rust-2903bbbc156fb9707b43038af6723844fd4ccf29.zip
Convert `bug`s back to `delayed_bug`s.
This commit undoes some of the previous commit's mechanical changes,
based on human judgment.
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs6
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs6
-rw-r--r--compiler/rustc_infer/src/infer/relate/nll.rs2
-rw-r--r--compiler/rustc_middle/src/ty/util.rs4
-rw-r--r--compiler/rustc_middle/src/util/bug.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs10
-rw-r--r--compiler/rustc_mir_build/src/thir/constant.rs10
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs2
-rw-r--r--tests/ui/drop/missing-drop-method.rs4
-rw-r--r--tests/ui/drop/missing-drop-method.stderr11
24 files changed, 87 insertions, 42 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index fea8c5a6de6..e228bef1139 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -626,8 +626,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                     | GenericArgKind::Const(_),
                     _,
                 ) => {
-                    // HIR lowering sometimes doesn't catch this in erroneous
-                    // programs, so we need to use span_delayed_bug here. See #82126.
+                    // This was previously a `span_delayed_bug` and could be
+                    // reached by the test for #82126, but no longer.
                     self.dcx().span_bug(
                         hir_arg.span(),
                         format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"),
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 0fc04175705..897918fb0a4 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -316,7 +316,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                     .and(type_op::normalize::Normalize::new(ty))
                     .fully_perform(self.infcx, span)
                 else {
-                    tcx.dcx().span_bug(span, format!("failed to normalize {ty:?}"));
+                    // Note: this path is currently not reached in any test, so
+                    // any example that triggers this would be worth minimizing
+                    // and converting into a test.
+                    tcx.dcx().span_delayed_bug(span, format!("failed to normalize {ty:?}"));
+                    continue;
                 };
                 constraints.extend(c);
 
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 77744945b12..946ffc05cc1 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -622,7 +622,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
                 );
                 // If this was a hard error, don't bother continuing evaluation.
                 if is_error {
-                    let guard: rustc_errors::ErrorGuaranteed = ecx
+                    let guard = ecx
                         .tcx
                         .dcx()
                         .span_delayed_bug(span, "The deny lint should have already errored");
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 42a64d8670d..435e251b130 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -734,6 +734,10 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
                 remapped_types.insert(def_id, ty::EarlyBinder::bind(ty));
             }
             Err(err) => {
+                // This code path is not reached in any tests, but may be
+                // reachable. If this is triggered, it should be converted to
+                // `span_delayed_bug` and the triggering case turned into a
+                // test.
                 tcx.dcx()
                     .span_bug(return_span, format!("could not fully resolve: {ty} => {err:?}"));
             }
@@ -914,7 +918,13 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
                         .with_note(format!("hidden type inferred to be `{}`", self.ty))
                         .emit()
                 }
-                _ => self.tcx.dcx().bug("should've been able to remap region"),
+                _ => {
+                    // This code path is not reached in any tests, but may be
+                    // reachable. If this is triggered, it should be converted
+                    // to `delayed_bug` and the triggering case turned into a
+                    // test.
+                    self.tcx.dcx().bug("should've been able to remap region");
+                }
             };
             return Err(guar);
         };
@@ -1273,6 +1283,8 @@ fn compare_number_of_generics<'tcx>(
     // inheriting the generics from will also have mismatched arguments, and
     // we'll report an error for that instead. Delay a bug for safety, though.
     if trait_.is_impl_trait_in_trait() {
+        // FIXME: no tests trigger this. If you find example code that does
+        // trigger this, please add it to the test suite.
         tcx.dcx()
             .bug("errors comparing numbers of generics of trait/impl functions were not emitted");
     }
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index da40d6a860e..7bdbab4325c 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -154,6 +154,9 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
         trait_m_sig.inputs_and_output,
     ));
     if !ocx.select_all_or_error().is_empty() {
+        // This code path is not reached in any tests, but may be reachable. If
+        // this is triggered, it should be converted to `delayed_bug` and the
+        // triggering case turned into a test.
         tcx.dcx().bug("encountered errors when checking RPITIT refinement (selection)");
     }
     let outlives_env = OutlivesEnvironment::with_bounds(
@@ -162,10 +165,16 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
     );
     let errors = infcx.resolve_regions(&outlives_env);
     if !errors.is_empty() {
+        // This code path is not reached in any tests, but may be reachable. If
+        // this is triggered, it should be converted to `delayed_bug` and the
+        // triggering case turned into a test.
         tcx.dcx().bug("encountered errors when checking RPITIT refinement (regions)");
     }
     // Resolve any lifetime variables that may have been introduced during normalization.
     let Ok((trait_bounds, impl_bounds)) = infcx.fully_resolve((trait_bounds, impl_bounds)) else {
+        // This code path is not reached in any tests, but may be reachable. If
+        // this is triggered, it should be converted to `delayed_bug` and the
+        // triggering case turned into a test.
         tcx.dcx().bug("encountered errors when checking RPITIT refinement (resolution)");
     };
 
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index 9b46b415491..82a6b6b6f2c 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -67,10 +67,11 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
             // already checked by coherence, but compilation may
             // not have been terminated.
             let span = tcx.def_span(drop_impl_did);
-            tcx.dcx().span_bug(
+            let reported = tcx.dcx().span_delayed_bug(
                 span,
                 format!("should have been rejected by coherence check: {dtor_self_type}"),
             );
+            Err(reported)
         }
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 81d8a51485f..f03d0f8a885 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1087,12 +1087,8 @@ fn check_type_defn<'tcx>(
                 packed && {
                     let ty = tcx.type_of(variant.tail().did).instantiate_identity();
                     let ty = tcx.erase_regions(ty);
-                    if ty.has_infer() {
-                        // Unresolved type expression.
-                        tcx.dcx().span_bug(item.span, format!("inference variables in {ty:?}"));
-                    } else {
-                        ty.needs_drop(tcx, tcx.param_env(item.owner_id))
-                    }
+                    assert!(!ty.has_infer());
+                    ty.needs_drop(tcx, tcx.param_env(item.owner_id))
                 }
             };
             // All fields (except for possibly the last) should be sized.
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 0a636fa9eac..89cc46dc5ab 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1315,9 +1315,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // the LUB of the breaks (possibly ! if none); else, it
         // is nil. This makes sense because infinite loops
         // (which would have type !) are only possible iff we
-        // permit break with a value [1].
+        // permit break with a value.
         if ctxt.coerce.is_none() && !ctxt.may_break {
-            // [1]
             self.dcx().span_bug(body.span, "no coercion, but loop may not break");
         }
         ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| Ty::new_unit(self.tcx))
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index fd62afbae96..9e3867e630d 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -48,6 +48,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let to = normalize(to);
         trace!(?from, ?to);
         if from.has_non_region_infer() || to.has_non_region_infer() {
+            // Note: this path is currently not reached in any test, so any
+            // example that triggers this would be worth minimizing and
+            // converting into a test.
             tcx.dcx().span_bug(span, "argument to transmute has inference variables");
         }
         // Transmutes that are only changing lifetimes are always ok.
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 13f33abaa64..005d217fdc4 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -924,7 +924,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         span: item_span,
                         ..
                     })) => {
-                        tcx.dcx().span_bug(
+                        tcx.dcx().span_delayed_bug(
                             *item_span,
                             "auto trait is invoked with no method error, but no error reported?",
                         );
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 643fe83e898..c0a99e5cc41 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -303,7 +303,7 @@ where
                     // Ignore this, we presume it will yield an error later,
                     // since if a type variable is not resolved by this point
                     // it never will be.
-                    self.tcx.dcx().span_bug(
+                    self.tcx.dcx().span_delayed_bug(
                         origin.span(),
                         format!("unresolved inference variable in outlives: {v:?}"),
                     );
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 515f44c914d..3ef37bf3466 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -175,7 +175,11 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
                 // Ignore this, we presume it will yield an error later, since
                 // if a type variable is not resolved by this point it never
                 // will be.
-                self.tcx.dcx().bug(format!("unresolved inference variable in outlives: {v:?}"));
+                self.tcx
+                    .dcx()
+                    .delayed_bug(format!("unresolved inference variable in outlives: {v:?}"));
+                // Add a bound that never holds.
+                VerifyBound::AnyBound(vec![])
             }
         }
     }
diff --git a/compiler/rustc_infer/src/infer/relate/nll.rs b/compiler/rustc_infer/src/infer/relate/nll.rs
index 4cc6457df7a..87a1ae7bbac 100644
--- a/compiler/rustc_infer/src/infer/relate/nll.rs
+++ b/compiler/rustc_infer/src/infer/relate/nll.rs
@@ -422,7 +422,7 @@ where
                 // Forbid inference variables in the RHS.
                 self.infcx
                     .dcx()
-                    .span_bug(self.delegate.span(), format!("unexpected inference var {b:?}",));
+                    .span_bug(self.delegate.span(), format!("unexpected inference var {b:?}"));
             }
             // FIXME(invariance): see the related FIXME above.
             _ => self.infcx.super_combine_consts(self, a, b),
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 95d55a7081d..3f539945841 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -356,7 +356,9 @@ impl<'tcx> TyCtxt<'tcx> {
             }
 
             let Some(item_id) = self.associated_item_def_ids(impl_did).first() else {
-                self.dcx().span_bug(self.def_span(impl_did), "Drop impl without drop function");
+                self.dcx()
+                    .span_delayed_bug(self.def_span(impl_did), "Drop impl without drop function");
+                return;
             };
 
             if let Some((old_item_id, _)) = dtor_candidate {
diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs
index dae6c0b9d68..a67ec991582 100644
--- a/compiler/rustc_middle/src/util/bug.rs
+++ b/compiler/rustc_middle/src/util/bug.rs
@@ -42,7 +42,7 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
 /// delayed bug, so what is the point of this? It exists to help us test the interaction of delayed
 /// bugs with the query system and incremental.
 pub fn trigger_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
-    tcx.dcx().span_bug(
+    tcx.dcx().span_delayed_bug(
         tcx.def_span(key),
         "delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]",
     );
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index d66540d8e79..a557f61b016 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -110,12 +110,12 @@ fn lit_to_mir_constant<'tcx>(
     let LitToConstInput { lit, ty, neg } = lit_input;
     let trunc = |n| {
         let param_ty = ty::ParamEnv::reveal_all().and(ty);
-        let width = tcx
-            .layout_of(param_ty)
-            .map_err(|_| {
+        let width = match tcx.layout_of(param_ty) {
+            Ok(layout) => layout.size,
+            Err(_) => {
                 tcx.dcx().bug(format!("couldn't compute width of literal: {:?}", lit_input.lit))
-            })?
-            .size;
+            }
+        };
         trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
         let result = width.truncate(n);
         trace!("trunc result: {}", result);
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index 46580432f13..65cc13286af 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -12,12 +12,12 @@ pub(crate) fn lit_to_const<'tcx>(
 
     let trunc = |n| {
         let param_ty = ParamEnv::reveal_all().and(ty);
-        let width = tcx
-            .layout_of(param_ty)
-            .map_err(|_| {
+        let width = match tcx.layout_of(param_ty) {
+            Ok(layout) => layout.size,
+            Err(_) => {
                 tcx.dcx().bug(format!("couldn't compute width of literal: {:?}", lit_input.lit))
-            })?
-            .size;
+            }
+        };
         trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
         let result = width.truncate(n);
         trace!("trunc result: {}", result);
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 676bc9db4a9..2f4da29133f 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -3681,9 +3681,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                 None
             }
             Res::SelfCtor(_) => {
-                // njn: remove comment?
                 // We resolve `Self` in pattern position as an ident sometimes during recovery,
-                // so delay a bug instead of ICEing.
+                // so delay a bug instead of ICEing. (Note: is this no longer true? We now ICE. If
+                // this triggers, please convert to a delayed bug and add a test.)
                 self.r.dcx().span_bug(
                     ident.span,
                     "unexpected `SelfCtor` in pattern, expected identifier"
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 79f423756fd..189e1ba54bc 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -62,11 +62,10 @@ pub fn is_const_evaluatable<'tcx>(
 
         match unexpanded_ct.kind() {
             ty::ConstKind::Expr(_) => {
-                // njn: ?
-                // FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete,
-                // but currently it is not possible to evaluate `ConstKind::Expr` so we are unable
-                // to tell if it is evaluatable or not. For now we just ICE until this is
-                // implemented.
+                // FIXME(generic_const_exprs): we have a fully concrete `ConstKind::Expr`, but
+                // haven't implemented evaluating `ConstKind::Expr` yet, so we are unable to tell
+                // if it is evaluatable or not. As this is unreachable for now, we can simple ICE
+                // here.
                 tcx.dcx().span_bug(span, "evaluating `ConstKind::Expr` is not currently supported");
             }
             ty::ConstKind::Unevaluated(uv) => {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 43f709352a2..cac53796747 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -172,6 +172,8 @@ fn do_normalize_predicates<'tcx>(
     // the normalized predicates.
     let errors = infcx.resolve_regions(&outlives_env);
     if !errors.is_empty() {
+        // @lcnr: Let's still ICE here for now. I want a test case
+        // for that.
         tcx.dcx().span_bug(
             span,
             format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"),
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index dc5b62fbd1c..f8de19043e1 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -647,9 +647,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
         Err(_) => {
             tcx.dcx().span_bug(
                 cause.span,
-                format!(
-                    "{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not"
-                ),
+                format!("{self_ty:?} was equal to {impl_ty:?} during selection but now it is not"),
             );
         }
     }
@@ -1190,10 +1188,11 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
             ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
             | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
                 // These traits have no associated types.
-                selcx.tcx().dcx().span_bug(
+                selcx.tcx().dcx().span_delayed_bug(
                     obligation.cause.span,
                     format!("Cannot project an associated type from `{impl_source:?}`"),
                 );
+                return Err(())
             }
         };
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index a8d9b0f42d9..d533e69a4fa 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -82,7 +82,7 @@ where
     let value = infcx.commit_if_ok(|_| {
         let ocx = ObligationCtxt::new(infcx);
         let value = op(&ocx).map_err(|_| {
-            infcx.dcx().span_bug(span, format!("error performing operation: {name}"))
+            infcx.dcx().span_delayed_bug(span, format!("error performing operation: {name}"))
         })?;
         let errors = ocx.select_all_or_error();
         if errors.is_empty() {
diff --git a/tests/ui/drop/missing-drop-method.rs b/tests/ui/drop/missing-drop-method.rs
new file mode 100644
index 00000000000..5828fd6c063
--- /dev/null
+++ b/tests/ui/drop/missing-drop-method.rs
@@ -0,0 +1,4 @@
+struct DropNoMethod;
+impl Drop for DropNoMethod {} //~ ERROR not all trait items implemented, missing: `drop`
+
+fn main() {}
diff --git a/tests/ui/drop/missing-drop-method.stderr b/tests/ui/drop/missing-drop-method.stderr
new file mode 100644
index 00000000000..1128f33e627
--- /dev/null
+++ b/tests/ui/drop/missing-drop-method.stderr
@@ -0,0 +1,11 @@
+error[E0046]: not all trait items implemented, missing: `drop`
+  --> $DIR/missing-drop-method.rs:2:1
+   |
+LL | impl Drop for DropNoMethod {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation
+   |
+   = help: implement the missing item: `fn drop(&mut self) { todo!() }`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0046`.