diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 44f741c5df1a2..69eb73b42552c 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::ErrorReported; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; use rustc_query_system::ich::StableHashingContext; @@ -314,6 +314,22 @@ impl<'tcx> AdtDef { /// Whether the ADT lacks fields. Note that this includes uninhabited enums, /// e.g., `enum Void {}` is considered payload free as well. pub fn is_payloadfree(&self) -> bool { + // Treat the ADT as not payload-free if arbitrary_enum_discriminant is used (#88621). + // This would disallow the following kind of enum from being casted into integer. + // ``` + // enum Enum { + // Foo() = 1, + // Bar{} = 2, + // Baz = 3, + // } + // ``` + if self + .variants + .iter() + .any(|v| matches!(v.discr, VariantDiscr::Explicit(_)) && v.ctor_kind != CtorKind::Const) + { + return false; + } self.variants.iter().all(|v| v.fields.is_empty()) } diff --git a/src/test/ui/cast/issue-88621.rs b/src/test/ui/cast/issue-88621.rs new file mode 100644 index 0000000000000..9242b80e22939 --- /dev/null +++ b/src/test/ui/cast/issue-88621.rs @@ -0,0 +1,13 @@ +#![feature(arbitrary_enum_discriminant)] + +#[repr(u8)] +enum Kind2 { + Foo() = 1, + Bar{} = 2, + Baz = 3, +} + +fn main() { + let _ = Kind2::Foo() as u8; + //~^ ERROR non-primitive cast +} diff --git a/src/test/ui/cast/issue-88621.stderr b/src/test/ui/cast/issue-88621.stderr new file mode 100644 index 0000000000000..e96d866515238 --- /dev/null +++ b/src/test/ui/cast/issue-88621.stderr @@ -0,0 +1,9 @@ +error[E0605]: non-primitive cast: `Kind2` as `u8` + --> $DIR/issue-88621.rs:11:13 + | +LL | let _ = Kind2::Foo() as u8; + | ^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0605`. diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs index 22c5332c9259f..ccc423e4a194c 100644 --- a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs +++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs @@ -22,14 +22,6 @@ impl Enum { } } -#[allow(dead_code)] -#[repr(u8)] -enum FieldlessEnum { - Unit = 3, - Tuple() = 2, - Struct {} = 1, -} - fn main() { const UNIT: Enum = Enum::Unit; const TUPLE: Enum = Enum::Tuple(5); @@ -48,9 +40,4 @@ fn main() { assert_eq!(3, UNIT_TAG); assert_eq!(2, TUPLE_TAG); assert_eq!(1, STRUCT_TAG); - - // Ensure `as` conversions are correct - assert_eq!(3, FieldlessEnum::Unit as u8); - assert_eq!(2, FieldlessEnum::Tuple() as u8); - assert_eq!(1, FieldlessEnum::Struct{} as u8); }