about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-10-25 09:37:09 +0000
committerbors <bors@rust-lang.org>2020-10-25 09:37:09 +0000
commit6b01c39e644dbe8b358e6c02a51169aa1fbef561 (patch)
tree7ade4d91a610dfd1e6f2ef5e9b894750993c1e03
parente0e617adaa89c759beccf74bc0f9eafaed44de22 (diff)
parente70817e712fd4d4e930ead0d587031e2b4a97a2e (diff)
downloadrust-6b01c39e644dbe8b358e6c02a51169aa1fbef561.tar.gz
rust-6b01c39e644dbe8b358e6c02a51169aa1fbef561.zip
Auto merge of #6181 - cgm616:undropped-manually-drops, r=flip1995
Add new lint for undropped ManuallyDrop values

Adds a new lint for the following code:

```rust
struct S;

impl Drop for S {
    fn drop(&mut self) {
        println!("drip drop");
    }
}

fn main() {
    // This will not drop the `S`!!!
    drop(std::mem::ManuallyDrop::new(S));
    unsafe {
        // This will.
        std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S));
    }
}
```

The inner value of a `ManuallyDrop` will not be dropped unless the proper, unsafe drop function is called on it. This lint makes sure that a user does not accidently use the wrong function and forget to drop a `ManuallyDrop` value.

Fixes #5581.

---

