Skip to content

Commit 6007e6f

Browse files
committed
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.
1 parent 7cf074a commit 6007e6f

File tree

15 files changed

+108
-57
lines changed

15 files changed

+108
-57
lines changed

src/librustc/hir/lowering.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2672,7 +2672,7 @@ impl<'a> LoweringContext<'a> {
26722672

26732673
fn lower_variant_data(&mut self, vdata: &VariantData) -> hir::VariantData {
26742674
match *vdata {
2675-
VariantData::Struct(ref fields, id) => {
2675+
VariantData::Struct(ref fields, id, recovered) => {
26762676
let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id);
26772677

26782678
hir::VariantData::Struct(
@@ -2682,6 +2682,7 @@ impl<'a> LoweringContext<'a> {
26822682
.map(|f| self.lower_struct_field(f))
26832683
.collect(),
26842684
hir_id,
2685+
recovered,
26852686
)
26862687
},
26872688
VariantData::Tuple(ref fields, id) => {

src/librustc/hir/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2173,7 +2173,7 @@ impl StructField {
21732173
/// Id of the whole struct lives in `Item`.
21742174
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
21752175
pub enum VariantData {
2176-
Struct(HirVec<StructField>, HirId),
2176+
Struct(HirVec<StructField>, HirId, bool),
21772177
Tuple(HirVec<StructField>, HirId),
21782178
Unit(HirId),
21792179
}
@@ -2187,7 +2187,7 @@ impl VariantData {
21872187
}
21882188
pub fn hir_id(&self) -> HirId {
21892189
match *self {
2190-
VariantData::Struct(_, hir_id)
2190+
VariantData::Struct(_, hir_id, _)
21912191
| VariantData::Tuple(_, hir_id)
21922192
| VariantData::Unit(hir_id) => hir_id,
21932193
}

src/librustc/ty/mod.rs

+16-12
Original file line numberDiff line numberDiff line change
@@ -1811,6 +1811,7 @@ pub struct VariantDef {
18111811
pub fields: Vec<FieldDef>,
18121812
pub ctor_kind: CtorKind,
18131813
flags: VariantFlags,
1814+
pub recovered: bool,
18141815
}
18151816

18161817
impl<'a, 'gcx, 'tcx> VariantDef {
@@ -1829,16 +1830,17 @@ impl<'a, 'gcx, 'tcx> VariantDef {
18291830
///
18301831
/// If someone speeds up attribute loading to not be a performance concern, they can
18311832
/// remove this hack and use the constructor `DefId` everywhere.
1832-
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
1833-
did: DefId,
1834-
ident: Ident,
1835-
discr: VariantDiscr,
1836-
fields: Vec<FieldDef>,
1837-
adt_kind: AdtKind,
1838-
ctor_kind: CtorKind,
1839-
attribute_def_id: DefId)
1840-
-> Self
1841-
{
1833+
pub fn new(
1834+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
1835+
did: DefId,
1836+
ident: Ident,
1837+
discr: VariantDiscr,
1838+
fields: Vec<FieldDef>,
1839+
adt_kind: AdtKind,
1840+
ctor_kind: CtorKind,
1841+
attribute_def_id: DefId,
1842+
recovered: bool,
1843+
) -> Self {
18421844
debug!("VariantDef::new({:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?})", did, ident, discr,
18431845
fields, adt_kind, ctor_kind, attribute_def_id);
18441846
let mut flags = VariantFlags::NO_VARIANT_FLAGS;
@@ -1852,7 +1854,8 @@ impl<'a, 'gcx, 'tcx> VariantDef {
18521854
discr,
18531855
fields,
18541856
ctor_kind,
1855-
flags
1857+
flags,
1858+
recovered,
18561859
}
18571860
}
18581861

@@ -1868,7 +1871,8 @@ impl_stable_hash_for!(struct VariantDef {
18681871
discr,
18691872
fields,
18701873
ctor_kind,
1871-
flags
1874+
flags,
1875+
recovered
18721876
});
18731877

18741878
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]

src/librustc_metadata/decoder.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,8 @@ impl<'a, 'tcx> CrateMetadata {
576576
}).collect(),
577577
adt_kind,
578578
data.ctor_kind,
579-
attribute_def_id
579+
attribute_def_id,
580+
false,
580581
)
581582
}
582583

src/librustc_save_analysis/dump_visitor.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -481,8 +481,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
481481
};
482482

483483
let (value, fields) = match item.node {
484-
ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) |
485-
ast::ItemKind::Union(ast::VariantData::Struct(ref fields, _), _) => {
484+
ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, ..), _) |
485+
ast::ItemKind::Union(ast::VariantData::Struct(ref fields, ..), _) => {
486486
let include_priv_fields = !self.save_ctxt.config.pub_only;
487487
let fields_str = fields
488488
.iter()
@@ -560,7 +560,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
560560
let name_span = variant.node.ident.span;
561561

562562
match variant.node.data {
563-
ast::VariantData::Struct(ref fields, _) => {
563+
ast::VariantData::Struct(ref fields, ..) => {
564564
let fields_str = fields
565565
.iter()
566566
.enumerate()

src/librustc_save_analysis/sig.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ impl Sig for ast::Variant_ {
703703
fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
704704
let mut text = self.ident.to_string();
705705
match self.data {
706-
ast::VariantData::Struct(ref fields, id) => {
706+
ast::VariantData::Struct(ref fields, id, r) => {
707707
let name_def = SigElement {
708708
id: id_from_node_id(id, scx),
709709
start: offset,
@@ -712,12 +712,16 @@ impl Sig for ast::Variant_ {
712712
text.push_str(" { ");
713713
let mut defs = vec![name_def];
714714
let mut refs = vec![];
715-
for f in fields {
716-
let field_sig = f.make(offset + text.len(), Some(id), scx)?;
717-
text.push_str(&field_sig.text);
718-
text.push_str(", ");
719-
defs.extend(field_sig.defs.into_iter());
720-
refs.extend(field_sig.refs.into_iter());
715+
if r {
716+
text.push_str("/* parse error */ ");
717+
} else {
718+
for f in fields {
719+
let field_sig = f.make(offset + text.len(), Some(id), scx)?;
720+
text.push_str(&field_sig.text);
721+
text.push_str(", ");
722+
defs.extend(field_sig.defs.into_iter());
723+
refs.extend(field_sig.refs.into_iter());
724+
}
721725
}
722726
text.push('}');
723727
Ok(Signature { text, defs, refs })

src/librustc_typeck/check/_match.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -918,14 +918,16 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
918918
pat_ty
919919
}
920920

921-
fn check_struct_pat_fields(&self,
922-
adt_ty: Ty<'tcx>,
923-
pat_id: hir::HirId,
924-
span: Span,
925-
variant: &'tcx ty::VariantDef,
926-
fields: &'gcx [Spanned<hir::FieldPat>],
927-
etc: bool,
928-
def_bm: ty::BindingMode) -> bool {
921+
fn check_struct_pat_fields(
922+
&self,
923+
adt_ty: Ty<'tcx>,
924+
pat_id: hir::HirId,
925+
span: Span,
926+
variant: &'tcx ty::VariantDef,
927+
fields: &'gcx [Spanned<hir::FieldPat>],
928+
etc: bool,
929+
def_bm: ty::BindingMode,
930+
) -> bool {
929931
let tcx = self.tcx;
930932

931933
let (substs, adt) = match adt_ty.sty {
@@ -985,7 +987,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
985987
.map(|field| field.ident.modern())
986988
.filter(|ident| !used_fields.contains_key(&ident))
987989
.collect::<Vec<_>>();
988-
if inexistent_fields.len() > 0 {
990+
if inexistent_fields.len() > 0 && !variant.recovered {
989991
let (field_names, t, plural) = if inexistent_fields.len() == 1 {
990992
(format!("a field named `{}`", inexistent_fields[0].1), "this", "")
991993
} else {

src/librustc_typeck/check/mod.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -3689,12 +3689,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
36893689
field, expr_t)
36903690
}
36913691

3692-
fn report_unknown_field(&self,
3693-
ty: Ty<'tcx>,
3694-
variant: &'tcx ty::VariantDef,
3695-
field: &hir::Field,
3696-
skip_fields: &[hir::Field],
3697-
kind_name: &str) {
3692+
fn report_unknown_field(
3693+
&self,
3694+
ty: Ty<'tcx>,
3695+
variant: &'tcx ty::VariantDef,
3696+
field: &hir::Field,
3697+
skip_fields: &[hir::Field],
3698+
kind_name: &str,
3699+
) {
3700+
if variant.recovered {
3701+
return;
3702+
}
36983703
let mut err = self.type_error_struct_with_diag(
36993704
field.ident.span,
37003705
|actual| match ty.sty {

src/librustc_typeck/collect.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -598,14 +598,19 @@ fn convert_variant<'a, 'tcx>(
598598
}
599599
})
600600
.collect();
601+
let recovered = match def {
602+
hir::VariantData::Struct(_, _, r) => *r,
603+
_ => false,
604+
};
601605
ty::VariantDef::new(tcx,
602606
did,
603607
ident,
604608
discr,
605609
fields,
606610
adt_kind,
607611
CtorKind::from_hir(def),
608-
attribute_def_id
612+
attribute_def_id,
613+
recovered,
609614
)
610615
}
611616

src/libsyntax/ast.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2133,7 +2133,7 @@ pub enum VariantData {
21332133
/// Struct variant.
21342134
///
21352135
/// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
2136-
Struct(Vec<StructField>, NodeId),
2136+
Struct(Vec<StructField>, NodeId, bool),
21372137
/// Tuple variant.
21382138
///
21392139
/// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
@@ -2147,13 +2147,13 @@ pub enum VariantData {
21472147
impl VariantData {
21482148
pub fn fields(&self) -> &[StructField] {
21492149
match *self {
2150-
VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => fields,
2150+
VariantData::Struct(ref fields, ..) | VariantData::Tuple(ref fields, _) => fields,
21512151
_ => &[],
21522152
}
21532153
}
21542154
pub fn id(&self) -> NodeId {
21552155
match *self {
2156-
VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id,
2156+
VariantData::Struct(_, id, _) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id,
21572157
}
21582158
}
21592159
pub fn is_struct(&self) -> bool {

src/libsyntax/config.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ impl<'a> StripUnconfigured<'a> {
225225

226226
fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) {
227227
match vdata {
228-
ast::VariantData::Struct(fields, _id) |
228+
ast::VariantData::Struct(fields, _id, _) |
229229
ast::VariantData::Tuple(fields, _id) =>
230230
fields.flat_map_in_place(|field| self.configure(field)),
231231
ast::VariantData::Unit(_id) => {}

src/libsyntax/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,7 @@ pub fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis:
765765

766766
pub fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut T) {
767767
match vdata {
768-
VariantData::Struct(fields, id) |
768+
VariantData::Struct(fields, id, _) |
769769
VariantData::Tuple(fields, id) => {
770770
visit_vec(fields, |field| vis.visit_struct_field(field));
771771
vis.visit_id(id);

src/libsyntax/parse/parser.rs

+18-10
Original file line numberDiff line numberDiff line change
@@ -6829,14 +6829,16 @@ impl<'a> Parser<'a> {
68296829
VariantData::Unit(ast::DUMMY_NODE_ID)
68306830
} else {
68316831
// If we see: `struct Foo<T> where T: Copy { ... }`
6832-
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
6832+
let (fields, recovered) = self.parse_record_struct_body()?;
6833+
VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
68336834
}
68346835
// No `where` so: `struct Foo<T>;`
68356836
} else if self.eat(&token::Semi) {
68366837
VariantData::Unit(ast::DUMMY_NODE_ID)
68376838
// Record-style struct definition
68386839
} else if self.token == token::OpenDelim(token::Brace) {
6839-
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
6840+
let (fields, recovered) = self.parse_record_struct_body()?;
6841+
VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
68406842
// Tuple-style struct definition with optional where-clause.
68416843
} else if self.token == token::OpenDelim(token::Paren) {
68426844
let body = VariantData::Tuple(self.parse_tuple_struct_body()?, ast::DUMMY_NODE_ID);
@@ -6864,9 +6866,11 @@ impl<'a> Parser<'a> {
68646866

68656867
let vdata = if self.token.is_keyword(keywords::Where) {
68666868
generics.where_clause = self.parse_where_clause()?;
6867-
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
6869+
let (fields, recovered) = self.parse_record_struct_body()?;
6870+
VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
68686871
} else if self.token == token::OpenDelim(token::Brace) {
6869-
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
6872+
let (fields, recovered) = self.parse_record_struct_body()?;
6873+
VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
68706874
} else {
68716875
let token_str = self.this_token_descr();
68726876
let mut err = self.fatal(&format!(
@@ -6898,12 +6902,14 @@ impl<'a> Parser<'a> {
68986902
}
68996903
}
69006904

6901-
fn parse_record_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
6905+
fn parse_record_struct_body(&mut self) -> PResult<'a, (Vec<StructField>, bool)> {
69026906
let mut fields = Vec::new();
6907+
let mut recovered = false;
69036908
if self.eat(&token::OpenDelim(token::Brace)) {
69046909
while self.token != token::CloseDelim(token::Brace) {
69056910
let field = self.parse_struct_decl_field().map_err(|e| {
69066911
self.recover_stmt();
6912+
recovered = true;
69076913
e
69086914
});
69096915
match field {
@@ -6922,7 +6928,7 @@ impl<'a> Parser<'a> {
69226928
return Err(err);
69236929
}
69246930

6925-
Ok(fields)
6931+
Ok((fields, recovered))
69266932
}
69276933

69286934
fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
@@ -7684,12 +7690,14 @@ impl<'a> Parser<'a> {
76847690
if self.check(&token::OpenDelim(token::Brace)) {
76857691
// Parse a struct variant.
76867692
all_nullary = false;
7687-
struct_def = VariantData::Struct(self.parse_record_struct_body()?,
7688-
ast::DUMMY_NODE_ID);
7693+
let (fields, recovered) = self.parse_record_struct_body()?;
7694+
struct_def = VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered);
76897695
} else if self.check(&token::OpenDelim(token::Paren)) {
76907696
all_nullary = false;
7691-
struct_def = VariantData::Tuple(self.parse_tuple_struct_body()?,
7692-
ast::DUMMY_NODE_ID);
7697+
struct_def = VariantData::Tuple(
7698+
self.parse_tuple_struct_body()?,
7699+
ast::DUMMY_NODE_ID,
7700+
);
76937701
} else if self.eat(&token::Eq) {
76947702
disr_expr = Some(AnonConst {
76957703
id: ast::DUMMY_NODE_ID,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
enum Foo {
2+
A { a, b: usize }
3+
//~^ ERROR expected `:`, found `,`
4+
}
5+
6+
fn main() {
7+
// no complaints about non-existing fields
8+
let f = Foo::A { a:3, b: 4};
9+
match f {
10+
// no complaints about non-existing fields
11+
Foo::A {a, b} => {}
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: expected `:`, found `,`
2+
--> $DIR/recovered-struct-variant.rs:2:10
3+
|
4+
LL | A { a, b: usize }
5+
| ^ expected `:`
6+
7+
error: aborting due to previous error
8+

0 commit comments

Comments
 (0)