diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 2281343e250..d12a6a09079 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -33,6 +33,10 @@ hir_typeck_expected_default_return_type = expected `()` because of default retur hir_typeck_expected_return_type = expected `{$expected}` because of return type +hir_typeck_explicit_destructor = explicit use of destructor method + .label = explicit destructor calls not allowed + .suggestion = consider using `drop` function + hir_typeck_field_multiply_specified_in_initializer = field `{$ident}` specified more than once .label = used more than once diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 02371f85ac3..c5b2aaf2361 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -2,9 +2,10 @@ use super::method::probe::ProbeScope; use super::method::MethodCallee; use super::{Expectation, FnCtxt, TupleArgumentsFlag}; +use crate::errors; use crate::type_error_struct; use rustc_ast::util::parser::PREC_POSTFIX; -use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey}; +use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res}; use rustc_hir::def_id::DefId; @@ -44,23 +45,15 @@ pub fn check_legal_trait_for_method_call( trait_id: DefId, ) { if tcx.lang_items().drop_trait() == Some(trait_id) { - let mut err = struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method"); - err.span_label(span, "explicit destructor calls not allowed"); - - let (sp, suggestion) = receiver - .and_then(|s| tcx.sess.source_map().span_to_snippet(s).ok()) - .filter(|snippet| !snippet.is_empty()) - .map(|snippet| (expr_span, format!("drop({snippet})"))) - .unwrap_or_else(|| (span, "drop".to_string())); - - err.span_suggestion( - sp, - "consider using `drop` function", - suggestion, - Applicability::MaybeIncorrect, - ); - - err.emit(); + let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) { + errors::ExplicitDestructorCallSugg::Snippet { + lo: expr_span.shrink_to_lo(), + hi: receiver.shrink_to_hi().to(expr_span.shrink_to_hi()), + } + } else { + errors::ExplicitDestructorCallSugg::Empty(span) + }; + tcx.sess.emit_err(errors::ExplicitDestructorCall { span, sugg }); } } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 054d23c71d4..8ba04ec4baf 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -129,6 +129,29 @@ pub enum ExpectedReturnTypeLabel<'tcx> { }, } +#[derive(Diagnostic)] +#[diag(hir_typeck_explicit_destructor, code = "E0040")] +pub struct ExplicitDestructorCall { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub sugg: ExplicitDestructorCallSugg, +} + +#[derive(Subdiagnostic)] +pub enum ExplicitDestructorCallSugg { + #[suggestion(hir_typeck_suggestion, code = "drop", applicability = "maybe-incorrect")] + Empty(#[primary_span] Span), + #[multipart_suggestion(hir_typeck_suggestion, style = "short")] + Snippet { + #[suggestion_part(code = "drop(")] + lo: Span, + #[suggestion_part(code = ")")] + hi: Span, + }, +} + #[derive(Diagnostic)] #[diag(hir_typeck_missing_parentheses_in_range, code = "E0689")] pub struct MissingParenthesesInRange { diff --git a/tests/ui/error-codes/E0040.stderr b/tests/ui/error-codes/E0040.stderr index 9fcda1a9385..839be79d28d 100644 --- a/tests/ui/error-codes/E0040.stderr +++ b/tests/ui/error-codes/E0040.stderr @@ -2,10 +2,12 @@ error[E0040]: explicit use of destructor method --> $DIR/E0040.rs:16:7 | LL | x.drop(); - | --^^^^-- - | | | - | | explicit destructor calls not allowed - | help: consider using `drop` function: `drop(x)` + | ^^^^ explicit destructor calls not allowed + | +help: consider using `drop` function + | +LL | drop(x); + | +++++ ~ error: aborting due to previous error diff --git a/tests/ui/explicit/explicit-call-to-dtor.stderr b/tests/ui/explicit/explicit-call-to-dtor.stderr index f3c9bf6cccd..f2e0b73b6c5 100644 --- a/tests/ui/explicit/explicit-call-to-dtor.stderr +++ b/tests/ui/explicit/explicit-call-to-dtor.stderr @@ -2,10 +2,12 @@ error[E0040]: explicit use of destructor method --> $DIR/explicit-call-to-dtor.rs:15:7 | LL | x.drop(); - | --^^^^-- - | | | - | | explicit destructor calls not allowed - | help: consider using `drop` function: `drop(x)` + | ^^^^ explicit destructor calls not allowed + | +help: consider using `drop` function + | +LL | drop(x); + | +++++ ~ error: aborting due to previous error diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr b/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr index c7067117349..5fa42fcf191 100644 --- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr +++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr @@ -2,10 +2,12 @@ error[E0040]: explicit use of destructor method --> $DIR/explicit-call-to-supertrait-dtor.rs:22:14 | LL | self.drop(); - | -----^^^^-- - | | | - | | explicit destructor calls not allowed - | help: consider using `drop` function: `drop(self)` + | ^^^^ explicit destructor calls not allowed + | +help: consider using `drop` function + | +LL | drop(self); + | +++++ ~ error: aborting due to previous error