1 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
2 use clippy_utils::is_must_use_func_call;
3 use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item};
4 use rustc_hir::{Expr, ExprKind, LangItem};
5 use rustc_lint::{LateContext, LateLintPass};
6 use rustc_session::{declare_lint_pass, declare_tool_lint};
11 /// Checks for calls to `std::mem::drop` with a reference
12 /// instead of an owned value.
14 /// ### Why is this bad?
15 /// Calling `drop` on a reference will only drop the
16 /// reference itself, which is a no-op. It will not call the `drop` method (from
17 /// the `Drop` trait implementation) on the underlying referenced value, which
18 /// is likely what was intended.
22 /// let mut lock_guard = mutex.lock();
23 /// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex
25 /// operation_that_requires_mutex_to_be_unlocked();
27 #[clippy::version = "pre 1.29.0"]
30 "calls to `std::mem::drop` with a reference instead of an owned value"
33 declare_clippy_lint! {
35 /// Checks for calls to `std::mem::forget` with a reference
36 /// instead of an owned value.
38 /// ### Why is this bad?
39 /// Calling `forget` on a reference will only forget the
40 /// reference itself, which is a no-op. It will not forget the underlying
42 /// value, which is likely what was intended.
46 /// let x = Box::new(1);
47 /// std::mem::forget(&x) // Should have been forget(x), x will still be dropped
49 #[clippy::version = "pre 1.29.0"]
52 "calls to `std::mem::forget` with a reference instead of an owned value"
55 declare_clippy_lint! {
57 /// Checks for calls to `std::mem::drop` with a value
58 /// that derives the Copy trait
60 /// ### Why is this bad?
61 /// Calling `std::mem::drop` [does nothing for types that
62 /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the
63 /// value will be copied and moved into the function on invocation.
67 /// let x: i32 = 42; // i32 implements Copy
68 /// std::mem::drop(x) // A copy of x is passed to the function, leaving the
69 /// // original unaffected
71 #[clippy::version = "pre 1.29.0"]
74 "calls to `std::mem::drop` with a value that implements Copy"
77 declare_clippy_lint! {
79 /// Checks for calls to `std::mem::forget` with a value that
80 /// derives the Copy trait
82 /// ### Why is this bad?
83 /// Calling `std::mem::forget` [does nothing for types that
84 /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the
85 /// value will be copied and moved into the function on invocation.
87 /// An alternative, but also valid, explanation is that Copy types do not
89 /// the Drop trait, which means they have no destructors. Without a destructor,
91 /// is nothing for `std::mem::forget` to ignore.
95 /// let x: i32 = 42; // i32 implements Copy
96 /// std::mem::forget(x) // A copy of x is passed to the function, leaving the
97 /// // original unaffected
99 #[clippy::version = "pre 1.29.0"]
102 "calls to `std::mem::forget` with a value that implements Copy"
105 declare_clippy_lint! {
107 /// Checks for calls to `std::mem::drop` with a value that does not implement `Drop`.
109 /// ### Why is this bad?
110 /// Calling `std::mem::drop` is no different than dropping such a type. A different value may
111 /// have been intended.
117 /// std::mem::drop(x);
119 #[clippy::version = "1.62.0"]
122 "call to `std::mem::drop` with a value which does not implement `Drop`"
125 declare_clippy_lint! {
127 /// Checks for calls to `std::mem::forget` with a value that does not implement `Drop`.
129 /// ### Why is this bad?
130 /// Calling `std::mem::forget` is no different than dropping such a type. A different value may
131 /// have been intended.
137 /// std::mem::forget(x);
139 #[clippy::version = "1.62.0"]
142 "call to `std::mem::forget` with a value which does not implement `Drop`"
145 declare_clippy_lint! {
147 /// Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`.
149 /// ### Why is this bad?
150 /// The safe `drop` function does not drop the inner value of a `ManuallyDrop`.
152 /// ### Known problems
153 /// Does not catch cases if the user binds `std::mem::drop`
154 /// to a different name and calls it that way.
159 /// drop(std::mem::ManuallyDrop::new(S));
165 /// std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S));
168 #[clippy::version = "1.49.0"]
169 pub UNDROPPED_MANUALLY_DROPS,
171 "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value"
174 const DROP_REF_SUMMARY: &str = "calls to `std::mem::drop` with a reference instead of an owned value. \
175 Dropping a reference does nothing";
176 const FORGET_REF_SUMMARY: &str = "calls to `std::mem::forget` with a reference instead of an owned value. \
177 Forgetting a reference does nothing";
178 const DROP_COPY_SUMMARY: &str = "calls to `std::mem::drop` with a value that implements `Copy`. \
179 Dropping a copy leaves the original intact";
180 const FORGET_COPY_SUMMARY: &str = "calls to `std::mem::forget` with a value that implements `Copy`. \
181 Forgetting a copy leaves the original intact";
182 const DROP_NON_DROP_SUMMARY: &str = "call to `std::mem::drop` with a value that does not implement `Drop`. \
183 Dropping such a type only extends its contained lifetimes";
184 const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value that does not implement `Drop`. \
185 Forgetting such a type is the same as dropping it";
187 declare_lint_pass!(DropForgetRef => [
194 UNDROPPED_MANUALLY_DROPS
197 impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
198 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
199 if let ExprKind::Call(path, [arg]) = expr.kind
200 && let ExprKind::Path(ref qpath) = path.kind
201 && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
202 && let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id)
204 let arg_ty = cx.typeck_results().expr_ty(arg);
205 let (lint, msg) = match fn_name {
206 sym::mem_drop if arg_ty.is_ref() => (DROP_REF, DROP_REF_SUMMARY),
207 sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY),
208 sym::mem_drop if is_copy(cx, arg_ty) => (DROP_COPY, DROP_COPY_SUMMARY),
209 sym::mem_forget if is_copy(cx, arg_ty) => (FORGET_COPY, FORGET_COPY_SUMMARY),
210 sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => {
213 UNDROPPED_MANUALLY_DROPS,
215 "the inner value of this ManuallyDrop will not be dropped",
217 "to drop a `ManuallyDrop<T>`, use std::mem::ManuallyDrop::drop",
222 if !(arg_ty.needs_drop(cx.tcx, cx.param_env)
223 || is_must_use_func_call(cx, arg)
224 || is_must_use_ty(cx, arg_ty)) =>
226 (DROP_NON_DROP, DROP_NON_DROP_SUMMARY)
228 sym::mem_forget if !arg_ty.needs_drop(cx.tcx, cx.param_env) => {
229 (FORGET_NON_DROP, FORGET_NON_DROP_SUMMARY)
239 &format!("argument has type `{}`", arg_ty),