Auto merge of #83908 - Flying-Toast:master, r=davidtwco

Add enum_intrinsics_non_enums lint

There is a clippy lint to prevent calling [`mem::discriminant`](https://doc.rust-lang.org/std/mem/fn.discriminant.html) with a non-enum type. I think the lint is worthy of being included in rustc, given that `discriminant::<T>()` where `T` is a non-enum has an unspecified return value, and there are no valid use cases where you'd actually want this.

I've also made the lint check [variant_count](https://doc.rust-lang.org/core/mem/fn.variant_count.html) (#73662).

closes #83899
This commit is contained in:
bors 2021-10-11 17:12:14 +00:00
commit 5b210643eb
22 changed files with 292 additions and 315 deletions

View file

@ -1,5 +1,5 @@
// run-pass
#![allow(dead_code)]
#![allow(dead_code, enum_intrinsics_non_enums)]
#![feature(variant_count)]
#![feature(never_type)]

View file

@ -1,4 +1,7 @@
// run-pass
#![allow(enum_intrinsics_non_enums)]
use std::mem;
enum ADT {

View file

@ -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);
}

View file

@ -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