Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions compiler/rustc_lint/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,38 @@ pub(crate) struct DropCopyDiag<'a> {
pub sugg: UseLetUnderscoreIgnoreSuggestion,
}

#[derive(Diagnostic)]
#[diag(
"calls to {$from_fn ->
[true] `std::ptr::drop_in_place`
*[false] `drop_in_place`
} with a pointer to a reference instead of a pointer to an owned value does nothing"
)]
pub(crate) struct DropInPlaceRefDiag<'a> {
pub from_fn: bool,
pub arg_ty: Ty<'a>,
#[label("argument has type `{$arg_ty}`")]
pub label: Span,
#[subdiagnostic]
pub sugg: UseLetUnderscoreIgnoreSuggestion,
}

#[derive(Diagnostic)]
#[diag(
"calls to {$from_fn ->
[true] `std::ptr::drop_in_place`
*[false] `drop_in_place`
} with a pointer to a value that implements `Copy` does nothing"
)]
pub(crate) struct DropInPlaceCopyDiag<'a> {
pub from_fn: bool,
pub arg_ty: Ty<'a>,
#[label("argument has type `{$arg_ty}`")]
pub label: Span,
#[subdiagnostic]
pub sugg: UseLetUnderscoreIgnoreSuggestion,
}

#[derive(Diagnostic)]
#[diag("calls to `std::mem::forget` with a reference instead of an owned value does nothing")]
pub(crate) struct ForgetRefDiag<'a> {
Expand Down Expand Up @@ -1030,6 +1062,30 @@ pub(crate) struct UndroppedManuallyDropsSuggestion {
pub end_span: Span,
}

#[derive(Diagnostic)]
#[diag(
"calls to `drop_in_place` with a pointer to a `std::mem::ManuallyDrop` instead of the inner value does nothing"
)]
pub(crate) struct UndroppedManuallyDropsInPlaceDiag<'a> {
pub arg_ty: Ty<'a>,
#[label("argument has type `{$arg_ty}`")]
pub label: Span,
#[subdiagnostic]
pub suggestion: UndroppedManuallyDropsInPlaceSuggestion,
}

#[derive(Subdiagnostic)]
#[multipart_suggestion(
"use `std::mem::ManuallyDrop::drop` to drop the inner value",
applicability = "maybe-incorrect"
)]
pub(crate) struct UndroppedManuallyDropsInPlaceSuggestion {
#[suggestion_part(code = "std::mem::ManuallyDrop::drop(&mut *")]
pub start_span: Span,
#[suggestion_part(code = ")")]
pub end_span: Span,
}

