diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index d48fcbbd672..8ac5beb21b5 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -1,16 +1,19 @@ use crate::ast; -use crate::ast::{BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind}; -use crate::parse::parser::{BlockMode, PathStyle, TokenType, SemiColonMode}; +use crate::ast::{ + BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind, VariantData, +}; +use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType}; use crate::parse::token; use crate::parse::PResult; use crate::parse::Parser; use crate::print::pprust; use crate::ptr::P; +use crate::source_map::Spanned; use crate::symbol::kw; use crate::ThinVec; use errors::{Applicability, DiagnosticBuilder}; -use syntax_pos::Span; use log::debug; +use syntax_pos::Span; pub trait RecoverQPath: Sized + 'static { const PATH_STYLE: PathStyle = PathStyle::Expr; @@ -79,6 +82,44 @@ impl<'a> Parser<'a> { } } + crate fn maybe_report_invalid_custom_discriminants( + &mut self, + discriminant_spans: Vec, + variants: &[Spanned], + ) { + let has_fields = variants.iter().any(|variant| match variant.node.data { + VariantData::Tuple(..) | VariantData::Struct(..) => true, + VariantData::Unit(..) => false, + }); + + if !discriminant_spans.is_empty() && has_fields { + let mut err = self.struct_span_err( + discriminant_spans.clone(), + "custom discriminant values are not allowed in enums with fields", + ); + for sp in discriminant_spans { + err.span_label(sp, "invalid 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), + ); + + } + } + err.emit(); + } + } + crate fn maybe_recover_from_bad_type_plus( &mut self, allow_plus: bool, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ae3665c834b..df801515082 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -7466,7 +7466,6 @@ fn parse_existential_or_alias( /// 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 all_nullary = true; let mut any_disr = vec![]; while self.token != token::CloseDelim(token::Brace) { let variant_attrs = self.parse_outer_attributes()?; @@ -7478,11 +7477,9 @@ fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult<'a, EnumDef> let ident = self.parse_ident()?; if self.check(&token::OpenDelim(token::Brace)) { // Parse a struct variant. - all_nullary = false; let (fields, recovered) = self.parse_record_struct_body()?; struct_def = VariantData::Struct(fields, recovered); } else if self.check(&token::OpenDelim(token::Paren)) { - all_nullary = false; struct_def = VariantData::Tuple( self.parse_tuple_struct_body()?, ast::DUMMY_NODE_ID, @@ -7526,16 +7523,7 @@ fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult<'a, EnumDef> } } self.expect(&token::CloseDelim(token::Brace))?; - if !any_disr.is_empty() && !all_nullary { - let mut err = self.struct_span_err( - any_disr.clone(), - "discriminator values can only be used with a field-less enum", - ); - for sp in any_disr { - err.span_label(sp, "only valid in field-less enums"); - } - err.emit(); - } + self.maybe_report_invalid_custom_discriminants(any_disr, &variants); Ok(ast::EnumDef { variants }) } diff --git a/src/test/ui/parser/issue-17383.rs b/src/test/ui/parser/issue-17383.rs index 04cd43d0b10..f95005cd914 100644 --- a/src/test/ui/parser/issue-17383.rs +++ b/src/test/ui/parser/issue-17383.rs @@ -1,6 +1,6 @@ enum X { A = 3, - //~^ ERROR discriminator values can only be used with a field-less enum + //~^ ERROR custom discriminant values are not allowed in enums with fields B(usize) } diff --git a/src/test/ui/parser/issue-17383.stderr b/src/test/ui/parser/issue-17383.stderr index 57caa3372a6..37abd0ff5e1 100644 --- a/src/test/ui/parser/issue-17383.stderr +++ b/src/test/ui/parser/issue-17383.stderr @@ -1,8 +1,11 @@ -error: discriminator values can only be used with a field-less enum +error: custom discriminant values are not allowed in enums with fields --> $DIR/issue-17383.rs:2:9 | LL | A = 3, - | ^ only valid in field-less enums + | ^ invalid custom discriminant +LL | +LL | B(usize) + | -------- variant with a field defined here error: aborting due to previous error diff --git a/src/test/ui/parser/tag-variant-disr-non-nullary.rs b/src/test/ui/parser/tag-variant-disr-non-nullary.rs index 83a3b727982..305edc4ad5a 100644 --- a/src/test/ui/parser/tag-variant-disr-non-nullary.rs +++ b/src/test/ui/parser/tag-variant-disr-non-nullary.rs @@ -1,11 +1,12 @@ enum Color { Red = 0xff0000, - //~^ ERROR discriminator values can only be used with a field-less enum + //~^ ERROR custom discriminant values are not allowed in enums with fields Green = 0x00ff00, Blue = 0x0000ff, Black = 0x000000, White = 0xffffff, Other(usize), + Other2(usize, usize), } fn main() {} diff --git a/src/test/ui/parser/tag-variant-disr-non-nullary.stderr b/src/test/ui/parser/tag-variant-disr-non-nullary.stderr index 884e9672cb1..2d3b2839531 100644 --- a/src/test/ui/parser/tag-variant-disr-non-nullary.stderr +++ b/src/test/ui/parser/tag-variant-disr-non-nullary.stderr @@ -1,17 +1,21 @@ -error: discriminator values can only be used with a field-less enum +error: custom discriminant values are not allowed in enums with fields --> $DIR/tag-variant-disr-non-nullary.rs:2:11 | LL | Red = 0xff0000, - | ^^^^^^^^ only valid in field-less enums + | ^^^^^^^^ invalid custom discriminant LL | LL | Green = 0x00ff00, - | ^^^^^^^^ only valid in field-less enums + | ^^^^^^^^ invalid custom discriminant LL | Blue = 0x0000ff, - | ^^^^^^^^ only valid in field-less enums + | ^^^^^^^^ invalid custom discriminant LL | Black = 0x000000, - | ^^^^^^^^ only valid in field-less enums + | ^^^^^^^^ invalid custom discriminant LL | White = 0xffffff, - | ^^^^^^^^ only valid in field-less enums + | ^^^^^^^^ invalid custom discriminant +LL | Other(usize), + | ------------ variant with a field defined here +LL | Other2(usize, usize), + | -------------------- variant with fields defined here error: aborting due to previous error