diff --git a/compiler/rustc_error_codes/src/error_codes/E0732.md b/compiler/rustc_error_codes/src/error_codes/E0732.md index 9536fdbf0df87..df719b4618bce 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0732.md +++ b/compiler/rustc_error_codes/src/error_codes/E0732.md @@ -4,16 +4,19 @@ Erroneous code example: ```compile_fail,E0732 enum Enum { // error! - Unit = 1, - Tuple() = 2, - Struct{} = 3, + Unit = 3, + Tuple(u16) = 2, + Struct { + a: u8, + b: u16, + } = 1, } # fn main() {} ``` -A `#[repr(inttype)]` must be provided on an `enum` if it has a non-unit -variant with a discriminant, or where there are both unit variants with -discriminants and non-unit variants. This restriction ensures that there +A `#[repr(inttype)]` must be provided on an `enum` if it not fieldless and +has a discriminant, or where there are both fieldless variants with +discriminants and variants that have fields. This restriction ensures that there is a well-defined way to extract a variant's discriminant from a value; for instance: diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 8eb51b977ed8a..f3b871078559a 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1384,12 +1384,17 @@ fn check_enum<'tcx>( } if tcx.adt_def(def_id).repr.int.is_none() { - let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..)); + let is_fieldless = |var: &hir::Variant<'_>| match var.data { + hir::VariantData::Unit(_) => true, + hir::VariantData::Tuple(fields, _) | hir::VariantData::Struct(fields, _) => { + fields.is_empty() + } + }; let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); - let has_non_units = vs.iter().any(|var| !is_unit(var)); - let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var)); - let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var)); + let has_non_units = vs.iter().any(|var| !is_fieldless(var)); + let disr_units = vs.iter().any(|var| is_fieldless(&var) && has_disr(&var)); + let disr_non_unit = vs.iter().any(|var| !is_fieldless(&var) && has_disr(&var)); if disr_non_unit || (disr_units && has_non_units) { let mut err = diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs index a6e5f70fdefa6..2e313b074f2bc 100644 --- a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs +++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs @@ -1,8 +1,9 @@ -#![crate_type="lib"] - +#![crate_type = "lib"] enum Enum { -//~^ ERROR `#[repr(inttype)]` must be specified - Unit = 1, - Tuple() = 2, - Struct{} = 3, + //~^ ERROR `#[repr(inttype)]` must be specified + Unit = 5, + Tuple(u8) = 3, + Struct { + foo: u16 + } = 1, } diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr index 7af063c591d56..e27010d4e813a 100644 --- a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr +++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr @@ -1,11 +1,12 @@ error[E0732]: `#[repr(inttype)]` must be specified - --> $DIR/arbitrary_enum_discriminant-no-repr.rs:3:1 + --> $DIR/arbitrary_enum_discriminant-no-repr.rs:2:1 | LL | / enum Enum { LL | | -LL | | Unit = 1, -LL | | Tuple() = 2, -LL | | Struct{} = 3, +LL | | Unit = 5, +LL | | Tuple(u8) = 3, +... | +LL | | } = 1, LL | | } | |_^ diff --git a/src/test/ui/enum-discriminant/fieldless-no-repr.rs b/src/test/ui/enum-discriminant/fieldless-no-repr.rs new file mode 100644 index 0000000000000..16a5204554795 --- /dev/null +++ b/src/test/ui/enum-discriminant/fieldless-no-repr.rs @@ -0,0 +1,8 @@ +// check-pass +#![crate_type="lib"] + +enum Enum { + Unit = 1, + Tuple() = 2, + Struct{} = 3, +}