@@ -6,6 +6,7 @@ use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node};
66use rustc_lint:: { LateContext , LateLintPass } ;
77use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
88use rustc_span:: sym;
9+ use std:: borrow:: Cow ;
910
1011declare_clippy_lint ! {
1112 /// ### What it does
@@ -76,6 +77,27 @@ declare_clippy_lint! {
7677 "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value"
7778}
7879
80+ declare_clippy_lint ! {
81+ /// ### What it does
82+ /// Checks for usage of `std::mem::forget(t)` where `t` is
83+ /// `Drop` or has a field that implements `Drop`.
84+ ///
85+ /// ### Why is this bad?
86+ /// `std::mem::forget(t)` prevents `t` from running its
87+ /// destructor, possibly causing leaks.
88+ ///
89+ /// ### Example
90+ /// ```rust
91+ /// # use std::mem;
92+ /// # use std::rc::Rc;
93+ /// mem::forget(Rc::new(55))
94+ /// ```
95+ #[ clippy:: version = "pre 1.29.0" ]
96+ pub MEM_FORGET ,
97+ restriction,
98+ "`mem::forget` usage on `Drop` types, likely to cause memory leaks"
99+ }
100+
79101const DROP_NON_DROP_SUMMARY : & str = "call to `std::mem::drop` with a value that does not implement `Drop`. \
80102 Dropping such a type only extends its contained lifetimes";
81103const FORGET_NON_DROP_SUMMARY : & str = "call to `std::mem::forget` with a value that does not implement `Drop`. \
@@ -84,7 +106,8 @@ const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value t
84106declare_lint_pass ! ( DropForgetRef => [
85107 DROP_NON_DROP ,
86108 FORGET_NON_DROP ,
87- UNDROPPED_MANUALLY_DROPS
109+ UNDROPPED_MANUALLY_DROPS ,
110+ MEM_FORGET ,
88111] ) ;
89112
90113impl < ' tcx > LateLintPass < ' tcx > for DropForgetRef {
@@ -97,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
97120 let arg_ty = cx. typeck_results ( ) . expr_ty ( arg) ;
98121 let is_copy = is_copy ( cx, arg_ty) ;
99122 let drop_is_single_call_in_arm = is_single_call_in_arm ( cx, arg, expr) ;
100- let ( lint, msg) = match fn_name {
123+ let ( lint, msg, note_span ) = match fn_name {
101124 // early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references, forgetting_copy_types
102125 sym:: mem_drop if arg_ty. is_ref ( ) && !drop_is_single_call_in_arm => return ,
103126 sym:: mem_forget if arg_ty. is_ref ( ) => return ,
@@ -121,19 +144,34 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
121144 || drop_is_single_call_in_arm
122145 ) =>
123146 {
124- ( DROP_NON_DROP , DROP_NON_DROP_SUMMARY )
125- } ,
126- sym:: mem_forget if !arg_ty. needs_drop ( cx. tcx , cx. param_env ) => {
127- ( FORGET_NON_DROP , FORGET_NON_DROP_SUMMARY )
147+ ( DROP_NON_DROP , DROP_NON_DROP_SUMMARY . into ( ) , Some ( arg. span ) )
128148 } ,
149+ sym:: mem_forget => {
150+ if arg_ty. needs_drop ( cx. tcx , cx. param_env ) {
151+ (
152+ MEM_FORGET ,
153+ Cow :: Owned ( format ! (
154+ "usage of `mem::forget` on {}" ,
155+ if arg_ty. ty_adt_def( ) . map_or( false , |def| def. has_dtor( cx. tcx) ) {
156+ "`Drop` type"
157+ } else {
158+ "type with `Drop` fields"
159+ }
160+ ) ) ,
161+ None ,
162+ )
163+ } else {
164+ ( FORGET_NON_DROP , FORGET_NON_DROP_SUMMARY . into ( ) , Some ( arg. span ) )
165+ }
166+ }
129167 _ => return ,
130168 } ;
131169 span_lint_and_note (
132170 cx,
133171 lint,
134172 expr. span ,
135- msg,
136- Some ( arg . span ) ,
173+ & msg,
174+ note_span ,
137175 & format ! ( "argument has type `{arg_ty}`" ) ,
138176 ) ;
139177 }
0 commit comments