mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 15:01:51 +00:00
Do not complain about non-existing fields after parse recovery
When failing to parse struct-like enum variants, the ADT gets recorded as having no fields. Record that we have actually recovered during parsing of this variant to avoid complaing about non-existing fields when actually using it.
This commit is contained in:
parent
7cf074a1e6
commit
6007e6f649
@ -2672,7 +2672,7 @@ impl<'a> LoweringContext<'a> {
|
|||||||
|
|
||||||
fn lower_variant_data(&mut self, vdata: &VariantData) -> hir::VariantData {
|
fn lower_variant_data(&mut self, vdata: &VariantData) -> hir::VariantData {
|
||||||
match *vdata {
|
match *vdata {
|
||||||
VariantData::Struct(ref fields, id) => {
|
VariantData::Struct(ref fields, id, recovered) => {
|
||||||
let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id);
|
let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id);
|
||||||
|
|
||||||
hir::VariantData::Struct(
|
hir::VariantData::Struct(
|
||||||
@ -2682,6 +2682,7 @@ impl<'a> LoweringContext<'a> {
|
|||||||
.map(|f| self.lower_struct_field(f))
|
.map(|f| self.lower_struct_field(f))
|
||||||
.collect(),
|
.collect(),
|
||||||
hir_id,
|
hir_id,
|
||||||
|
recovered,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
VariantData::Tuple(ref fields, id) => {
|
VariantData::Tuple(ref fields, id) => {
|
||||||
|
@ -2173,7 +2173,7 @@ impl StructField {
|
|||||||
/// Id of the whole struct lives in `Item`.
|
/// Id of the whole struct lives in `Item`.
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||||
pub enum VariantData {
|
pub enum VariantData {
|
||||||
Struct(HirVec<StructField>, HirId),
|
Struct(HirVec<StructField>, HirId, bool),
|
||||||
Tuple(HirVec<StructField>, HirId),
|
Tuple(HirVec<StructField>, HirId),
|
||||||
Unit(HirId),
|
Unit(HirId),
|
||||||
}
|
}
|
||||||
@ -2187,7 +2187,7 @@ impl VariantData {
|
|||||||
}
|
}
|
||||||
pub fn hir_id(&self) -> HirId {
|
pub fn hir_id(&self) -> HirId {
|
||||||
match *self {
|
match *self {
|
||||||
VariantData::Struct(_, hir_id)
|
VariantData::Struct(_, hir_id, _)
|
||||||
| VariantData::Tuple(_, hir_id)
|
| VariantData::Tuple(_, hir_id)
|
||||||
| VariantData::Unit(hir_id) => hir_id,
|
| VariantData::Unit(hir_id) => hir_id,
|
||||||
}
|
}
|
||||||
|
@ -1811,6 +1811,7 @@ pub struct VariantDef {
|
|||||||
pub fields: Vec<FieldDef>,
|
pub fields: Vec<FieldDef>,
|
||||||
pub ctor_kind: CtorKind,
|
pub ctor_kind: CtorKind,
|
||||||
flags: VariantFlags,
|
flags: VariantFlags,
|
||||||
|
pub recovered: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> VariantDef {
|
impl<'a, 'gcx, 'tcx> VariantDef {
|
||||||
@ -1829,16 +1830,17 @@ impl<'a, 'gcx, 'tcx> VariantDef {
|
|||||||
///
|
///
|
||||||
/// If someone speeds up attribute loading to not be a performance concern, they can
|
/// If someone speeds up attribute loading to not be a performance concern, they can
|
||||||
/// remove this hack and use the constructor `DefId` everywhere.
|
/// remove this hack and use the constructor `DefId` everywhere.
|
||||||
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
pub fn new(
|
||||||
did: DefId,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
ident: Ident,
|
did: DefId,
|
||||||
discr: VariantDiscr,
|
ident: Ident,
|
||||||
fields: Vec<FieldDef>,
|
discr: VariantDiscr,
|
||||||
adt_kind: AdtKind,
|
fields: Vec<FieldDef>,
|
||||||
ctor_kind: CtorKind,
|
adt_kind: AdtKind,
|
||||||
attribute_def_id: DefId)
|
ctor_kind: CtorKind,
|
||||||
-> Self
|
attribute_def_id: DefId,
|
||||||
{
|
recovered: bool,
|
||||||
|
) -> Self {
|
||||||
debug!("VariantDef::new({:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?})", did, ident, discr,
|
debug!("VariantDef::new({:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?})", did, ident, discr,
|
||||||
fields, adt_kind, ctor_kind, attribute_def_id);
|
fields, adt_kind, ctor_kind, attribute_def_id);
|
||||||
let mut flags = VariantFlags::NO_VARIANT_FLAGS;
|
let mut flags = VariantFlags::NO_VARIANT_FLAGS;
|
||||||
@ -1852,7 +1854,8 @@ impl<'a, 'gcx, 'tcx> VariantDef {
|
|||||||
discr,
|
discr,
|
||||||
fields,
|
fields,
|
||||||
ctor_kind,
|
ctor_kind,
|
||||||
flags
|
flags,
|
||||||
|
recovered,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1868,7 +1871,8 @@ impl_stable_hash_for!(struct VariantDef {
|
|||||||
discr,
|
discr,
|
||||||
fields,
|
fields,
|
||||||
ctor_kind,
|
ctor_kind,
|
||||||
flags
|
flags,
|
||||||
|
recovered
|
||||||
});
|
});
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
|
||||||
|
@ -576,7 +576,8 @@ impl<'a, 'tcx> CrateMetadata {
|
|||||||
}).collect(),
|
}).collect(),
|
||||||
adt_kind,
|
adt_kind,
|
||||||
data.ctor_kind,
|
data.ctor_kind,
|
||||||
attribute_def_id
|
attribute_def_id,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,8 +481,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (value, fields) = match item.node {
|
let (value, fields) = match item.node {
|
||||||
ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) |
|
ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, ..), _) |
|
||||||
ast::ItemKind::Union(ast::VariantData::Struct(ref fields, _), _) => {
|
ast::ItemKind::Union(ast::VariantData::Struct(ref fields, ..), _) => {
|
||||||
let include_priv_fields = !self.save_ctxt.config.pub_only;
|
let include_priv_fields = !self.save_ctxt.config.pub_only;
|
||||||
let fields_str = fields
|
let fields_str = fields
|
||||||
.iter()
|
.iter()
|
||||||
@ -560,7 +560,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
|||||||
let name_span = variant.node.ident.span;
|
let name_span = variant.node.ident.span;
|
||||||
|
|
||||||
match variant.node.data {
|
match variant.node.data {
|
||||||
ast::VariantData::Struct(ref fields, _) => {
|
ast::VariantData::Struct(ref fields, ..) => {
|
||||||
let fields_str = fields
|
let fields_str = fields
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -703,7 +703,7 @@ impl Sig for ast::Variant_ {
|
|||||||
fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
|
fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
|
||||||
let mut text = self.ident.to_string();
|
let mut text = self.ident.to_string();
|
||||||
match self.data {
|
match self.data {
|
||||||
ast::VariantData::Struct(ref fields, id) => {
|
ast::VariantData::Struct(ref fields, id, r) => {
|
||||||
let name_def = SigElement {
|
let name_def = SigElement {
|
||||||
id: id_from_node_id(id, scx),
|
id: id_from_node_id(id, scx),
|
||||||
start: offset,
|
start: offset,
|
||||||
@ -712,12 +712,16 @@ impl Sig for ast::Variant_ {
|
|||||||
text.push_str(" { ");
|
text.push_str(" { ");
|
||||||
let mut defs = vec![name_def];
|
let mut defs = vec![name_def];
|
||||||
let mut refs = vec![];
|
let mut refs = vec![];
|
||||||
for f in fields {
|
if r {
|
||||||
let field_sig = f.make(offset + text.len(), Some(id), scx)?;
|
text.push_str("/* parse error */ ");
|
||||||
text.push_str(&field_sig.text);
|
} else {
|
||||||
text.push_str(", ");
|
for f in fields {
|
||||||
defs.extend(field_sig.defs.into_iter());
|
let field_sig = f.make(offset + text.len(), Some(id), scx)?;
|
||||||
refs.extend(field_sig.refs.into_iter());
|
text.push_str(&field_sig.text);
|
||||||
|
text.push_str(", ");
|
||||||
|
defs.extend(field_sig.defs.into_iter());
|
||||||
|
refs.extend(field_sig.refs.into_iter());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
text.push('}');
|
text.push('}');
|
||||||
Ok(Signature { text, defs, refs })
|
Ok(Signature { text, defs, refs })
|
||||||
|
@ -918,14 +918,16 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
|
|||||||
pat_ty
|
pat_ty
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_struct_pat_fields(&self,
|
fn check_struct_pat_fields(
|
||||||
adt_ty: Ty<'tcx>,
|
&self,
|
||||||
pat_id: hir::HirId,
|
adt_ty: Ty<'tcx>,
|
||||||
span: Span,
|
pat_id: hir::HirId,
|
||||||
variant: &'tcx ty::VariantDef,
|
span: Span,
|
||||||
fields: &'gcx [Spanned<hir::FieldPat>],
|
variant: &'tcx ty::VariantDef,
|
||||||
etc: bool,
|
fields: &'gcx [Spanned<hir::FieldPat>],
|
||||||
def_bm: ty::BindingMode) -> bool {
|
etc: bool,
|
||||||
|
def_bm: ty::BindingMode,
|
||||||
|
) -> bool {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
let (substs, adt) = match adt_ty.sty {
|
let (substs, adt) = match adt_ty.sty {
|
||||||
@ -985,7 +987,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
|
|||||||
.map(|field| field.ident.modern())
|
.map(|field| field.ident.modern())
|
||||||
.filter(|ident| !used_fields.contains_key(&ident))
|
.filter(|ident| !used_fields.contains_key(&ident))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if inexistent_fields.len() > 0 {
|
if inexistent_fields.len() > 0 && !variant.recovered {
|
||||||
let (field_names, t, plural) = if inexistent_fields.len() == 1 {
|
let (field_names, t, plural) = if inexistent_fields.len() == 1 {
|
||||||
(format!("a field named `{}`", inexistent_fields[0].1), "this", "")
|
(format!("a field named `{}`", inexistent_fields[0].1), "this", "")
|
||||||
} else {
|
} else {
|
||||||
|
@ -3689,12 +3689,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
field, expr_t)
|
field, expr_t)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_unknown_field(&self,
|
fn report_unknown_field(
|
||||||
ty: Ty<'tcx>,
|
&self,
|
||||||
variant: &'tcx ty::VariantDef,
|
ty: Ty<'tcx>,
|
||||||
field: &hir::Field,
|
variant: &'tcx ty::VariantDef,
|
||||||
skip_fields: &[hir::Field],
|
field: &hir::Field,
|
||||||
kind_name: &str) {
|
skip_fields: &[hir::Field],
|
||||||
|
kind_name: &str,
|
||||||
|
) {
|
||||||
|
if variant.recovered {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let mut err = self.type_error_struct_with_diag(
|
let mut err = self.type_error_struct_with_diag(
|
||||||
field.ident.span,
|
field.ident.span,
|
||||||
|actual| match ty.sty {
|
|actual| match ty.sty {
|
||||||
|
@ -598,6 +598,10 @@ fn convert_variant<'a, 'tcx>(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
let recovered = match def {
|
||||||
|
hir::VariantData::Struct(_, _, r) => *r,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
ty::VariantDef::new(tcx,
|
ty::VariantDef::new(tcx,
|
||||||
did,
|
did,
|
||||||
ident,
|
ident,
|
||||||
@ -605,7 +609,8 @@ fn convert_variant<'a, 'tcx>(
|
|||||||
fields,
|
fields,
|
||||||
adt_kind,
|
adt_kind,
|
||||||
CtorKind::from_hir(def),
|
CtorKind::from_hir(def),
|
||||||
attribute_def_id
|
attribute_def_id,
|
||||||
|
recovered,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2133,7 +2133,7 @@ pub enum VariantData {
|
|||||||
/// Struct variant.
|
/// Struct variant.
|
||||||
///
|
///
|
||||||
/// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
|
/// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
|
||||||
Struct(Vec<StructField>, NodeId),
|
Struct(Vec<StructField>, NodeId, bool),
|
||||||
/// Tuple variant.
|
/// Tuple variant.
|
||||||
///
|
///
|
||||||
/// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
|
/// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
|
||||||
@ -2147,13 +2147,13 @@ pub enum VariantData {
|
|||||||
impl VariantData {
|
impl VariantData {
|
||||||
pub fn fields(&self) -> &[StructField] {
|
pub fn fields(&self) -> &[StructField] {
|
||||||
match *self {
|
match *self {
|
||||||
VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => fields,
|
VariantData::Struct(ref fields, ..) | VariantData::Tuple(ref fields, _) => fields,
|
||||||
_ => &[],
|
_ => &[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn id(&self) -> NodeId {
|
pub fn id(&self) -> NodeId {
|
||||||
match *self {
|
match *self {
|
||||||
VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id,
|
VariantData::Struct(_, id, _) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn is_struct(&self) -> bool {
|
pub fn is_struct(&self) -> bool {
|
||||||
|
@ -225,7 +225,7 @@ impl<'a> StripUnconfigured<'a> {
|
|||||||
|
|
||||||
fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) {
|
fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) {
|
||||||
match vdata {
|
match vdata {
|
||||||
ast::VariantData::Struct(fields, _id) |
|
ast::VariantData::Struct(fields, _id, _) |
|
||||||
ast::VariantData::Tuple(fields, _id) =>
|
ast::VariantData::Tuple(fields, _id) =>
|
||||||
fields.flat_map_in_place(|field| self.configure(field)),
|
fields.flat_map_in_place(|field| self.configure(field)),
|
||||||
ast::VariantData::Unit(_id) => {}
|
ast::VariantData::Unit(_id) => {}
|
||||||
|
@ -765,7 +765,7 @@ pub fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis:
|
|||||||
|
|
||||||
pub fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut T) {
|
pub fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut T) {
|
||||||
match vdata {
|
match vdata {
|
||||||
VariantData::Struct(fields, id) |
|
VariantData::Struct(fields, id, _) |
|
||||||
VariantData::Tuple(fields, id) => {
|
VariantData::Tuple(fields, id) => {
|
||||||
visit_vec(fields, |field| vis.visit_struct_field(field));
|
visit_vec(fields, |field| vis.visit_struct_field(field));
|
||||||
vis.visit_id(id);
|
vis.visit_id(id);
|
||||||
|
@ -6829,14 +6829,16 @@ impl<'a> Parser<'a> {
|
|||||||
VariantData::Unit(ast::DUMMY_NODE_ID)
|
VariantData::Unit(ast::DUMMY_NODE_ID)
|
||||||
} else {
|
} else {
|
||||||
// If we see: `struct Foo<T> where T: Copy { ... }`
|
// If we see: `struct Foo<T> where T: Copy { ... }`
|
||||||
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
|
let (fields, recovered) = self.parse_record_struct_body()?;
|
||||||
|
VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
|
||||||
}
|
}
|
||||||
// No `where` so: `struct Foo<T>;`
|
// No `where` so: `struct Foo<T>;`
|
||||||
} else if self.eat(&token::Semi) {
|
} else if self.eat(&token::Semi) {
|
||||||
VariantData::Unit(ast::DUMMY_NODE_ID)
|
VariantData::Unit(ast::DUMMY_NODE_ID)
|
||||||
// Record-style struct definition
|
// Record-style struct definition
|
||||||
} else if self.token == token::OpenDelim(token::Brace) {
|
} else if self.token == token::OpenDelim(token::Brace) {
|
||||||
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
|
let (fields, recovered) = self.parse_record_struct_body()?;
|
||||||
|
VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
|
||||||
// Tuple-style struct definition with optional where-clause.
|
// Tuple-style struct definition with optional where-clause.
|
||||||
} else if self.token == token::OpenDelim(token::Paren) {
|
} else if self.token == token::OpenDelim(token::Paren) {
|
||||||
let body = VariantData::Tuple(self.parse_tuple_struct_body()?, ast::DUMMY_NODE_ID);
|
let body = VariantData::Tuple(self.parse_tuple_struct_body()?, ast::DUMMY_NODE_ID);
|
||||||
@ -6864,9 +6866,11 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
let vdata = if self.token.is_keyword(keywords::Where) {
|
let vdata = if self.token.is_keyword(keywords::Where) {
|
||||||
generics.where_clause = self.parse_where_clause()?;
|
generics.where_clause = self.parse_where_clause()?;
|
||||||
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
|
let (fields, recovered) = self.parse_record_struct_body()?;
|
||||||
|
VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
|
||||||
} else if self.token == token::OpenDelim(token::Brace) {
|
} else if self.token == token::OpenDelim(token::Brace) {
|
||||||
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
|
let (fields, recovered) = self.parse_record_struct_body()?;
|
||||||
|
VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
|
||||||
} else {
|
} else {
|
||||||
let token_str = self.this_token_descr();
|
let token_str = self.this_token_descr();
|
||||||
let mut err = self.fatal(&format!(
|
let mut err = self.fatal(&format!(
|
||||||
@ -6898,12 +6902,14 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_record_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
|
fn parse_record_struct_body(&mut self) -> PResult<'a, (Vec<StructField>, bool)> {
|
||||||
let mut fields = Vec::new();
|
let mut fields = Vec::new();
|
||||||
|
let mut recovered = false;
|
||||||
if self.eat(&token::OpenDelim(token::Brace)) {
|
if self.eat(&token::OpenDelim(token::Brace)) {
|
||||||
while self.token != token::CloseDelim(token::Brace) {
|
while self.token != token::CloseDelim(token::Brace) {
|
||||||
let field = self.parse_struct_decl_field().map_err(|e| {
|
let field = self.parse_struct_decl_field().map_err(|e| {
|
||||||
self.recover_stmt();
|
self.recover_stmt();
|
||||||
|
recovered = true;
|
||||||
e
|
e
|
||||||
});
|
});
|
||||||
match field {
|
match field {
|
||||||
@ -6922,7 +6928,7 @@ impl<'a> Parser<'a> {
|
|||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(fields)
|
Ok((fields, recovered))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
|
fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
|
||||||
@ -7684,12 +7690,14 @@ impl<'a> Parser<'a> {
|
|||||||
if self.check(&token::OpenDelim(token::Brace)) {
|
if self.check(&token::OpenDelim(token::Brace)) {
|
||||||
// Parse a struct variant.
|
// Parse a struct variant.
|
||||||
all_nullary = false;
|
all_nullary = false;
|
||||||
struct_def = VariantData::Struct(self.parse_record_struct_body()?,
|
let (fields, recovered) = self.parse_record_struct_body()?;
|
||||||
ast::DUMMY_NODE_ID);
|
struct_def = VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered);
|
||||||
} else if self.check(&token::OpenDelim(token::Paren)) {
|
} else if self.check(&token::OpenDelim(token::Paren)) {
|
||||||
all_nullary = false;
|
all_nullary = false;
|
||||||
struct_def = VariantData::Tuple(self.parse_tuple_struct_body()?,
|
struct_def = VariantData::Tuple(
|
||||||
ast::DUMMY_NODE_ID);
|
self.parse_tuple_struct_body()?,
|
||||||
|
ast::DUMMY_NODE_ID,
|
||||||
|
);
|
||||||
} else if self.eat(&token::Eq) {
|
} else if self.eat(&token::Eq) {
|
||||||
disr_expr = Some(AnonConst {
|
disr_expr = Some(AnonConst {
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
13
src/test/ui/parser/recovered-struct-variant.rs
Normal file
13
src/test/ui/parser/recovered-struct-variant.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
enum Foo {
|
||||||
|
A { a, b: usize }
|
||||||
|
//~^ ERROR expected `:`, found `,`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// no complaints about non-existing fields
|
||||||
|
let f = Foo::A { a:3, b: 4};
|
||||||
|
match f {
|
||||||
|
// no complaints about non-existing fields
|
||||||
|
Foo::A {a, b} => {}
|
||||||
|
}
|
||||||
|
}
|
8
src/test/ui/parser/recovered-struct-variant.stderr
Normal file
8
src/test/ui/parser/recovered-struct-variant.stderr
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
error: expected `:`, found `,`
|
||||||
|
--> $DIR/recovered-struct-variant.rs:2:10
|
||||||
|
|
|
||||||
|
LL | A { a, b: usize }
|
||||||
|
| ^ expected `:`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Reference in New Issue
Block a user