*Please keep the line below*
changelog: none
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/lib.rs5
-rw-r--r--clippy_lints/src/undropped_manually_drops.rs50
-rw-r--r--src/lintlist/mod.rs7
-rw-r--r--tests/ui/undropped_manually_drops.rs26
-rw-r--r--tests/ui/undropped_manually_drops.stderr19
6 files changed, 108 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a563917332b..1e60bcbb98c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1982,6 +1982,7 @@ Released 2018-09-13
 [`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err
 [`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
 [`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
+[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
 [`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
 [`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
 [`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 1267c5a675e..42948996a35 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -314,6 +314,7 @@ mod transmute;
 mod transmuting_null;
 mod try_err;
 mod types;
+mod undropped_manually_drops;
 mod unicode;
 mod unit_return_expecting_ord;
 mod unnamed_address;
@@ -865,6 +866,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &types::UNIT_CMP,
         &types::UNNECESSARY_CAST,
         &types::VEC_BOX,
+        &undropped_manually_drops::UNDROPPED_MANUALLY_DROPS,
         &unicode::INVISIBLE_CHARACTERS,
         &unicode::NON_ASCII_LITERAL,
         &unicode::UNICODE_NOT_NFC,
@@ -1141,6 +1143,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
     store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
     store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
+    store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
 
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
@@ -1528,6 +1531,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&types::UNIT_CMP),
         LintId::of(&types::UNNECESSARY_CAST),
         LintId::of(&types::VEC_BOX),
+        LintId::of(&undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
         LintId::of(&unicode::INVISIBLE_CHARACTERS),
         LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
         LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
@@ -1800,6 +1804,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
         LintId::of(&types::CAST_REF_TO_MUT),
         LintId::of(&types::UNIT_CMP),
+        LintId::of(&undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
         LintId::of(&unicode::INVISIBLE_CHARACTERS),
         LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
         LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
diff --git a/clippy_lints/src/undropped_manually_drops.rs b/clippy_lints/src/undropped_manually_drops.rs
new file mode 100644
index 00000000000..5443f1601fc
--- /dev/null
+++ b/clippy_lints/src/undropped_manually_drops.rs
@@ -0,0 +1,50 @@
+use crate::utils::{is_type_lang_item, match_function_call, paths, span_lint_and_help};
+use rustc_hir::{lang_items, Expr};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:** Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`.
+    ///
+    /// **Why is this bad?** The safe `drop` function does not drop the inner value of a `ManuallyDrop`.
+    ///
+    /// **Known problems:** Does not catch cases if the user binds `std::mem::drop`
+    /// to a different name and calls it that way.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// struct S;
+    /// drop(std::mem::ManuallyDrop::new(S));
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct S;
+    /// unsafe {
+    ///     std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S));
+    /// }
+    /// ```
+    pub UNDROPPED_MANUALLY_DROPS,
+    correctness,
+    "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value"
+}
+
+declare_lint_pass!(UndroppedManuallyDrops => [UNDROPPED_MANUALLY_DROPS]);
+
+impl LateLintPass<'tcx> for UndroppedManuallyDrops {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let Some(ref args) = match_function_call(cx, expr, &paths::DROP) {
+            let ty = cx.typeck_results().expr_ty(&args[0]);
+            if is_type_lang_item(cx, ty, lang_items::LangItem::ManuallyDrop) {
+                span_lint_and_help(
+                    cx,
+                    UNDROPPED_MANUALLY_DROPS,
+                    expr.span,
+                    "the inner value of this ManuallyDrop will not be dropped",
+                    None,
+                    "to drop a `ManuallyDrop<T>`, use std::mem::ManuallyDrop::drop",
+                );
+            }
+        }
+    }
+}
diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs
index a2e91210320..eee295b5c37 100644
--- a/src/lintlist/mod.rs
+++ b/src/lintlist/mod.rs
@@ -2434,6 +2434,13 @@ vec![
         module: "trait_bounds",
     },
     Lint {
+        name: "undropped_manually_drops",
+        group: "correctness",
+        desc: "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value",
+        deprecation: None,
+        module: "undropped_manually_drops",
+    },
+    Lint {
         name: "unicode_not_nfc",
         group: "pedantic",
         desc: "using a Unicode literal not in NFC normal form (see [Unicode tr15](http://www.unicode.org/reports/tr15/) for further information)",
diff --git a/tests/ui/undropped_manually_drops.rs b/tests/ui/undropped_manually_drops.rs
new file mode 100644
index 00000000000..f4cfc92e1cd
--- /dev/null
+++ b/tests/ui/undropped_manually_drops.rs
@@ -0,0 +1,26 @@
+#![warn(clippy::undropped_manually_drops)]
+
+struct S;
+
+fn main() {
+    let f = std::mem::drop;
+    let g = std::mem::ManuallyDrop::drop;
+    let mut manual1 = std::mem::ManuallyDrop::new(S);
+    let mut manual2 = std::mem::ManuallyDrop::new(S);
+    let mut manual3 = std::mem::ManuallyDrop::new(S);
+    let mut manual4 = std::mem::ManuallyDrop::new(S);
+
+    // These lines will not drop `S` and should be linted
+    drop(std::mem::ManuallyDrop::new(S));
+    drop(manual1);
+
+    // FIXME: this line is not linted, though it should be
+    f(manual2);
+
+    // These lines will drop `S` and should be okay.
+    unsafe {
+        std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S));
+        std::mem::ManuallyDrop::drop(&mut manual3);
+        g(&mut manual4);
+    }
+}
diff --git a/tests/ui/undropped_manually_drops.stderr b/tests/ui/undropped_manually_drops.stderr
new file mode 100644
index 00000000000..2ac0fe98697
--- /dev/null
+++ b/tests/ui/undropped_manually_drops.stderr
@@ -0,0 +1,19 @@
+error: the inner value of this ManuallyDrop will not be dropped
+  --> $DIR/undropped_manually_drops.rs:14:5
+   |
+LL |     drop(std::mem::ManuallyDrop::new(S));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::undropped-manually-drops` implied by `-D warnings`
+   = help: to drop a `ManuallyDrop<T>`, use std::mem::ManuallyDrop::drop
+
+error: the inner value of this ManuallyDrop will not be dropped
+  --> $DIR/undropped_manually_drops.rs:15:5
+   |
+LL |     drop(manual1);
+   |     ^^^^^^^^^^^^^
+   |
+   = help: to drop a `ManuallyDrop<T>`, use std::mem::ManuallyDrop::drop
+
+error: aborting due to 2 previous errors
+