From 078441ce9b1de761d31802d3975d21688c58e717 Mon Sep 17 00:00:00 2001 From: surechen Date: Sat, 25 May 2024 11:44:14 +0800 Subject: [PATCH] Let lint_forgetting_references give the suggestion if possible --- compiler/rustc_lint/messages.ftl | 1 + .../rustc_lint/src/drop_forget_useless.rs | 10 +- compiler/rustc_lint/src/lints.rs | 9 +- tests/ui/lint/forgetting_copy_types.stderr | 30 +++- .../forgetting_references-can-fixed.fixed | 40 ++++++ .../lint/forgetting_references-can-fixed.rs | 40 ++++++ .../forgetting_references-can-fixed.stderr | 133 ++++++++++++++++++ tests/ui/lint/forgetting_references.rs | 10 ++ tests/ui/lint/forgetting_references.stderr | 88 ++++++++++-- 9 files changed, 336 insertions(+), 25 deletions(-) create mode 100644 tests/ui/lint/forgetting_references-can-fixed.fixed create mode 100644 tests/ui/lint/forgetting_references-can-fixed.rs create mode 100644 tests/ui/lint/forgetting_references-can-fixed.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 32bfaba63e8af..408781f2eea03 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -230,6 +230,7 @@ lint_forgetting_copy_types = calls to `std::mem::forget` with a value that imple lint_forgetting_references = calls to `std::mem::forget` with a reference instead of an owned value does nothing .label = argument has type `{$arg_ty}` .note = use `let _ = ...` to ignore the expression or result + .suggestion = use `let _ = ...` to ignore the expression or result lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label} .label = this {$label} contains {$count -> diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs index 7378545426610..dc30916065268 100644 --- a/compiler/rustc_lint/src/drop_forget_useless.rs +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -4,8 +4,8 @@ use rustc_span::sym; use crate::{ lints::{ - DropCopyDiag, DropRefDiag, ForgetCopyDiag, ForgetRefDiag, IgnoreDropSuggestion, - UndroppedManuallyDropsDiag, UndroppedManuallyDropsSuggestion, + DropCopyDiag, DropRefDiag, ForgetCopyDiag, ForgetRefDiag, UndroppedManuallyDropsDiag, + UndroppedManuallyDropsSuggestion, UseLetUnderscoreIgnoreSuggestion, }, LateContext, LateLintPass, LintContext, }; @@ -152,12 +152,12 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { && let StmtKind::Semi(e) = stmt.kind && e.hir_id == expr.hir_id { - IgnoreDropSuggestion::Suggestion { + UseLetUnderscoreIgnoreSuggestion::Suggestion { start_span: expr.span.shrink_to_lo().until(arg.span), end_span: arg.span.shrink_to_hi().until(expr.span.shrink_to_hi()), } } else { - IgnoreDropSuggestion::Note + UseLetUnderscoreIgnoreSuggestion::Note }; match fn_name { sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => { @@ -171,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { cx.emit_span_lint( FORGETTING_REFERENCES, expr.span, - ForgetRefDiag { arg_ty, label: arg.span }, + ForgetRefDiag { arg_ty, label: arg.span, sugg }, ); } sym::mem_drop if is_copy && !drop_is_single_call_in_arm => { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 41d0c109f8cfe..13b6075ccaf49 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -658,7 +658,7 @@ pub struct ForLoopsOverFalliblesSuggestion<'a> { } #[derive(Subdiagnostic)] -pub enum IgnoreDropSuggestion { +pub enum UseLetUnderscoreIgnoreSuggestion { #[note(lint_note)] Note, #[multipart_suggestion(lint_suggestion, style = "verbose", applicability = "maybe-incorrect")] @@ -678,7 +678,7 @@ pub struct DropRefDiag<'a> { #[label] pub label: Span, #[subdiagnostic] - pub sugg: IgnoreDropSuggestion, + pub sugg: UseLetUnderscoreIgnoreSuggestion, } #[derive(LintDiagnostic)] @@ -692,11 +692,12 @@ pub struct DropCopyDiag<'a> { #[derive(LintDiagnostic)] #[diag(lint_forgetting_references)] -#[note] pub struct ForgetRefDiag<'a> { pub arg_ty: Ty<'a>, #[label] pub label: Span, + #[subdiagnostic] + pub sugg: UseLetUnderscoreIgnoreSuggestion, } #[derive(LintDiagnostic)] @@ -706,7 +707,7 @@ pub struct ForgetCopyDiag<'a> { #[label] pub label: Span, #[subdiagnostic] - pub sugg: IgnoreDropSuggestion, + pub sugg: UseLetUnderscoreIgnoreSuggestion, } #[derive(LintDiagnostic)] diff --git a/tests/ui/lint/forgetting_copy_types.stderr b/tests/ui/lint/forgetting_copy_types.stderr index a2b07351d7904..980ee6caba254 100644 --- a/tests/ui/lint/forgetting_copy_types.stderr +++ b/tests/ui/lint/forgetting_copy_types.stderr @@ -39,8 +39,12 @@ LL | forget(s3); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result = note: `#[warn(forgetting_references)]` on by default +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(s3); +LL + let _ = s3; + | warning: calls to `std::mem::forget` with a value that implements `Copy` does nothing --> $DIR/forgetting_copy_types.rs:37:5 @@ -64,7 +68,11 @@ LL | forget(s5); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(s5); +LL + let _ = s5; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_copy_types.rs:50:5 @@ -74,7 +82,11 @@ LL | forget(a2); | | | argument has type `&AnotherStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(a2); +LL + let _ = a2; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_copy_types.rs:52:5 @@ -84,7 +96,11 @@ LL | forget(a3); | | | argument has type `&AnotherStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(a3); +LL + let _ = a3; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_copy_types.rs:53:5 @@ -94,7 +110,11 @@ LL | forget(a4); | | | argument has type `&AnotherStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(a4); +LL + let _ = a4; + | warning: 8 warnings emitted diff --git a/tests/ui/lint/forgetting_references-can-fixed.fixed b/tests/ui/lint/forgetting_references-can-fixed.fixed new file mode 100644 index 0000000000000..64475f042840a --- /dev/null +++ b/tests/ui/lint/forgetting_references-can-fixed.fixed @@ -0,0 +1,40 @@ +//@ check-fail +//@ run-rustfix + +#![deny(forgetting_references)] + +use std::mem::forget; + +struct SomeStruct; + +fn main() { + let _ = &SomeStruct; //~ ERROR calls to `std::mem::forget` + + let mut owned = SomeStruct; + let _ = &owned; //~ ERROR calls to `std::mem::forget` + let _ = &&owned; //~ ERROR calls to `std::mem::forget` + let _ = &mut owned; //~ ERROR calls to `std::mem::forget` + forget(owned); + + let reference1 = &SomeStruct; + let _ = &*reference1; //~ ERROR calls to `std::mem::forget` + + let reference2 = &mut SomeStruct; + let _ = reference2; //~ ERROR calls to `std::mem::forget` + + let ref reference3 = SomeStruct; + let _ = reference3; //~ ERROR calls to `std::mem::forget` +} + +#[allow(dead_code)] +fn test_generic_fn_forget(val: T) { + let _ = &val; //~ ERROR calls to `std::mem::forget` + forget(val); +} + +#[allow(dead_code)] +fn test_similarly_named_function() { + fn forget(_val: T) {} + forget(&SomeStruct); //OK; call to unrelated function which happens to have the same name + let _ = &SomeStruct; //~ ERROR calls to `std::mem::forget` +} diff --git a/tests/ui/lint/forgetting_references-can-fixed.rs b/tests/ui/lint/forgetting_references-can-fixed.rs new file mode 100644 index 0000000000000..4c9ef541d3418 --- /dev/null +++ b/tests/ui/lint/forgetting_references-can-fixed.rs @@ -0,0 +1,40 @@ +//@ check-fail +//@ run-rustfix + +#![deny(forgetting_references)] + +use std::mem::forget; + +struct SomeStruct; + +fn main() { + forget(&SomeStruct); //~ ERROR calls to `std::mem::forget` + + let mut owned = SomeStruct; + forget(&owned); //~ ERROR calls to `std::mem::forget` + forget(&&owned); //~ ERROR calls to `std::mem::forget` + forget(&mut owned); //~ ERROR calls to `std::mem::forget` + forget(owned); + + let reference1 = &SomeStruct; + forget(&*reference1); //~ ERROR calls to `std::mem::forget` + + let reference2 = &mut SomeStruct; + forget(reference2); //~ ERROR calls to `std::mem::forget` + + let ref reference3 = SomeStruct; + forget(reference3); //~ ERROR calls to `std::mem::forget` +} + +#[allow(dead_code)] +fn test_generic_fn_forget(val: T) { + forget(&val); //~ ERROR calls to `std::mem::forget` + forget(val); +} + +#[allow(dead_code)] +fn test_similarly_named_function() { + fn forget(_val: T) {} + forget(&SomeStruct); //OK; call to unrelated function which happens to have the same name + std::mem::forget(&SomeStruct); //~ ERROR calls to `std::mem::forget` +} diff --git a/tests/ui/lint/forgetting_references-can-fixed.stderr b/tests/ui/lint/forgetting_references-can-fixed.stderr new file mode 100644 index 0000000000000..05eb636ab4595 --- /dev/null +++ b/tests/ui/lint/forgetting_references-can-fixed.stderr @@ -0,0 +1,133 @@ +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:11:5 + | +LL | forget(&SomeStruct); + | ^^^^^^^-----------^ + | | + | argument has type `&SomeStruct` + | +note: the lint level is defined here + --> $DIR/forgetting_references-can-fixed.rs:4:9 + | +LL | #![deny(forgetting_references)] + | ^^^^^^^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&SomeStruct); +LL + let _ = &SomeStruct; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:14:5 + | +LL | forget(&owned); + | ^^^^^^^------^ + | | + | argument has type `&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&owned); +LL + let _ = &owned; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:15:5 + | +LL | forget(&&owned); + | ^^^^^^^-------^ + | | + | argument has type `&&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&&owned); +LL + let _ = &&owned; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:16:5 + | +LL | forget(&mut owned); + | ^^^^^^^----------^ + | | + | argument has type `&mut SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&mut owned); +LL + let _ = &mut owned; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:20:5 + | +LL | forget(&*reference1); + | ^^^^^^^------------^ + | | + | argument has type `&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&*reference1); +LL + let _ = &*reference1; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:23:5 + | +LL | forget(reference2); + | ^^^^^^^----------^ + | | + | argument has type `&mut SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(reference2); +LL + let _ = reference2; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:26:5 + | +LL | forget(reference3); + | ^^^^^^^----------^ + | | + | argument has type `&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(reference3); +LL + let _ = reference3; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:31:5 + | +LL | forget(&val); + | ^^^^^^^----^ + | | + | argument has type `&T` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&val); +LL + let _ = &val; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:39:5 + | +LL | std::mem::forget(&SomeStruct); + | ^^^^^^^^^^^^^^^^^-----------^ + | | + | argument has type `&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - std::mem::forget(&SomeStruct); +LL + let _ = &SomeStruct; + | + +error: aborting due to 9 previous errors + diff --git a/tests/ui/lint/forgetting_references.rs b/tests/ui/lint/forgetting_references.rs index ecfa23ee49705..d0ec2a77ab1ca 100644 --- a/tests/ui/lint/forgetting_references.rs +++ b/tests/ui/lint/forgetting_references.rs @@ -23,6 +23,16 @@ fn main() { let ref reference3 = SomeStruct; forget(reference3); //~ WARN calls to `std::mem::forget` + + let ref reference4 = SomeStruct; + + let a = 1; + match a { + 1 => forget(&*reference1), //~ WARN calls to `std::mem::forget` + 2 => forget(reference3), //~ WARN calls to `std::mem::forget` + 3 => forget(reference4), //~ WARN calls to `std::mem::forget` + _ => {} + } } #[allow(dead_code)] diff --git a/tests/ui/lint/forgetting_references.stderr b/tests/ui/lint/forgetting_references.stderr index 5624b690789f8..afd5030a6805b 100644 --- a/tests/ui/lint/forgetting_references.stderr +++ b/tests/ui/lint/forgetting_references.stderr @@ -6,12 +6,16 @@ LL | forget(&SomeStruct); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result note: the lint level is defined here --> $DIR/forgetting_references.rs:3:9 | LL | #![warn(forgetting_references)] | ^^^^^^^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&SomeStruct); +LL + let _ = &SomeStruct; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_references.rs:13:5 @@ -21,7 +25,11 @@ LL | forget(&owned); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&owned); +LL + let _ = &owned; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_references.rs:14:5 @@ -31,7 +39,11 @@ LL | forget(&&owned); | | | argument has type `&&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&&owned); +LL + let _ = &&owned; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_references.rs:15:5 @@ -41,7 +53,11 @@ LL | forget(&mut owned); | | | argument has type `&mut SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&mut owned); +LL + let _ = &mut owned; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_references.rs:19:5 @@ -51,7 +67,11 @@ LL | forget(&*reference1); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&*reference1); +LL + let _ = &*reference1; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_references.rs:22:5 @@ -61,7 +81,11 @@ LL | forget(reference2); | | | argument has type `&mut SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(reference2); +LL + let _ = reference2; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_references.rs:25:5 @@ -71,27 +95,69 @@ LL | forget(reference3); | | | argument has type `&SomeStruct` | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(reference3); +LL + let _ = reference3; + | + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:31:14 + | +LL | 1 => forget(&*reference1), + | ^^^^^^^------------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:32:14 + | +LL | 2 => forget(reference3), + | ^^^^^^^----------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:33:14 + | +LL | 3 => forget(reference4), + | ^^^^^^^----------^ + | | + | argument has type `&SomeStruct` + | = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forgetting_references.rs:30:5 + --> $DIR/forgetting_references.rs:40:5 | LL | forget(&val); | ^^^^^^^----^ | | | argument has type `&T` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&val); +LL + let _ = &val; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forgetting_references.rs:38:5 + --> $DIR/forgetting_references.rs:48:5 | LL | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^-----------^ | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - std::mem::forget(&SomeStruct); +LL + let _ = &SomeStruct; + | -warning: 9 warnings emitted +warning: 12 warnings emitted