From 35d6a2ef2ba71d5ea120c2879825968babcf9a89 Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Sun, 2 Aug 2020 16:30:09 +0200
Subject: [PATCH] Lint path statements to use drop for drop types

---
 src/librustc_lint/unused.rs            | 20 ++++++++++++++++++--
 src/test/ui/warn-path-statement.rs     | 13 ++++++++++++-
 src/test/ui/warn-path-statement.stderr | 16 ++++++++++++++--
 3 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 8d8fb8c3c6098..ee4361ce16b62 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -275,10 +275,26 @@ declare_lint_pass!(PathStatements => [PATH_STATEMENTS]);
 
 impl<'tcx> LateLintPass<'tcx> for PathStatements {
     fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
-        if let hir::StmtKind::Semi(ref expr) = s.kind {
+        if let hir::StmtKind::Semi(expr) = s.kind {
             if let hir::ExprKind::Path(_) = expr.kind {
                 cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| {
-                    lint.build("path statement with no effect").emit()
+                    let ty = cx.typeck_results().expr_ty(expr);
+                    if ty.needs_drop(cx.tcx, cx.param_env) {
+                        let mut lint = lint.build("path statement drops value");
+                        if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
+                            lint.span_suggestion(
+                                s.span,
+                                "use `drop` to clarify the intent",
+                                format!("drop({});", snippet),
+                                Applicability::MachineApplicable,
+                            );
+                        } else {
+                            lint.span_help(s.span, "use `drop` to clarify the intent");
+                        }
+                        lint.emit()
+                    } else {
+                        lint.build("path statement with no effect").emit()
+                    }
                 });
             }
         }
diff --git a/src/test/ui/warn-path-statement.rs b/src/test/ui/warn-path-statement.rs
index e8525f8b892d6..2435be623f310 100644
--- a/src/test/ui/warn-path-statement.rs
+++ b/src/test/ui/warn-path-statement.rs
@@ -1,6 +1,17 @@
 // compile-flags: -D path-statements
-fn main() {
+struct Droppy;
+
+impl Drop for Droppy {
+    fn drop(&mut self) {}
+}
 
+fn main() {
     let x = 10;
     x; //~ ERROR path statement with no effect
+
+    let y = Droppy;
+    y; //~ ERROR path statement drops value
+
+    let z = (Droppy,);
+    z; //~ ERROR path statement drops value
 }
diff --git a/src/test/ui/warn-path-statement.stderr b/src/test/ui/warn-path-statement.stderr
index 30afb99e5f02c..248d2ef299be3 100644
--- a/src/test/ui/warn-path-statement.stderr
+++ b/src/test/ui/warn-path-statement.stderr
@@ -1,10 +1,22 @@
 error: path statement with no effect
-  --> $DIR/warn-path-statement.rs:5:5
+  --> $DIR/warn-path-statement.rs:10:5
    |
 LL |     x;
    |     ^^
    |
    = note: requested on the command line with `-D path-statements`
 
-error: aborting due to previous error
+error: path statement drops value
+  --> $DIR/warn-path-statement.rs:13:5
+   |
+LL |     y;
+   |     ^^ help: use `drop` to clarify the intent: `drop(y);`
+
+error: path statement drops value
+  --> $DIR/warn-path-statement.rs:16:5
+   |
+LL |     z;
+   |     ^^ help: use `drop` to clarify the intent: `drop(z);`
+
+error: aborting due to 3 previous errors