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 } ;
5
5
use rustc_lint:: { LateContext , LateLintPass } ;
6
- use rustc_middle:: ty;
7
6
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
8
7
use rustc_span:: sym;
9
8
@@ -103,6 +102,75 @@ declare_clippy_lint! {
103
102
"calls to `std::mem::forget` with a value that implements Copy"
104
103
}
105
104
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
+
106
174
const DROP_REF_SUMMARY : & str = "calls to `std::mem::drop` with a reference instead of an owned value. \
107
175
Dropping a reference does nothing";
108
176
const 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
111
179
Dropping a copy leaves the original intact";
112
180
const FORGET_COPY_SUMMARY : & str = "calls to `std::mem::forget` with a value that implements `Copy`. \
113
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 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";
114
186
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
+ ] ) ;
116
196
117
197
impl < ' tcx > LateLintPass < ' tcx > for DropForgetRef {
118
198
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 ;
166
220
}
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
+ ) ;
168
241
}
169
242
}
170
243
}
0 commit comments