// invalid_from_utf8.rs
#[derive(Diagnostic)]
pub(crate) enum InvalidFromUtf8Diag {
Expand Down
96 changes: 81 additions & 15 deletions compiler/rustc_lint/src/drop_forget_useless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ use rustc_session::{declare_lint, declare_lint_pass};
use rustc_span::sym;

use crate::diagnostics::{
DropCopyDiag, DropRefDiag, ForgetCopyDiag, ForgetRefDiag, UndroppedManuallyDropsDiag,
UndroppedManuallyDropsSuggestion, UseLetUnderscoreIgnoreSuggestion,
DropCopyDiag, DropInPlaceCopyDiag, DropInPlaceRefDiag, DropRefDiag, ForgetCopyDiag,
ForgetRefDiag, UndroppedManuallyDropsDiag, UndroppedManuallyDropsInPlaceDiag,
UndroppedManuallyDropsInPlaceSuggestion, UndroppedManuallyDropsSuggestion,
UseLetUnderscoreIgnoreSuggestion,
};
use crate::{LateContext, LateLintPass, LintContext};

declare_lint! {
/// The `dropping_references` lint checks for calls to `std::mem::drop` with a reference
/// instead of an owned value.
/// The `dropping_references` lint checks for calls to `std::mem::drop`
/// and `std::ptr::drop_in_place` where the dropped type is a reference instead of
/// an owned value.
///
/// ### Example
///
Expand All @@ -34,7 +37,7 @@ declare_lint! {
/// is likely what was intended.
pub DROPPING_REFERENCES,
Warn,
"calls to `std::mem::drop` with a reference instead of an owned value"
"calls to `drop` and `drop_in_place` where the dropped type is a reference instead of an owned value"
}

declare_lint! {
Expand All @@ -61,8 +64,8 @@ declare_lint! {
}

declare_lint! {
/// The `dropping_copy_types` lint checks for calls to `std::mem::drop` with a value
/// that derives the Copy trait.
/// The `dropping_copy_types` lint checks for calls to `std::mem::drop`
/// and `std::ptr::drop_in_place` where the dropped value implements the `Copy` trait.
///
/// ### Example
///
Expand All @@ -81,7 +84,7 @@ declare_lint! {
/// value will be copied and moved into the function on invocation.
pub DROPPING_COPY_TYPES,
Warn,
"calls to `std::mem::drop` with a value that implements Copy"
"calls to `drop` and `drop_in_place` where the dropped value implements Copy"
}

declare_lint! {
Expand Down Expand Up @@ -113,8 +116,9 @@ declare_lint! {
}

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.
/// The `undropped_manually_drops` lint check for calls to `std::mem::drop`
/// and `std::ptr::drop_in_place` where the dropped value is `std::mem::ManuallyDrop`
/// which doesn't drop.
///
/// ### Example
///
Expand All @@ -131,21 +135,32 @@ declare_lint! {
/// 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"
"calls to `drop` and `drop_in_place` where the dropped value is `std::mem::ManuallyDrop`"
}

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>) {
if let ExprKind::Call(path, [arg]) = expr.kind
&& let ExprKind::Path(ref qpath) = path.kind
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
&& let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id)
let (fn_did, arg) = match expr.kind {
// matching on `function(<receiver>, ...)`
ExprKind::Call(path, [arg]) if let ExprKind::Path(ref qpath) = path.kind => {
(cx.qpath_res(qpath, path.hir_id).opt_def_id(), arg)
}
// matching on `<receiver>.method(..)`
ExprKind::MethodCall(_, arg, _, _) => {
(cx.typeck_results().type_dependent_def_id(expr.hir_id), arg)
}
_ => return,
};

if let Some(fn_did) = fn_did
&& let Some(fn_name) = cx.tcx.get_diagnostic_name(fn_did)
{
let arg_ty = cx.typeck_results().expr_ty(arg);
let is_copy = cx.type_is_copy_modulo_regions(arg_ty);
let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);

let let_underscore_ignore_sugg = || {
if let Some((_, node)) = cx.tcx.hir_parent_iter(expr.hir_id).nth(0)
&& let Node::Stmt(stmt) = node
Expand All @@ -161,6 +176,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless {
UseLetUnderscoreIgnoreSuggestion::Note
}
};

match fn_name {
sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => {
cx.emit_span_lint(
Expand All @@ -169,6 +185,22 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless {
DropRefDiag { arg_ty, label: arg.span, sugg: let_underscore_ignore_sugg() },
);
}
sym::ptr_drop_in_place | sym::ptr_drop_in_place_self
if let &ty::RawPtr(inner_ty, _mutbl) = arg_ty.kind()
&& inner_ty.is_ref()
&& !drop_is_single_call_in_arm =>
{
cx.emit_span_lint(
DROPPING_REFERENCES,
expr.span,
DropInPlaceRefDiag {
arg_ty,
label: arg.span,
sugg: let_underscore_ignore_sugg(),
from_fn: fn_name == sym::ptr_drop_in_place,
},
);
}
sym::mem_forget if arg_ty.is_ref() => {
cx.emit_span_lint(
FORGETTING_REFERENCES,
Expand All @@ -191,6 +223,22 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless {
},
);
}
sym::ptr_drop_in_place | sym::ptr_drop_in_place_self
if let &ty::RawPtr(inner_ty, _mutbl) = arg_ty.kind()
&& cx.type_is_copy_modulo_regions(inner_ty)
&& !drop_is_single_call_in_arm =>
{
cx.emit_span_lint(
DROPPING_COPY_TYPES,
expr.span,
DropInPlaceCopyDiag {
arg_ty,
label: arg.span,
sugg: let_underscore_ignore_sugg(),
from_fn: fn_name == sym::ptr_drop_in_place,
},
);
}
sym::mem_forget if is_copy => {
cx.emit_span_lint(
FORGETTING_COPY_TYPES,
Expand Down Expand Up @@ -219,6 +267,24 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless {
},
);
}
sym::ptr_drop_in_place | sym::ptr_drop_in_place_self
if let &ty::RawPtr(inner_ty, _mutbl) = arg_ty.kind()
&& let ty::Adt(adt, _) = inner_ty.kind()
&& adt.is_manually_drop() =>
{
cx.emit_span_lint(
UNDROPPED_MANUALLY_DROPS,
expr.span,
UndroppedManuallyDropsInPlaceDiag {
arg_ty,
label: arg.span,
suggestion: UndroppedManuallyDropsInPlaceSuggestion {
start_span: expr.span.shrink_to_lo().until(arg.span.shrink_to_lo()),
end_span: arg.span.shrink_to_hi().until(expr.span.shrink_to_hi()),
},
},
);
}
_ => return,
};
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,8 @@ symbols! {
ptr_const_is_null,
ptr_copy,
ptr_copy_nonoverlapping,
ptr_drop_in_place,
ptr_drop_in_place_self,
ptr_from_ref,
ptr_guaranteed_cmp,
ptr_is_null,
Expand Down
1 change: 1 addition & 0 deletions library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,7 @@ impl<T: PointeeSized> *mut T {
/// [`ptr::drop_in_place`]: crate::ptr::drop_in_place()
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")]
#[rustc_diagnostic_item = "ptr_drop_in_place_self"]
#[inline(always)]
pub const unsafe fn drop_in_place(self)
where
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

//@error-in-other-file: /retag .* for Unique permission .* only grants SharedReadOnly permission/

#![allow(dropping_copy_types)]

fn main() {
unsafe {
let x = 0u8;
Expand Down
2 changes: 2 additions & 0 deletions src/tools/miri/tests/pass/drop_in_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// valid when dropped. This test confirms that behavior.
// This is not a stable guarantee!

#![allow(dropping_copy_types)]

use std::ptr;

fn main() {
Expand Down
20 changes: 20 additions & 0 deletions tests/ui/lint/dropping_copy_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,26 @@ fn main() {
drop(a3);
drop(a4); //~ WARN calls to `std::mem::drop`
drop(a5);

unsafe {
let mut s6 = SomeStruct {};
std::ptr::drop_in_place(&raw mut s6); //~ WARN calls to `std::ptr::drop_in_place`

let mut s7 = SomeStruct {};
let ptr = &raw mut s7;
std::ptr::drop_in_place(ptr); //~ WARN calls to `std::ptr::drop_in_place`

std::ptr::drop_in_place(&mut SomeStruct {} as *mut _); //~ WARN calls to `std::ptr::drop_in_place`
}

unsafe {
let mut s8 = SomeStruct {};
(&raw mut s8).drop_in_place(); //~ WARN calls to `drop_in_place`

let mut s9 = SomeStruct {};
let ptr = &raw mut s9;
ptr.drop_in_place(); //~ WARN calls to `drop_in_place`
}
}

#[allow(unused)]
Expand Down
Loading
Loading