Skip to content

Commit 17651e3

Browse files
committed
report pat no field error no recoverd struct variant
1 parent 35b658f commit 17651e3

File tree

9 files changed

+141
-20
lines changed

9 files changed

+141
-20
lines changed

compiler/rustc_hir_analysis/src/collect.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,10 @@ fn lower_variant(
10911091
vis: tcx.visibility(f.def_id),
10921092
})
10931093
.collect();
1094-
let recovered = matches!(def, hir::VariantData::Struct { recovered: Recovered::Yes(_), .. });
1094+
let recovered = match def {
1095+
hir::VariantData::Struct { recovered: Recovered::Yes(guard), .. } => Some(guard).copied(),
1096+
_ => None,
1097+
};
10951098
ty::VariantDef::new(
10961099
ident.name,
10971100
variant_did.map(LocalDefId::to_def_id),

compiler/rustc_hir_typeck/src/expr.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -2177,11 +2177,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21772177
skip_fields: &[hir::ExprField<'_>],
21782178
kind_name: &str,
21792179
) -> ErrorGuaranteed {
2180-
if variant.is_recovered() {
2181-
let guar =
2182-
self.dcx().span_delayed_bug(expr.span, "parser recovered but no error was emitted");
2183-
self.set_tainted_by_errors(guar);
2184-
return guar;
2180+
if let Some(guaranteed) = variant.has_errors() {
2181+
return guaranteed;
21852182
}
21862183
let mut err = self.err_ctxt().type_error_struct_with_diag(
21872184
field.ident.span,
@@ -2547,6 +2544,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25472544
"ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, base_ty={:?}",
25482545
ident, base, expr, base_ty
25492546
);
2547+
2548+
for (ty, _) in self.autoderef(expr.span, base_ty) {
2549+
if let ty::Adt(def, _) = ty.kind()
2550+
&& !def.is_enum()
2551+
{
2552+
let variant = def.non_enum_variant();
2553+
if let Some(taint) = variant.has_errors() {
2554+
return taint;
2555+
}
2556+
}
2557+
}
2558+
25502559
let mut err = self.no_such_field_err(ident, base_ty, base.hir_id);
25512560

25522561
match *base_ty.peel_refs().kind() {

compiler/rustc_hir_typeck/src/pat.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1531,9 +1531,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15311531
.filter(|(_, ident)| !used_fields.contains_key(ident))
15321532
.collect::<Vec<_>>();
15331533

1534-
let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered())
1534+
let inexistent_fields_err = if !inexistent_fields.is_empty()
15351535
&& !inexistent_fields.iter().any(|field| field.ident.name == kw::Underscore)
15361536
{
1537+
if let Some(guard) = variant.has_errors() {
1538+
return Err(guard);
1539+
}
15371540
Some(self.error_inexistent_fields(
15381541
adt.variant_descr(),
15391542
&inexistent_fields,
@@ -1812,6 +1815,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18121815
return Ok(());
18131816
}
18141817

1818+
if let Some(guaranteed) = variant.has_errors() {
1819+
return Err(guaranteed);
1820+
}
1821+
18151822
let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
18161823
let mut err = struct_span_code_err!(
18171824
self.dcx(),

compiler/rustc_metadata/src/rmeta/decoder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
11331133
.collect(),
11341134
adt_kind,
11351135
parent_did,
1136-
false,
1136+
None,
11371137
data.is_non_exhaustive,
11381138
// FIXME: unnamed fields in crate metadata is unimplemented yet.
11391139
false,

compiler/rustc_middle/src/ty/mod.rs

+37-12
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,8 @@ pub struct VariantDef {
11831183
pub discr: VariantDiscr,
11841184
/// Fields of this variant.
11851185
pub fields: IndexVec<FieldIdx, FieldDef>,
1186+
/// The error guarantees from parser, if any.
1187+
tainted: Option<ErrorGuaranteed>,
11861188
/// Flags of the variant (e.g. is field list non-exhaustive)?
11871189
flags: VariantFlags,
11881190
}
@@ -1212,7 +1214,7 @@ impl VariantDef {
12121214
fields: IndexVec<FieldIdx, FieldDef>,
12131215
adt_kind: AdtKind,
12141216
parent_did: DefId,
1215-
recovered: bool,
1217+
recover_tainted: Option<ErrorGuaranteed>,
12161218
is_field_list_non_exhaustive: bool,
12171219
has_unnamed_fields: bool,
12181220
) -> Self {
@@ -1227,15 +1229,23 @@ impl VariantDef {
12271229
flags |= VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
12281230
}
12291231

1230-
if recovered {
1232+
if recover_tainted.is_some() {
12311233
flags |= VariantFlags::IS_RECOVERED;
12321234
}
12331235

12341236
if has_unnamed_fields {
12351237
flags |= VariantFlags::HAS_UNNAMED_FIELDS;
12361238
}
12371239

1238-
VariantDef { def_id: variant_did.unwrap_or(parent_did), ctor, name, discr, fields, flags }
1240+
VariantDef {
1241+
def_id: variant_did.unwrap_or(parent_did),
1242+
ctor,
1243+
name,
1244+
discr,
1245+
fields,
1246+
flags,
1247+
tainted: recover_tainted,
1248+
}
12391249
}
12401250

12411251
/// Is this field list non-exhaustive?
@@ -1244,12 +1254,6 @@ impl VariantDef {
12441254
self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE)
12451255
}
12461256

1247-
/// Was this variant obtained as part of recovering from a syntactic error?
1248-
#[inline]
1249-
pub fn is_recovered(&self) -> bool {
1250-
self.flags.intersects(VariantFlags::IS_RECOVERED)
1251-
}
1252-
12531257
/// Does this variant contains unnamed fields
12541258
#[inline]
12551259
pub fn has_unnamed_fields(&self) -> bool {
@@ -1261,6 +1265,11 @@ impl VariantDef {
12611265
Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
12621266
}
12631267

1268+
/// Was this variant obtained as part of recovering from a syntactic error?
1269+
pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1270+
self.tainted
1271+
}
1272+
12641273
#[inline]
12651274
pub fn ctor_kind(&self) -> Option<CtorKind> {
12661275
self.ctor.map(|(kind, _)| kind)
@@ -1308,8 +1317,24 @@ impl PartialEq for VariantDef {
13081317
// definition of `VariantDef` changes, a compile-error will be produced,
13091318
// reminding us to revisit this assumption.
13101319

1311-
let Self { def_id: lhs_def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = &self;
1312-
let Self { def_id: rhs_def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = other;
1320+
let Self {
1321+
def_id: lhs_def_id,
1322+
ctor: _,
1323+
name: _,
1324+
discr: _,
1325+
fields: _,
1326+
flags: _,
1327+
tainted: _,
1328+
} = &self;
1329+
let Self {
1330+
def_id: rhs_def_id,
1331+
ctor: _,
1332+
name: _,
1333+
discr: _,
1334+
fields: _,
1335+
flags: _,
1336+
tainted: _,
1337+
} = other;
13131338

13141339
let res = lhs_def_id == rhs_def_id;
13151340

@@ -1339,7 +1364,7 @@ impl Hash for VariantDef {
13391364
// of `VariantDef` changes, a compile-error will be produced, reminding
13401365
// us to revisit this assumption.
13411366

1342-
let Self { def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = &self;
1367+
let Self { def_id, ctor: _, name: _, discr: _, fields: _, flags: _, tainted: _ } = &self;
13431368
def_id.hash(s)
13441369
}
13451370
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
struct Wrong {
2+
x: i32; //~ ERROR struct fields are separated by `,`
3+
y: i32,
4+
z: i32,
5+
h: i32,
6+
}
7+
8+
fn oops(w: &Wrong) {
9+
w.x;
10+
}
11+
12+
fn foo(w: &Wrong) {
13+
w.y;
14+
}
15+
16+
fn haha(w: &Wrong) {
17+
w.z;
18+
}
19+
20+
struct WrongWithType {
21+
x: 1, //~ ERROR expected type, found `1`
22+
y: i32,
23+
z: i32,
24+
h: i32,
25+
}
26+
27+
fn oops_type(w: &WrongWithType) {
28+
w.x;
29+
}
30+
31+
fn foo_type(w: &WrongWithType) {
32+
w.y;
33+
}
34+
35+
fn haha_type(w: &WrongWithType) {
36+
w.z;
37+
}
38+
39+
fn main() {
40+
let v = Wrong { x: 1, y: 2, z: 3, h: 4 };
41+
let x = WrongWithType { x: 1, y: 2, z: 3, h: 4 };
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: struct fields are separated by `,`
2+
--> $DIR/struct-parser-recovery-issue-126344.rs:2:11
3+
|
4+
LL | struct Wrong {
5+
| ----- while parsing this struct
6+
LL | x: i32;
7+
| ^ help: replace `;` with `,`
8+
9+
error: expected type, found `1`
10+
--> $DIR/struct-parser-recovery-issue-126344.rs:21:8
11+
|
12+
LL | struct WrongWithType {
13+
| ------------- while parsing this struct
14+
LL | x: 1,
15+
| ^ expected type
16+
17+
error: aborting due to 2 previous errors
18+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
struct X {,} //~ ERROR expected identifier, found `,`
2+
3+
fn main() {
4+
|| {
5+
if let X { x: 1,} = (X {}) {}
6+
};
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: expected identifier, found `,`
2+
--> $DIR/struct-index-err-ice-issue-126744.rs:1:11
3+
|
4+
LL | struct X {,}
5+
| - ^ expected identifier
6+
| |
7+
| while parsing this struct
8+
9+
error: aborting due to 1 previous error
10+

0 commit comments

Comments
 (0)