about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_lint/src/enum_intrinsics_non_enums.rs106
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--library/core/src/mem/mod.rs1
-rw-r--r--src/test/ui/consts/const-variant-count.rs2
-rw-r--r--src/test/ui/enum-discriminant/discriminant_value-wrapper.rs3
-rw-r--r--src/test/ui/lint/lint-enum-intrinsics-non-enums.rs67
-rw-r--r--src/test/ui/lint/lint-enum-intrinsics-non-enums.stderr95
-rw-r--r--src/tools/clippy/CHANGELOG.md5
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_all.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_correctness.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_discriminant.rs82
-rw-r--r--src/tools/clippy/tests/ui/mem_discriminant.fixed45
-rw-r--r--src/tools/clippy/tests/ui/mem_discriminant.rs45
-rw-r--r--src/tools/clippy/tests/ui/mem_discriminant.stderr94
-rw-r--r--src/tools/clippy/tests/ui/mem_discriminant_unfixable.rs16
-rw-r--r--src/tools/clippy/tests/ui/mem_discriminant_unfixable.stderr20
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed1
-rw-r--r--src/tools/clippy/tests/ui/rename.rs1
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr14
22 files changed, 292 insertions, 315 deletions
diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
new file mode 100644
index 00000000000..876245747f6
--- /dev/null
+++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
@@ -0,0 +1,106 @@
+use crate::{context::LintContext, LateContext, LateLintPass};
+use rustc_hir as hir;
+use rustc_middle::ty::{fold::TypeFoldable, Ty};
+use rustc_span::{symbol::sym, Span};
+
+declare_lint! {
+    /// The `enum_intrinsics_non_enums` lint detects calls to
+    /// intrinsic functions that require an enum ([`core::mem::discriminant`],
+    /// [`core::mem::variant_count`]), but are called with a non-enum type.
+    ///
+    /// [`core::mem::discriminant`]: https://doc.rust-lang.org/core/mem/fn.discriminant.html
+    /// [`core::mem::variant_count`]: https://doc.rust-lang.org/core/mem/fn.variant_count.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(enum_intrinsics_non_enums)]
+    /// core::mem::discriminant::<i32>(&123);
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In order to accept any enum, the `mem::discriminant` and
+    /// `mem::variant_count` functions are generic over a type `T`.
+    /// This makes it technically possible for `T` to be a non-enum,
+    /// in which case the return value is unspecified.
+    ///
+    /// This lint prevents such incorrect usage of these functions.
+    ENUM_INTRINSICS_NON_ENUMS,
+    Deny,
+    "detects calls to `core::mem::discriminant` and `core::mem::variant_count` with non-enum types"
+}
+
+declare_lint_pass!(EnumIntrinsicsNonEnums => [ENUM_INTRINSICS_NON_ENUMS]);
+
+/// Returns `true` if we know for sure that the given type is not an enum. Note that for cases where
+/// the type is generic, we can't be certain if it will be an enum so we have to assume that it is.
+fn is_non_enum(t: Ty<'_>) -> bool {
+    !t.is_enum() && !t.potentially_needs_subst()
+}
+
+fn enforce_mem_discriminant(
+    cx: &LateContext<'_>,
+    func_expr: &hir::Expr<'_>,
+    expr_span: Span,
+    args_span: Span,
+) {
+    let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
+    if is_non_enum(ty_param) {
+        cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| {
+            builder
+                .build(
+                    "the return value of `mem::discriminant` is \
+                        unspecified when called with a non-enum type",
+                )
+                .span_note(
+                    args_span,
+                    &format!(
+                        "the argument to `discriminant` should be a \
+                            reference to an enum, but it was passed \
+                            a reference to a `{}`, which is not an enum.",
+                        ty_param,
+                    ),
+                )
+                .emit();
+        });
+    }
+}
+
+fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, span: Span) {
+    let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
+    if is_non_enum(ty_param) {
+        cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| {
+            builder
+                .build(
+                    "the return value of `mem::variant_count` is \
+                        unspecified when called with a non-enum type",
+                )
+                .note(&format!(
+                    "the type parameter of `variant_count` should \
+                            be an enum, but it was instantiated with \
+                            the type `{}`, which is not an enum.",
+                    ty_param,
+                ))
+                .emit();
+        });
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for EnumIntrinsicsNonEnums {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
+        if let hir::ExprKind::Call(ref func, ref args) = expr.kind {
+            if let hir::ExprKind::Path(ref qpath) = func.kind {
+                if let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() {
+                    if cx.tcx.is_diagnostic_item(sym::mem_discriminant, def_id) {
+                        enforce_mem_discriminant(cx, func, expr.span, args[0].span);
+                    } else if cx.tcx.is_diagnostic_item(sym::mem_variant_count, def_id) {
+                        enforce_mem_variant_count(cx, func, expr.span);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 17eb0054584..6f684a0fe51 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -47,6 +47,7 @@ mod array_into_iter;
 pub mod builtin;
 mod context;
 mod early;
+mod enum_intrinsics_non_enums;
 mod internal;
 mod late;
 mod levels;
@@ -76,6 +77,7 @@ use rustc_span::Span;
 
 use array_into_iter::ArrayIntoIter;
 use builtin::*;
+use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
 use internal::*;
 use methods::*;
 use non_ascii_idents::*;
@@ -168,6 +170,7 @@ macro_rules! late_lint_passes {
                 TemporaryCStringAsPtr: TemporaryCStringAsPtr,
                 NonPanicFmt: NonPanicFmt,
                 NoopMethodCall: NoopMethodCall,
+                EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
                 InvalidAtomicOrdering: InvalidAtomicOrdering,
                 NamedAsmLabels: NamedAsmLabels,
             ]
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 9551120ca55..6c889e88a59 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -816,6 +816,7 @@ symbols! {
         mem_size_of,
         mem_size_of_val,
         mem_uninitialized,
+        mem_variant_count,
         mem_zeroed,
         member_constraints,
         memory,
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 84fd1a532c1..894ae10e1b4 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -1053,6 +1053,7 @@ pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
 #[inline(always)]
 #[unstable(feature = "variant_count", issue = "73662")]
 #[rustc_const_unstable(feature = "variant_count", issue = "73662")]
+#[rustc_diagnostic_item = "mem_variant_count"]
 pub const fn variant_count<T>() -> usize {
     intrinsics::variant_count::<T>()
 }
diff --git a/src/test/ui/consts/const-variant-count.rs b/src/test/ui/consts/const-variant-count.rs
index 455419d2c7f..50eaeeb4685 100644
--- a/src/test/ui/consts/const-variant-count.rs
+++ b/src/test/ui/consts/const-variant-count.rs
@@ -1,5 +1,5 @@
 // run-pass
-#![allow(dead_code)]
+#![allow(dead_code, enum_intrinsics_non_enums)]
 #![feature(variant_count)]
 #![feature(never_type)]
 
diff --git a/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs b/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs
index daef2de87a9..65dc9166330 100644
--- a/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs
+++ b/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs
@@ -1,4 +1,7 @@
 // run-pass
+
+#![allow(enum_intrinsics_non_enums)]
+
 use std::mem;
 
 enum ADT {
diff --git a/src/test/ui/lint/lint-enum-intrinsics-non-enums.rs b/src/test/ui/lint/lint-enum-intrinsics-non-enums.rs
new file mode 100644
index 00000000000..8ad337064e5
--- /dev/null
+++ b/src/test/ui/lint/lint-enum-intrinsics-non-enums.rs
@@ -0,0 +1,67 @@
+// Test the enum_intrinsics_non_enums lint.
+
+#![feature(variant_count)]
+
+use std::mem::{discriminant, variant_count};
+
+enum SomeEnum {
+    A,
+    B,
+}
+
+struct SomeStruct;
+
+fn generic_discriminant<T>(v: &T) {
+    discriminant::<T>(v);
+}
+
+fn generic_variant_count<T>() -> usize {
+    variant_count::<T>()
+}
+
+fn test_discriminant() {
+    discriminant(&SomeEnum::A);
+    generic_discriminant(&SomeEnum::B);
+
+    discriminant(&());
+    //~^ error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
+
+    discriminant(&&SomeEnum::B);
+    //~^ error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
+
+    discriminant(&SomeStruct);
+    //~^ error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
+
+    discriminant(&123u32);
+    //~^ error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
+
+    discriminant(&&123i8);
+    //~^ error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
+}
+
+fn test_variant_count() {
+    variant_count::<SomeEnum>();
+    generic_variant_count::<SomeEnum>();
+
+    variant_count::<&str>();
+    //~^ error: the return value of `mem::variant_count` is unspecified when called with a non-enum type
+
+    variant_count::<*const u8>();
+    //~^ error: the return value of `mem::variant_count` is unspecified when called with a non-enum type
+
+    variant_count::<()>();
+    //~^ error: the return value of `mem::variant_count` is unspecified when called with a non-enum type
+
+    variant_count::<&SomeEnum>();
+    //~^ error: the return value of `mem::variant_count` is unspecified when called with a non-enum type
+}
+
+fn main() {
+    test_discriminant();
+    test_variant_count();
+
+    // The lint ignores cases where the type is generic, so these should be
+    // allowed even though their return values are unspecified
+    generic_variant_count::<SomeStruct>();
+    generic_discriminant::<SomeStruct>(&SomeStruct);
+}
diff --git a/src/test/ui/lint/lint-enum-intrinsics-non-enums.stderr b/src/test/ui/lint/lint-enum-intrinsics-non-enums.stderr
new file mode 100644
index 00000000000..bec9fb62efa
--- /dev/null
+++ b/src/test/ui/lint/lint-enum-intrinsics-non-enums.stderr
@@ -0,0 +1,95 @@
+error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:26:5
+   |
+LL |     discriminant(&());
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[deny(enum_intrinsics_non_enums)]` on by default
+note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `()`, which is not an enum.
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:26:18
+   |
+LL |     discriminant(&());
+   |                  ^^^
+
+error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:29:5
+   |
+LL |     discriminant(&&SomeEnum::B);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `&SomeEnum`, which is not an enum.
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:29:18
+   |
+LL |     discriminant(&&SomeEnum::B);
+   |                  ^^^^^^^^^^^^^
+
+error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:32:5
+   |
+LL |     discriminant(&SomeStruct);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `SomeStruct`, which is not an enum.
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:32:18
+   |
+LL |     discriminant(&SomeStruct);
+   |                  ^^^^^^^^^^^
+
+error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:35:5
+   |
+LL |     discriminant(&123u32);
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `u32`, which is not an enum.
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:35:18
+   |
+LL |     discriminant(&123u32);
+   |                  ^^^^^^^
+
+error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:38:5
+   |
+LL |     discriminant(&&123i8);
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `&i8`, which is not an enum.
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:38:18
+   |
+LL |     discriminant(&&123i8);
+   |                  ^^^^^^^
+
+error: the return value of `mem::variant_count` is unspecified when called with a non-enum type
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:46:5
+   |
+LL |     variant_count::<&str>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `&str`, which is not an enum.
+
+error: the return value of `mem::variant_count` is unspecified when called with a non-enum type
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:49:5
+   |
+LL |     variant_count::<*const u8>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `*const u8`, which is not an enum.
+
+error: the return value of `mem::variant_count` is unspecified when called with a non-enum type
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:52:5
+   |
+LL |     variant_count::<()>();
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `()`, which is not an enum.
+
+error: the return value of `mem::variant_count` is unspecified when called with a non-enum type
+  --> $DIR/lint-enum-intrinsics-non-enums.rs:55:5
+   |
+LL |     variant_count::<&SomeEnum>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the type parameter of `variant_count` should be an enum, but it was instantiated with the type `&SomeEnum`, which is not an enum.
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 7fdb300c977..e700e5f0d73 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -1873,10 +1873,10 @@ Released 2019-01-17
 
 [2e26fdc2...b2601be](https://github.com/rust-lang/rust-clippy/compare/2e26fdc2...b2601be)
 
-* New lints: [`slow_vector_initialization`], [`mem_discriminant_non_enum`],
+* New lints: [`slow_vector_initialization`], `mem_discriminant_non_enum`,
   [`redundant_clone`], [`wildcard_dependencies`],
   [`into_iter_on_ref`], `into_iter_on_array`, [`deprecated_cfg_attr`],
-  [`mem_discriminant_non_enum`], [`cargo_common_metadata`]
+  [`cargo_common_metadata`]
 * Add support for `u128` and `i128` to integer related lints
 * Add float support to `mistyped_literal_suffixes`
 * Fix false positives in `use_self`
@@ -2839,7 +2839,6 @@ Released 2018-09-13
 [`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
 [`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
 [`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
-[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum
 [`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget
 [`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none
 [`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
index 3e6e0244754..6a3ee35b41a 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
@@ -127,7 +127,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
     LintId::of(matches::SINGLE_MATCH),
     LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
-    LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
     LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
     LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
     LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
index e0ef7b3b8af..bbe47a0e772 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
@@ -36,7 +36,6 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
     LintId::of(loops::ITER_NEXT_LOOP),
     LintId::of(loops::NEVER_LOOP),
     LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
-    LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
     LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
     LintId::of(methods::CLONE_DOUBLE_REF),
     LintId::of(methods::ITERATOR_STEP_BY_ZERO),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
index 2ba2b3da55c..b0be3b65366 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
@@ -241,7 +241,6 @@ store.register_lints(&[
     matches::SINGLE_MATCH_ELSE,
     matches::WILDCARD_ENUM_MATCH_ARM,
     matches::WILDCARD_IN_OR_PATTERNS,
-    mem_discriminant::MEM_DISCRIMINANT_NON_ENUM,
     mem_forget::MEM_FORGET,
     mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
     mem_replace::MEM_REPLACE_WITH_DEFAULT,
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 9fc6a9e0ccc..5534f9c94f3 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -266,7 +266,6 @@ mod map_unit_fn;
 mod match_on_vec_items;
 mod match_result_ok;
 mod matches;
-mod mem_discriminant;
 mod mem_forget;
 mod mem_replace;
 mod methods;
@@ -600,7 +599,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
     store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
     store.register_late_pass(|| Box::new(neg_multiply::NegMultiply));
-    store.register_late_pass(|| Box::new(mem_discriminant::MemDiscriminant));
     store.register_late_pass(|| Box::new(mem_forget::MemForget));
     store.register_late_pass(|| Box::new(arithmetic::Arithmetic::default()));
     store.register_late_pass(|| Box::new(assign_ops::AssignOps));
@@ -850,6 +848,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
     ls.register_renamed("clippy::panic_params", "non_fmt_panics");
     ls.register_renamed("clippy::unknown_clippy_lints", "unknown_lints");
     ls.register_renamed("clippy::invalid_atomic_ordering", "invalid_atomic_ordering");
+    ls.register_renamed("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums");
 }
 
 // only exists to let the dogfood integration test works.
diff --git a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs b/src/tools/clippy/clippy_lints/src/mem_discriminant.rs
deleted file mode 100644
index 59176c4b846..00000000000
--- a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::snippet;
-use clippy_utils::ty::walk_ptrs_ty_depth;
-use clippy_utils::{match_def_path, paths};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for calls of `mem::discriminant()` on a non-enum type.
-    ///
-    /// ### Why is this bad?
-    /// The value of `mem::discriminant()` on non-enum types
-    /// is unspecified.
-    ///
-    /// ### Example
-    /// ```rust
-    /// use std::mem;
-    ///
-    /// mem::discriminant(&"hello");
-    /// mem::discriminant(&&Some(2));
-    /// ```
-    pub MEM_DISCRIMINANT_NON_ENUM,
-    correctness,
-    "calling `mem::descriminant` on non-enum type"
-}
-
-declare_lint_pass!(MemDiscriminant => [MEM_DISCRIMINANT_NON_ENUM]);
-
-impl<'tcx> LateLintPass<'tcx> for MemDiscriminant {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if let ExprKind::Call(func, func_args) = expr.kind;
-            // is `mem::discriminant`
-            if let ExprKind::Path(ref func_qpath) = func.kind;
-            if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
-            if match_def_path(cx, def_id, &paths::MEM_DISCRIMINANT);
-            // type is non-enum
-            let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0);
-            if !ty_param.is_enum();
-
-            then {
-                span_lint_and_then(
-                    cx,
-                    MEM_DISCRIMINANT_NON_ENUM,
-                    expr.span,
-                    &format!("calling `mem::discriminant` on non-enum type `{}`", ty_param),
-                    |diag| {
-                        // if this is a reference to an enum, suggest dereferencing
-                        let (base_ty, ptr_depth) = walk_ptrs_ty_depth(ty_param);
-                        if ptr_depth >= 1 && base_ty.is_enum() {
-                            let param = &func_args[0];
-
-                            // cancel out '&'s first
-                            let mut derefs_needed = ptr_depth;
-                            let mut cur_expr = param;
-                            while derefs_needed > 0  {
-                                if let ExprKind::AddrOf(BorrowKind::Ref, _, inner_expr) = cur_expr.kind {
-                                    derefs_needed -= 1;
-                                    cur_expr = inner_expr;
-                                } else {
-                                    break;
-                                }
-                            }
-
-                            let derefs = "*".repeat(derefs_needed);
-                            diag.span_suggestion(
-                                param.span,
-                                "try dereferencing",
-                                format!("{}{}", derefs, snippet(cx, cur_expr.span, "<param>")),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                    },
-                )
-            }
-        }
-    }
-}
diff --git a/src/tools/clippy/tests/ui/mem_discriminant.fixed b/src/tools/clippy/tests/ui/mem_discriminant.fixed
deleted file mode 100644
index 69a8f286d05..00000000000
--- a/src/tools/clippy/tests/ui/mem_discriminant.fixed
+++ /dev/null
@@ -1,45 +0,0 @@
-// run-rustfix
-
-#![deny(clippy::mem_discriminant_non_enum)]
-
-use std::mem;
-
-enum Foo {
-    One(usize),
-    Two(u8),
-}
-
-fn main() {
-    // bad
-    mem::discriminant(&Some(2));
-    mem::discriminant(&None::<u8>);
-    mem::discriminant(&Foo::One(5));
-    mem::discriminant(&Foo::Two(5));
-
-    let ro = &Some(3);
-    let rro = &ro;
-    mem::discriminant(ro);
-    mem::discriminant(*rro);
-    mem::discriminant(*rro);
-
-    macro_rules! mem_discriminant_but_in_a_macro {
-        ($param:expr) => {
-            mem::discriminant($param)
-        };
-    }
-
-    mem_discriminant_but_in_a_macro!(*rro);
-
-    let rrrrro = &&&rro;
-    mem::discriminant(****rrrrro);
-    mem::discriminant(****rrrrro);
-
-    // ok
-    mem::discriminant(&Some(2));
-    mem::discriminant(&None::<u8>);
-    mem::discriminant(&Foo::One(5));
-    mem::discriminant(&Foo::Two(5));
-    mem::discriminant(ro);
-    mem::discriminant(*rro);
-    mem::discriminant(****rrrrro);
-}
diff --git a/src/tools/clippy/tests/ui/mem_discriminant.rs b/src/tools/clippy/tests/ui/mem_discriminant.rs
deleted file mode 100644
index 55db50fcdc7..00000000000
--- a/src/tools/clippy/tests/ui/mem_discriminant.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-// run-rustfix
-
-#![deny(clippy::mem_discriminant_non_enum)]
-
-use std::mem;
-
-enum Foo {
-    One(usize),
-    Two(u8),
-}
-
-fn main() {
-    // bad
-    mem::discriminant(&&Some(2));
-    mem::discriminant(&&None::<u8>);
-    mem::discriminant(&&Foo::One(5));
-    mem::discriminant(&&Foo::Two(5));
-
-    let ro = &Some(3);
-    let rro = &ro;
-    mem::discriminant(&ro);
-    mem::discriminant(rro);
-    mem::discriminant(&rro);
-
-    macro_rules! mem_discriminant_but_in_a_macro {
-        ($param:expr) => {
-            mem::discriminant($param)
-        };
-    }
-
-    mem_discriminant_but_in_a_macro!(&rro);
-
-    let rrrrro = &&&rro;
-    mem::discriminant(&rrrrro);
-    mem::discriminant(*rrrrro);
-
-    // ok
-    mem::discriminant(&Some(2));
-    mem::discriminant(&None::<u8>);
-    mem::discriminant(&Foo::One(5));
-    mem::discriminant(&Foo::Two(5));
-    mem::discriminant(ro);
-    mem::discriminant(*rro);
-    mem::discriminant(****rrrrro);
-}
diff --git a/src/tools/clippy/tests/ui/mem_discriminant.stderr b/src/tools/clippy/tests/ui/mem_discriminant.stderr
deleted file mode 100644
index 36a225b7594..00000000000
--- a/src/tools/clippy/tests/ui/mem_discriminant.stderr
+++ /dev/null
@@ -1,94 +0,0 @@
-error: calling `mem::discriminant` on non-enum type `&std::option::Option<i32>`
-  --> $DIR/mem_discriminant.rs:14:5
-   |
-LL |     mem::discriminant(&&Some(2));
-   |     ^^^^^^^^^^^^^^^^^^---------^
-   |                       |
-   |                       help: try dereferencing: `&Some(2)`
-   |
-note: the lint level is defined here
-  --> $DIR/mem_discriminant.rs:3:9
-   |
-LL | #![deny(clippy::mem_discriminant_non_enum)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: calling `mem::discriminant` on non-enum type `&std::option::Option<u8>`
-  --> $DIR/mem_discriminant.rs:15:5
-   |
-LL |     mem::discriminant(&&None::<u8>);
-   |     ^^^^^^^^^^^^^^^^^^------------^
-   |                       |
-   |                       help: try dereferencing: `&None::<u8>`
-
-error: calling `mem::discriminant` on non-enum type `&Foo`
-  --> $DIR/mem_discriminant.rs:16:5
-   |
-LL |     mem::discriminant(&&Foo::One(5));
-   |     ^^^^^^^^^^^^^^^^^^-------------^
-   |                       |
-   |                       help: try dereferencing: `&Foo::One(5)`
-
-error: calling `mem::discriminant` on non-enum type `&Foo`
-  --> $DIR/mem_discriminant.rs:17:5
-   |
-LL |     mem::discriminant(&&Foo::Two(5));
-   |     ^^^^^^^^^^^^^^^^^^-------------^
-   |                       |
-   |                       help: try dereferencing: `&Foo::Two(5)`
-
-error: calling `mem::discriminant` on non-enum type `&std::option::Option<i32>`
-  --> $DIR/mem_discriminant.rs:21:5
-   |
-LL |     mem::discriminant(&ro);
-   |     ^^^^^^^^^^^^^^^^^^---^
-   |                       |
-   |                       help: try dereferencing: `ro`
-
-error: calling `mem::discriminant` on non-enum type `&std::option::Option<i32>`
-  --> $DIR/mem_discriminant.rs:22:5
-   |
-LL |     mem::discriminant(rro);
-   |     ^^^^^^^^^^^^^^^^^^---^
-   |                       |
-   |                       help: try dereferencing: `*rro`
-
-error: calling `mem::discriminant` on non-enum type `&&std::option::Option<i32>`
-  --> $DIR/mem_discriminant.rs:23:5
-   |
-LL |     mem::discriminant(&rro);
-   |     ^^^^^^^^^^^^^^^^^^----^
-   |                       |
-   |                       help: try dereferencing: `*rro`
-
-error: calling `mem::discriminant` on non-enum type `&&std::option::Option<i32>`
-  --> $DIR/mem_discriminant.rs:27:13
-   |
-LL |             mem::discriminant($param)
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL |     mem_discriminant_but_in_a_macro!(&rro);
-   |     ---------------------------------------
-   |     |                                |
-   |     |                                help: try dereferencing: `*rro`
-   |     in this macro invocation
-   |
-   = note: this error originates in the macro `mem_discriminant_but_in_a_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: calling `mem::discriminant` on non-enum type `&&&&&std::option::Option<i32>`
-  --> $DIR/mem_discriminant.rs:34:5
-   |
-LL |     mem::discriminant(&rrrrro);
-   |     ^^^^^^^^^^^^^^^^^^-------^
-   |                       |
-   |                       help: try dereferencing: `****rrrrro`
-
-error: calling `mem::discriminant` on non-enum type `&&&std::option::Option<i32>`
-  --> $DIR/mem_discriminant.rs:35:5
-   |
-LL |     mem::discriminant(*rrrrro);
-   |     ^^^^^^^^^^^^^^^^^^-------^
-   |                       |
-   |                       help: try dereferencing: `****rrrrro`
-
-error: aborting due to 10 previous errors
-
diff --git a/src/tools/clippy/tests/ui/mem_discriminant_unfixable.rs b/src/tools/clippy/tests/ui/mem_discriminant_unfixable.rs
deleted file mode 100644
index e245d3257d5..00000000000
--- a/src/tools/clippy/tests/ui/mem_discriminant_unfixable.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-#![deny(clippy::mem_discriminant_non_enum)]
-
-use std::mem;
-
-enum Foo {
-    One(usize),
-    Two(u8),
-}
-
-struct A(Foo);
-
-fn main() {
-    // bad
-    mem::discriminant(&"hello");
-    mem::discriminant(&A(Foo::One(0)));
-}
diff --git a/src/tools/clippy/tests/ui/mem_discriminant_unfixable.stderr b/src/tools/clippy/tests/ui/mem_discriminant_unfixable.stderr
deleted file mode 100644
index e2de3776f2c..00000000000
--- a/src/tools/clippy/tests/ui/mem_discriminant_unfixable.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: calling `mem::discriminant` on non-enum type `&str`
-  --> $DIR/mem_discriminant_unfixable.rs:14:5
-   |
-LL |     mem::discriminant(&"hello");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/mem_discriminant_unfixable.rs:1:9
-   |
-LL | #![deny(clippy::mem_discriminant_non_enum)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: calling `mem::discriminant` on non-enum type `A`
-  --> $DIR/mem_discriminant_unfixable.rs:15:5
-   |
-LL |     mem::discriminant(&A(Foo::One(0)));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 13fbb6e2a6e..a66c2e587c8 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -8,6 +8,7 @@
 #![allow(clippy::redundant_static_lifetimes)]
 // warn for the old lint name here, to test if the renaming worked
 #![warn(clippy::cognitive_complexity)]
+#![warn(enum_intrinsics_non_enums)]
 
 #[warn(clippy::module_name_repetitions)]
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index cbd3b1e9166..fa81201a2da 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -8,6 +8,7 @@
 #![allow(clippy::redundant_static_lifetimes)]
 // warn for the old lint name here, to test if the renaming worked
 #![warn(clippy::cyclomatic_complexity)]
+#![warn(clippy::mem_discriminant_non_enum)]
 
 #[warn(clippy::stutter)]
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index c5d633ff86b..05c7854074c 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -6,23 +6,29 @@ LL | #![warn(clippy::cyclomatic_complexity)]
    |
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
+error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
+  --> $DIR/rename.rs:11:9
+   |
+LL | #![warn(clippy::mem_discriminant_non_enum)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
+
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:12:8
+  --> $DIR/rename.rs:13:8
    |
 LL | #[warn(clippy::stutter)]
    |        ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:15:8
+  --> $DIR/rename.rs:16:8
    |
 LL | #[warn(clippy::new_without_default_derive)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:18:8
+  --> $DIR/rename.rs:19:8
    |
 LL | #[warn(clippy::const_static_lifetime)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors