diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 98fe3821947..51eb8210d46 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -492,6 +492,10 @@ lint_tykind = usage of `ty::TyKind` lint_tykind_kind = usage of `ty::TyKind::` .suggestion = try using `ty::` directly +lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::ManuallyDrop` instead of the inner value does nothing + .label = argument has type `{$arg_ty}` + .suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value + lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op .label = this function will not propagate the caller location diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs index ed2b384805e..4cea6169dc3 100644 --- a/compiler/rustc_lint/src/drop_forget_useless.rs +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -1,8 +1,12 @@ use rustc_hir::{Arm, Expr, ExprKind, Node}; +use rustc_middle::ty; use rustc_span::sym; use crate::{ - lints::{DropCopyDiag, DropRefDiag, ForgetCopyDiag, ForgetRefDiag}, + lints::{ + DropCopyDiag, DropRefDiag, ForgetCopyDiag, ForgetRefDiag, UndroppedManuallyDropsDiag, + UndroppedManuallyDropsSuggestion, + }, LateContext, LateLintPass, LintContext, }; @@ -109,7 +113,29 @@ declare_lint! { "calls to `std::mem::forget` with a value that implements Copy" } -declare_lint_pass!(DropForgetUseless => [DROPPING_REFERENCES, FORGETTING_REFERENCES, DROPPING_COPY_TYPES, FORGETTING_COPY_TYPES]); +declare_lint! { + /// The `undropped_manually_drops` lint check for calls to `std::mem::drop` with + /// a value of `std::mem::ManuallyDrop` which doesn't drop. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// struct S; + /// drop(std::mem::ManuallyDrop::new(S)); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `ManuallyDrop` does not drop it's inner value so calling `std::mem::drop` will + /// not drop the inner value of the `ManuallyDrop` either. + pub UNDROPPED_MANUALLY_DROPS, + Deny, + "calls to `std::mem::drop` with `std::mem::ManuallyDrop` instead of it's inner value" +} + +declare_lint_pass!(DropForgetUseless => [DROPPING_REFERENCES, FORGETTING_REFERENCES, DROPPING_COPY_TYPES, FORGETTING_COPY_TYPES, UNDROPPED_MANUALLY_DROPS]); impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { @@ -134,6 +160,20 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { sym::mem_forget if is_copy => { cx.emit_spanned_lint(FORGETTING_COPY_TYPES, expr.span, ForgetCopyDiag { arg_ty, label: arg.span }); } + sym::mem_drop if let ty::Adt(adt, _) = arg_ty.kind() && adt.is_manually_drop() => { + cx.emit_spanned_lint( + UNDROPPED_MANUALLY_DROPS, + expr.span, + UndroppedManuallyDropsDiag { + arg_ty, + label: arg.span, + suggestion: UndroppedManuallyDropsSuggestion { + start_span: arg.span.shrink_to_lo(), + end_span: arg.span.shrink_to_hi() + } + } + ); + } _ => return, }; } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index fd15f795202..03dbffcc2c4 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -699,6 +699,25 @@ pub struct ForgetCopyDiag<'a> { pub label: Span, } +#[derive(LintDiagnostic)] +#[diag(lint_undropped_manually_drops)] +pub struct UndroppedManuallyDropsDiag<'a> { + pub arg_ty: Ty<'a>, + #[label] + pub label: Span, + #[subdiagnostic] + pub suggestion: UndroppedManuallyDropsSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")] +pub struct UndroppedManuallyDropsSuggestion { + #[suggestion_part(code = "std::mem::ManuallyDrop::into_inner(")] + pub start_span: Span, + #[suggestion_part(code = ")")] + pub end_span: Span, +} + // invalid_from_utf8.rs #[derive(LintDiagnostic)] pub enum InvalidFromUtf8Diag { diff --git a/tests/ui/lint/undropped_manually_drops.rs b/tests/ui/lint/undropped_manually_drops.rs new file mode 100644 index 00000000000..7286121a404 --- /dev/null +++ b/tests/ui/lint/undropped_manually_drops.rs @@ -0,0 +1,19 @@ +// check-fail + +struct S; + +fn main() { + let mut manual1 = std::mem::ManuallyDrop::new(S); + let mut manual2 = std::mem::ManuallyDrop::new(S); + let mut manual3 = std::mem::ManuallyDrop::new(S); + + drop(std::mem::ManuallyDrop::new(S)); //~ ERROR calls to `std::mem::drop` + drop(manual1); //~ ERROR calls to `std::mem::drop` + drop({ manual3 }); //~ ERROR calls to `std::mem::drop` + + // These lines will drop `S` and should be okay. + unsafe { + std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S)); + std::mem::ManuallyDrop::drop(&mut manual2); + } +} diff --git a/tests/ui/lint/undropped_manually_drops.stderr b/tests/ui/lint/undropped_manually_drops.stderr new file mode 100644 index 00000000000..156b647ebd3 --- /dev/null +++ b/tests/ui/lint/undropped_manually_drops.stderr @@ -0,0 +1,42 @@ +error: calls to `std::mem::drop` with `std::mem::ManuallyDrop` instead of the inner value does nothing + --> $DIR/undropped_manually_drops.rs:10:5 + | +LL | drop(std::mem::ManuallyDrop::new(S)); + | ^^^^^------------------------------^ + | | + | argument has type `ManuallyDrop` + | + = note: `#[deny(undropped_manually_drops)]` on by default +help: use `std::mem::ManuallyDrop::into_inner` to get the inner value + | +LL | drop(std::mem::ManuallyDrop::into_inner(std::mem::ManuallyDrop::new(S))); + | +++++++++++++++++++++++++++++++++++ + + +error: calls to `std::mem::drop` with `std::mem::ManuallyDrop` instead of the inner value does nothing + --> $DIR/undropped_manually_drops.rs:11:5 + | +LL | drop(manual1); + | ^^^^^-------^ + | | + | argument has type `ManuallyDrop` + | +help: use `std::mem::ManuallyDrop::into_inner` to get the inner value + | +LL | drop(std::mem::ManuallyDrop::into_inner(manual1)); + | +++++++++++++++++++++++++++++++++++ + + +error: calls to `std::mem::drop` with `std::mem::ManuallyDrop` instead of the inner value does nothing + --> $DIR/undropped_manually_drops.rs:12:5 + | +LL | drop({ manual3 }); + | ^^^^^-----------^ + | | + | argument has type `ManuallyDrop` + | +help: use `std::mem::ManuallyDrop::into_inner` to get the inner value + | +LL | drop(std::mem::ManuallyDrop::into_inner({ manual3 })); + | +++++++++++++++++++++++++++++++++++ + + +error: aborting due to 3 previous errors +