mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-26 14:43:24 +00:00
Implement arbitrary_enum_discriminant
This commit is contained in:
parent
38cd9489f7
commit
ac98342e84
@ -0,0 +1,37 @@
|
||||
# `arbitrary_enum_discriminant`
|
||||
|
||||
The tracking issue for this feature is: [#60553]
|
||||
|
||||
[#60553]: https://github.com/rust-lang/rust/issues/60553
|
||||
|
||||
------------------------
|
||||
|
||||
The `arbitrary_enum_discriminant` feature permits tuple-like and
|
||||
struct-like enum variants with `#[repr(<int-type>)]` to have explicit discriminants.
|
||||
|
||||
## Examples
|
||||
|
||||
```rust
|
||||
#![feature(arbitrary_enum_discriminant)]
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(u8)]
|
||||
enum Enum {
|
||||
Unit = 3,
|
||||
Tuple(u16) = 2,
|
||||
Struct {
|
||||
a: u8,
|
||||
b: u16,
|
||||
} = 1,
|
||||
}
|
||||
|
||||
impl Enum {
|
||||
fn tag(&self) -> u8 {
|
||||
unsafe { *(self as *const Self as *const u8) }
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(3, Enum::Unit.tag());
|
||||
assert_eq!(2, Enum::Tuple(5).tag());
|
||||
assert_eq!(1, Enum::Struct{a: 7, b: 11}.tag());
|
||||
```
|
@ -1936,6 +1936,25 @@ pub fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, vs: &'tcx [hir::Variant], i
|
||||
}
|
||||
}
|
||||
|
||||
if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant {
|
||||
let is_unit =
|
||||
|var: &hir::Variant| match var.node.data {
|
||||
hir::VariantData::Unit(..) => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
let has_disr = |var: &hir::Variant| var.node.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));
|
||||
|
||||
if disr_non_unit || (disr_units && has_non_units) {
|
||||
let mut err = struct_span_err!(tcx.sess, sp, E0732,
|
||||
"`#[repr(inttype)]` must be specified");
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
let mut disr_vals: Vec<Discr<'tcx>> = Vec::with_capacity(vs.len());
|
||||
for ((_, discr), v) in def.discriminants(tcx).zip(vs) {
|
||||
// Check for duplicate discriminant values
|
||||
|
@ -4733,6 +4733,38 @@ if there are multiple variants, it is not clear how the enum should be
|
||||
represented.
|
||||
"##,
|
||||
|
||||
E0732: r##"
|
||||
An `enum` with a discriminant must specify a `#[repr(inttype)]`.
|
||||
|
||||
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
|
||||
is a well-defined way to extract a variant's discriminant from a value;
|
||||
for instance:
|
||||
|
||||
```
|
||||
#![feature(arbitrary_enum_discriminant)]
|
||||
|
||||
#[repr(u8)]
|
||||
enum Enum {
|
||||
Unit = 3,
|
||||
Tuple(u16) = 2,
|
||||
Struct {
|
||||
a: u8,
|
||||
b: u16,
|
||||
} = 1,
|
||||
}
|
||||
|
||||
fn discriminant(v : &Enum) -> u8 {
|
||||
unsafe { *(v as *const Enum as *const u8) }
|
||||
}
|
||||
|
||||
assert_eq!(3, discriminant(&Enum::Unit));
|
||||
assert_eq!(2, discriminant(&Enum::Tuple(5)));
|
||||
assert_eq!(1, discriminant(&Enum::Struct{a: 7, b: 11}));
|
||||
```
|
||||
"##,
|
||||
|
||||
}
|
||||
|
||||
register_diagnostics! {
|
||||
|
@ -25,13 +25,14 @@ use crate::source_map::Spanned;
|
||||
use crate::edition::{ALL_EDITIONS, Edition};
|
||||
use crate::visit::{self, FnKind, Visitor};
|
||||
use crate::parse::{token, ParseSess};
|
||||
use crate::parse::parser::Parser;
|
||||
use crate::symbol::{Symbol, sym};
|
||||
use crate::tokenstream::TokenTree;
|
||||
|
||||
use errors::{Applicability, DiagnosticBuilder, Handler};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
|
||||
use log::debug;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
@ -566,6 +567,9 @@ declare_features! (
|
||||
// #[repr(transparent)] on unions.
|
||||
(active, transparent_unions, "1.37.0", Some(60405), None),
|
||||
|
||||
// Allows explicit discriminants on non-unit enum variants.
|
||||
(active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
@ -1705,20 +1709,20 @@ pub fn emit_feature_err(
|
||||
feature_err(sess, feature, span, issue, explain).emit();
|
||||
}
|
||||
|
||||
pub fn feature_err<'a>(
|
||||
pub fn feature_err<'a, S: Into<MultiSpan>>(
|
||||
sess: &'a ParseSess,
|
||||
feature: Symbol,
|
||||
span: Span,
|
||||
span: S,
|
||||
issue: GateIssue,
|
||||
explain: &str,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard)
|
||||
}
|
||||
|
||||
fn leveled_feature_err<'a>(
|
||||
fn leveled_feature_err<'a, S: Into<MultiSpan>>(
|
||||
sess: &'a ParseSess,
|
||||
feature: Symbol,
|
||||
span: Span,
|
||||
span: S,
|
||||
issue: GateIssue,
|
||||
explain: &str,
|
||||
level: GateStrength,
|
||||
@ -2033,6 +2037,29 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
ast::ItemKind::Enum(ast::EnumDef{ref variants, ..}, ..) => {
|
||||
for variant in variants {
|
||||
match (&variant.node.data, &variant.node.disr_expr) {
|
||||
(ast::VariantData::Unit(..), _) => {},
|
||||
(_, Some(disr_expr)) =>
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
arbitrary_enum_discriminant,
|
||||
disr_expr.value.span,
|
||||
"discriminants on non-unit variants are experimental"),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
let has_feature = self.context.features.arbitrary_enum_discriminant;
|
||||
if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) {
|
||||
Parser::maybe_report_invalid_custom_discriminants(
|
||||
self.context.parse_sess,
|
||||
&variants,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => {
|
||||
if polarity == ast::ImplPolarity::Negative {
|
||||
gate_feature_post!(&self, optin_builtin_traits,
|
||||
|
@ -2,7 +2,7 @@ use crate::ast::{
|
||||
self, Arg, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind,
|
||||
Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, VariantData,
|
||||
};
|
||||
use crate::parse::{SeqSep, PResult, Parser};
|
||||
use crate::parse::{SeqSep, PResult, Parser, ParseSess};
|
||||
use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType};
|
||||
use crate::parse::token::{self, TokenKind};
|
||||
use crate::print::pprust;
|
||||
@ -539,8 +539,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
crate fn maybe_report_invalid_custom_discriminants(
|
||||
&mut self,
|
||||
discriminant_spans: Vec<Span>,
|
||||
sess: &ParseSess,
|
||||
variants: &[Spanned<ast::Variant_>],
|
||||
) {
|
||||
let has_fields = variants.iter().any(|variant| match variant.node.data {
|
||||
@ -548,28 +547,39 @@ impl<'a> Parser<'a> {
|
||||
VariantData::Unit(..) => false,
|
||||
});
|
||||
|
||||
let discriminant_spans = variants.iter().filter(|variant| match variant.node.data {
|
||||
VariantData::Tuple(..) | VariantData::Struct(..) => false,
|
||||
VariantData::Unit(..) => true,
|
||||
})
|
||||
.filter_map(|variant| variant.node.disr_expr.as_ref().map(|c| c.value.span))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !discriminant_spans.is_empty() && has_fields {
|
||||
let mut err = self.struct_span_err(
|
||||
let mut err = crate::feature_gate::feature_err(
|
||||
sess,
|
||||
sym::arbitrary_enum_discriminant,
|
||||
discriminant_spans.clone(),
|
||||
"custom discriminant values are not allowed in enums with fields",
|
||||
crate::feature_gate::GateIssue::Language,
|
||||
"custom discriminant values are not allowed in enums with tuple or struct variants",
|
||||
);
|
||||
for sp in discriminant_spans {
|
||||
err.span_label(sp, "invalid custom discriminant");
|
||||
err.span_label(sp, "disallowed custom discriminant");
|
||||
}
|
||||
for variant in variants.iter() {
|
||||
if let VariantData::Struct(fields, ..) | VariantData::Tuple(fields, ..) =
|
||||
&variant.node.data
|
||||
{
|
||||
let fields = if fields.len() > 1 {
|
||||
"fields"
|
||||
} else {
|
||||
"a field"
|
||||
};
|
||||
err.span_label(
|
||||
variant.span,
|
||||
&format!("variant with {fields} defined here", fields = fields),
|
||||
);
|
||||
|
||||
match &variant.node.data {
|
||||
VariantData::Struct(..) => {
|
||||
err.span_label(
|
||||
variant.span,
|
||||
"struct variant defined here",
|
||||
);
|
||||
}
|
||||
VariantData::Tuple(..) => {
|
||||
err.span_label(
|
||||
variant.span,
|
||||
"tuple variant defined here",
|
||||
);
|
||||
}
|
||||
VariantData::Unit(..) => {}
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
|
@ -6963,36 +6963,34 @@ impl<'a> Parser<'a> {
|
||||
/// Parses the part of an enum declaration following the `{`.
|
||||
fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult<'a, EnumDef> {
|
||||
let mut variants = Vec::new();
|
||||
let mut any_disr = vec![];
|
||||
while self.token != token::CloseDelim(token::Brace) {
|
||||
let variant_attrs = self.parse_outer_attributes()?;
|
||||
let vlo = self.token.span;
|
||||
|
||||
let struct_def;
|
||||
let mut disr_expr = None;
|
||||
self.eat_bad_pub();
|
||||
let ident = self.parse_ident()?;
|
||||
if self.check(&token::OpenDelim(token::Brace)) {
|
||||
|
||||
let struct_def = if self.check(&token::OpenDelim(token::Brace)) {
|
||||
// Parse a struct variant.
|
||||
let (fields, recovered) = self.parse_record_struct_body()?;
|
||||
struct_def = VariantData::Struct(fields, recovered);
|
||||
VariantData::Struct(fields, recovered)
|
||||
} else if self.check(&token::OpenDelim(token::Paren)) {
|
||||
struct_def = VariantData::Tuple(
|
||||
VariantData::Tuple(
|
||||
self.parse_tuple_struct_body()?,
|
||||
ast::DUMMY_NODE_ID,
|
||||
);
|
||||
} else if self.eat(&token::Eq) {
|
||||
disr_expr = Some(AnonConst {
|
||||
)
|
||||
} else {
|
||||
VariantData::Unit(ast::DUMMY_NODE_ID)
|
||||
};
|
||||
|
||||
let disr_expr = if self.eat(&token::Eq) {
|
||||
Some(AnonConst {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
value: self.parse_expr()?,
|
||||
});
|
||||
if let Some(sp) = disr_expr.as_ref().map(|c| c.value.span) {
|
||||
any_disr.push(sp);
|
||||
}
|
||||
struct_def = VariantData::Unit(ast::DUMMY_NODE_ID);
|
||||
})
|
||||
} else {
|
||||
struct_def = VariantData::Unit(ast::DUMMY_NODE_ID);
|
||||
}
|
||||
None
|
||||
};
|
||||
|
||||
let vr = ast::Variant_ {
|
||||
ident,
|
||||
@ -7020,7 +7018,6 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
self.expect(&token::CloseDelim(token::Brace))?;
|
||||
self.maybe_report_invalid_custom_discriminants(any_disr, &variants);
|
||||
|
||||
Ok(ast::EnumDef { variants })
|
||||
}
|
||||
|
@ -135,6 +135,7 @@ symbols! {
|
||||
always,
|
||||
and,
|
||||
any,
|
||||
arbitrary_enum_discriminant,
|
||||
arbitrary_self_types,
|
||||
Arguments,
|
||||
ArgumentV1,
|
||||
|
@ -0,0 +1,9 @@
|
||||
#![crate_type="lib"]
|
||||
#![feature(arbitrary_enum_discriminant)]
|
||||
|
||||
enum Enum {
|
||||
//~^ ERROR `#[repr(inttype)]` must be specified
|
||||
Unit = 1,
|
||||
Tuple() = 2,
|
||||
Struct{} = 3,
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
error[E0732]: `#[repr(inttype)]` must be specified
|
||||
--> $DIR/arbitrary_enum_discriminant-no-repr.rs:4:1
|
||||
|
|
||||
LL | / enum Enum {
|
||||
LL | |
|
||||
LL | | Unit = 1,
|
||||
LL | | Tuple() = 2,
|
||||
LL | | Struct{} = 3,
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0732`.
|
56
src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs
Normal file
56
src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs
Normal file
@ -0,0 +1,56 @@
|
||||
// run-pass
|
||||
#![feature(arbitrary_enum_discriminant, const_raw_ptr_deref, test)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
use test::black_box;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(u8)]
|
||||
enum Enum {
|
||||
Unit = 3,
|
||||
Tuple(u16) = 2,
|
||||
Struct {
|
||||
a: u8,
|
||||
b: u16,
|
||||
} = 1,
|
||||
}
|
||||
|
||||
impl Enum {
|
||||
const unsafe fn tag(&self) -> u8 {
|
||||
*(self as *const Self as *const u8)
|
||||
}
|
||||
}
|
||||
|
||||
#[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);
|
||||
const STRUCT: Enum = Enum::Struct{a: 7, b: 11};
|
||||
|
||||
// Ensure discriminants are correct during runtime execution
|
||||
assert_eq!(3, unsafe { black_box(UNIT).tag() });
|
||||
assert_eq!(2, unsafe { black_box(TUPLE).tag() });
|
||||
assert_eq!(1, unsafe { black_box(STRUCT).tag() });
|
||||
|
||||
// Ensure discriminants are correct during CTFE
|
||||
const UNIT_TAG: u8 = unsafe { UNIT.tag() };
|
||||
const TUPLE_TAG: u8 = unsafe { TUPLE.tag() };
|
||||
const STRUCT_TAG: u8 = unsafe { STRUCT.tag() };
|
||||
|
||||
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);
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
// run-pass
|
||||
use std::mem;
|
||||
|
||||
enum ADT {
|
@ -1,5 +1,6 @@
|
||||
// run-pass
|
||||
#![allow(stable_features)]
|
||||
#![feature(core, core_intrinsics)]
|
||||
#![feature(arbitrary_enum_discriminant, core, core_intrinsics)]
|
||||
|
||||
extern crate core;
|
||||
use core::intrinsics::discriminant_value;
|
||||
@ -38,6 +39,17 @@ enum NullablePointer {
|
||||
|
||||
static CONST : u32 = 0xBEEF;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(isize)]
|
||||
enum Mixed {
|
||||
Unit = 3,
|
||||
Tuple(u16) = 2,
|
||||
Struct {
|
||||
a: u8,
|
||||
b: u16,
|
||||
} = 1,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
|
||||
@ -64,5 +76,9 @@ pub fn main() {
|
||||
|
||||
assert_eq!(discriminant_value(&10), 0);
|
||||
assert_eq!(discriminant_value(&"test"), 0);
|
||||
|
||||
assert_eq!(3, discriminant_value(&Mixed::Unit));
|
||||
assert_eq!(2, discriminant_value(&Mixed::Tuple(5)));
|
||||
assert_eq!(1, discriminant_value(&Mixed::Struct{a: 7, b: 11}));
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
#![crate_type="lib"]
|
||||
|
||||
enum Enum {
|
||||
Unit = 1,
|
||||
//~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants
|
||||
Tuple() = 2,
|
||||
//~^ ERROR discriminants on non-unit variants are experimental
|
||||
Struct{} = 3,
|
||||
//~^ ERROR discriminants on non-unit variants are experimental
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
error[E0658]: discriminants on non-unit variants are experimental
|
||||
--> $DIR/feature-gate-arbitrary_enum_discriminant.rs:6:13
|
||||
|
|
||||
LL | Tuple() = 2,
|
||||
| ^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/60553
|
||||
= help: add #![feature(arbitrary_enum_discriminant)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: discriminants on non-unit variants are experimental
|
||||
--> $DIR/feature-gate-arbitrary_enum_discriminant.rs:8:14
|
||||
|
|
||||
LL | Struct{} = 3,
|
||||
| ^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/60553
|
||||
= help: add #![feature(arbitrary_enum_discriminant)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants
|
||||
--> $DIR/feature-gate-arbitrary_enum_discriminant.rs:4:10
|
||||
|
|
||||
LL | Unit = 1,
|
||||
| ^ disallowed custom discriminant
|
||||
LL |
|
||||
LL | Tuple() = 2,
|
||||
| ----------- tuple variant defined here
|
||||
LL |
|
||||
LL | Struct{} = 3,
|
||||
| ------------ struct variant defined here
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/60553
|
||||
= help: add #![feature(arbitrary_enum_discriminant)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -1,6 +1,6 @@
|
||||
enum X {
|
||||
A = 3,
|
||||
//~^ ERROR custom discriminant values are not allowed in enums with fields
|
||||
//~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants
|
||||
B(usize)
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
error: custom discriminant values are not allowed in enums with fields
|
||||
error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants
|
||||
--> $DIR/issue-17383.rs:2:9
|
||||
|
|
||||
LL | A = 3,
|
||||
| ^ invalid custom discriminant
|
||||
| ^ disallowed custom discriminant
|
||||
LL |
|
||||
LL | B(usize)
|
||||
| -------- variant with a field defined here
|
||||
| -------- tuple variant defined here
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/60553
|
||||
= help: add #![feature(arbitrary_enum_discriminant)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -1,6 +1,6 @@
|
||||
enum Color {
|
||||
Red = 0xff0000,
|
||||
//~^ ERROR custom discriminant values are not allowed in enums with fields
|
||||
//~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants
|
||||
Green = 0x00ff00,
|
||||
Blue = 0x0000ff,
|
||||
Black = 0x000000,
|
||||
|
@ -1,21 +1,25 @@
|
||||
error: custom discriminant values are not allowed in enums with fields
|
||||
error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants
|
||||
--> $DIR/tag-variant-disr-non-nullary.rs:2:11
|
||||
|
|
||||
LL | Red = 0xff0000,
|
||||
| ^^^^^^^^ invalid custom discriminant
|
||||
| ^^^^^^^^ disallowed custom discriminant
|
||||
LL |
|
||||
LL | Green = 0x00ff00,
|
||||
| ^^^^^^^^ invalid custom discriminant
|
||||
| ^^^^^^^^ disallowed custom discriminant
|
||||
LL | Blue = 0x0000ff,
|
||||
| ^^^^^^^^ invalid custom discriminant
|
||||
| ^^^^^^^^ disallowed custom discriminant
|
||||
LL | Black = 0x000000,
|
||||
| ^^^^^^^^ invalid custom discriminant
|
||||
| ^^^^^^^^ disallowed custom discriminant
|
||||
LL | White = 0xffffff,
|
||||
| ^^^^^^^^ invalid custom discriminant
|
||||
| ^^^^^^^^ disallowed custom discriminant
|
||||
LL | Other(usize),
|
||||
| ------------ variant with a field defined here
|
||||
| ------------ tuple variant defined here
|
||||
LL | Other2(usize, usize),
|
||||
| -------------------- variant with fields defined here
|
||||
| -------------------- tuple variant defined here
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/60553
|
||||
= help: add #![feature(arbitrary_enum_discriminant)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
Loading…
Reference in New Issue
Block a user