1- use clippy_utils:: diagnostics:: span_lint_and_note;
2- use clippy_utils:: ty :: is_copy ;
3- use if_chain :: if_chain ;
4- use rustc_hir:: { Expr , ExprKind } ;
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 } ;
55use rustc_lint:: { LateContext , LateLintPass } ;
6- use rustc_middle:: ty;
76use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
87use rustc_span:: sym;
98
@@ -103,6 +102,75 @@ declare_clippy_lint! {
103102 "calls to `std::mem::forget` with a value that implements Copy"
104103}
105104
105+ declare_clippy_lint ! {
106+ /// ### What it does
107+ /// Checks for calls to `std::mem::drop` with a value that does not implement `Drop`.
108+ ///
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.
112+ ///
113+ /// ### Example
114+ /// ```rust
115+ /// struct Foo;
116+ /// let x = Foo;
117+ /// std::mem::drop(x);
118+ /// ```
119+ #[ clippy:: version = "1.61.0" ]
120+ pub DROP_NON_DROP ,
121+ suspicious,
122+ "call to `std::mem::drop` with a value which does not implement `Drop`"
123+ }
124+
125+ declare_clippy_lint ! {
126+ /// ### What it does
127+ /// Checks for calls to `std::mem::forget` with a value that does not implement `Drop`.
128+ ///
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.
132+ ///
133+ /// ### Example
134+ /// ```rust
135+ /// struct Foo;
136+ /// let x = Foo;
137+ /// std::mem::forget(x);
138+ /// ```
139+ #[ clippy:: version = "1.61.0" ]
140+ pub FORGET_NON_DROP ,
141+ suspicious,
142+ "call to `std::mem::forget` with a value which does not implement `Drop`"
143+ }
144+
145+ declare_clippy_lint ! {
146+ /// ### What it does
147+ /// Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`.
148+ ///
149+ /// ### Why is this bad?
150+ /// The safe `drop` function does not drop the inner value of a `ManuallyDrop`.
151+ ///
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.
155+ ///
156+ /// ### Example
157+ /// ```rust
158+ /// struct S;
159+ /// drop(std::mem::ManuallyDrop::new(S));
160+ /// ```
161+ /// Use instead:
162+ /// ```rust
163+ /// struct S;
164+ /// unsafe {
165+ /// std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S));
166+ /// }
167+ /// ```
168+ #[ clippy:: version = "1.49.0" ]
169+ pub UNDROPPED_MANUALLY_DROPS ,
170+ correctness,
171+ "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value"
172+ }
173+
106174const DROP_REF_SUMMARY : & str = "calls to `std::mem::drop` with a reference instead of an owned value. \
107175 Dropping a reference does nothing";
108176const FORGET_REF_SUMMARY : & str = "calls to `std::mem::forget` with a reference instead of an owned value. \
@@ -111,60 +179,65 @@ const DROP_COPY_SUMMARY: &str = "calls to `std::mem::drop` with a value that imp
111179 Dropping a copy leaves the original intact";
112180const FORGET_COPY_SUMMARY : & str = "calls to `std::mem::forget` with a value that implements `Copy`. \
113181 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 it's 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";
114186
115- declare_lint_pass ! ( DropForgetRef => [ DROP_REF , FORGET_REF , DROP_COPY , FORGET_COPY ] ) ;
187+ declare_lint_pass ! ( DropForgetRef => [
188+ DROP_REF ,
189+ FORGET_REF ,
190+ DROP_COPY ,
191+ FORGET_COPY ,
192+ DROP_NON_DROP ,
193+ FORGET_NON_DROP ,
194+ UNDROPPED_MANUALLY_DROPS
195+ ] ) ;
116196
117197impl < ' tcx > LateLintPass < ' tcx > for DropForgetRef {
118198 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
119- if_chain ! {
120- if let ExprKind :: Call ( path, args) = expr. kind;
121- if let ExprKind :: Path ( ref qpath) = path. kind;
122- if args. len( ) == 1 ;
123- if let Some ( def_id) = cx. qpath_res( qpath, path. hir_id) . opt_def_id( ) ;
124- then {
125- let lint;
126- let msg;
127- let arg = & args[ 0 ] ;
128- let arg_ty = cx. typeck_results( ) . expr_ty( arg) ;
129-
130- if let ty:: Ref ( ..) = arg_ty. kind( ) {
131- match cx. tcx. get_diagnostic_name( def_id) {
132- Some ( sym:: mem_drop) => {
133- lint = DROP_REF ;
134- msg = DROP_REF_SUMMARY . to_string( ) ;
135- } ,
136- Some ( sym:: mem_forget) => {
137- lint = FORGET_REF ;
138- msg = FORGET_REF_SUMMARY . to_string( ) ;
139- } ,
140- _ => return ,
141- }
142- span_lint_and_note( cx,
143- lint,
144- expr. span,
145- & msg,
146- Some ( arg. span) ,
147- & format!( "argument has type `{}`" , arg_ty) ) ;
148- } else if is_copy( cx, arg_ty) {
149- match cx. tcx. get_diagnostic_name( def_id) {
150- Some ( sym:: mem_drop) => {
151- lint = DROP_COPY ;
152- msg = DROP_COPY_SUMMARY . to_string( ) ;
153- } ,
154- Some ( sym:: mem_forget) => {
155- lint = FORGET_COPY ;
156- msg = FORGET_COPY_SUMMARY . to_string( ) ;
157- } ,
158- _ => return ,
159- }
160- span_lint_and_note( cx,
161- lint,
162- expr. span,
163- & msg,
164- Some ( arg. span) ,
165- & format!( "argument has type {}" , arg_ty) ) ;
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)
203+ {
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 ) => {
211+ span_lint_and_help (
212+ cx,
213+ UNDROPPED_MANUALLY_DROPS ,
214+ expr. span ,
215+ "the inner value of this ManuallyDrop will not be dropped" ,
216+ None ,
217+ "to drop a `ManuallyDrop<T>`, use std::mem::ManuallyDrop::drop" ,
218+ ) ;
219+ return ;
166220 }
167- }
221+ sym:: mem_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) ) =>
225+ {
226+ ( DROP_NON_DROP , DROP_NON_DROP_SUMMARY )
227+ } ,
228+ sym:: mem_forget if !arg_ty. needs_drop ( cx. tcx , cx. param_env ) => {
229+ ( FORGET_NON_DROP , FORGET_NON_DROP_SUMMARY )
230+ } ,
231+ _ => return ,
232+ } ;
233+ span_lint_and_note (
234+ cx,
235+ lint,
236+ expr. span ,
237+ msg,
238+ Some ( arg. span ) ,
239+ & format ! ( "argument has type `{}`" , arg_ty) ,
240+ ) ;
168241 }
169242 }
170243}
0 commit comments