Skip to content

Commit 1686551

Browse files
committed
Fix recovery of anonymous types
1 parent 9ce026c commit 1686551

File tree

14 files changed

+270
-243
lines changed

14 files changed

+270
-243
lines changed

compiler/rustc_ast/src/ast.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2093,9 +2093,9 @@ pub enum TyKind {
20932093
/// A tuple (`(A, B, C, D,...)`).
20942094
Tup(ThinVec<P<Ty>>),
20952095
/// An anonymous struct type i.e. `struct { foo: Type }`
2096-
AnonymousStruct(ThinVec<FieldDef>, /* recovered */ bool),
2096+
AnonymousStruct(ThinVec<FieldDef>),
20972097
/// An anonymous union type i.e. `union { bar: Type }`
2098-
AnonymousUnion(ThinVec<FieldDef>, /* recovered */ bool),
2098+
AnonymousUnion(ThinVec<FieldDef>),
20992099
/// A path (`module::module::...::Type`), optionally
21002100
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
21012101
///

compiler/rustc_ast/src/mut_visit.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -509,8 +509,7 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
509509
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
510510
}
511511
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
512-
TyKind::AnonymousStruct(fields, _recovered)
513-
| TyKind::AnonymousUnion(fields, _recovered) => {
512+
TyKind::AnonymousStruct(fields) | TyKind::AnonymousUnion(fields) => {
514513
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
515514
}
516515
}

compiler/rustc_ast_lowering/src/item.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -708,10 +708,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
708708
}
709709
}
710710

711-
pub(super) fn lower_field_def(
712-
&mut self,
713-
(index, f): (usize, &FieldDef),
714-
) -> hir::FieldDef<'hir> {
711+
fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
715712
let ty = if let TyKind::Path(qself, path) = &f.ty.kind {
716713
let t = self.lower_path_ty(
717714
&f.ty,

compiler/rustc_ast_lowering/src/lib.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
#![feature(let_chains)]
3535
#![feature(never_type)]
3636
#![recursion_limit = "256"]
37-
// #![deny(rustc::untranslatable_diagnostic)]
38-
// #![deny(rustc::diagnostic_outside_of_impl)]
37+
#![deny(rustc::untranslatable_diagnostic)]
38+
#![deny(rustc::diagnostic_outside_of_impl)]
3939

4040
#[macro_use]
4141
extern crate tracing;
@@ -1294,12 +1294,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
12941294
hir::TyKind::Err(self.tcx.sess.delay_span_bug(t.span, "TyKind::Err lowered"))
12951295
}
12961296
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
1297-
TyKind::AnonymousStruct(ref _fields, _recovered) => {
1298-
hir::TyKind::Err(self.tcx.sess.span_err(t.span, "anonymous structs are unimplemented"))
1299-
}
1300-
TyKind::AnonymousUnion(ref _fields, _recovered) => {
1301-
hir::TyKind::Err(self.tcx.sess.span_err(t.span, "anonymous unions are unimplemented"))
1302-
}
1297+
#[allow(rustc::untranslatable_diagnostic)]
1298+
#[allow(rustc::diagnostic_outside_of_impl)]
1299+
TyKind::AnonymousStruct(ref _fields) => hir::TyKind::Err(
1300+
self.tcx.sess.span_err(t.span, "anonymous structs are unimplemented"),
1301+
),
1302+
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
1303+
#[allow(rustc::untranslatable_diagnostic)]
1304+
#[allow(rustc::diagnostic_outside_of_impl)]
1305+
TyKind::AnonymousUnion(ref _fields) => hir::TyKind::Err(
1306+
self.tcx.sess.span_err(t.span, "anonymous unions are unimplemented"),
1307+
),
13031308
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
13041309
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
13051310
TyKind::Ref(region, mt) => {

compiler/rustc_ast_passes/src/ast_validation.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ impl<'a> AstValidator<'a> {
221221
}
222222
TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => {
223223
// self.with_banned_assoc_ty_bound(|this| {
224-
walk_list!(self, visit_struct_field_def, fields)
224+
walk_list!(self, visit_struct_field_def, fields)
225225
// });
226226
}
227227
_ => visit::walk_ty(self, t),
@@ -865,6 +865,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
865865

866866
fn visit_ty(&mut self, ty: &'a Ty) {
867867
self.visit_ty_common(ty);
868+
tracing::info!(?ty);
868869
self.deny_anonymous_struct(ty);
869870
self.walk_ty(ty)
870871
}
@@ -1085,7 +1086,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
10851086
self.visit_ident(item.ident);
10861087
self.visit_generics(generics);
10871088
// self.with_banned_assoc_ty_bound(|this| {
1088-
walk_list!(self, visit_struct_field_def, fields);
1089+
walk_list!(self, visit_struct_field_def, fields);
10891090
// });
10901091
walk_list!(self, visit_attribute, &item.attrs);
10911092
return;
@@ -1102,7 +1103,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11021103
self.visit_ident(item.ident);
11031104
self.visit_generics(generics);
11041105
// self.with_banned_assoc_ty_bound(|this| {
1105-
walk_list!(self, visit_struct_field_def, fields);
1106+
walk_list!(self, visit_struct_field_def, fields);
11061107
// });
11071108
walk_list!(self, visit_attribute, &item.attrs);
11081109
return;

compiler/rustc_ast_pretty/src/pprust/state.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1053,11 +1053,11 @@ impl<'a> State<'a> {
10531053
}
10541054
self.pclose();
10551055
}
1056-
ast::TyKind::AnonymousStruct(fields, _recovered) => {
1056+
ast::TyKind::AnonymousStruct(fields) => {
10571057
self.head("struct");
10581058
self.print_record_struct_body(&fields, ty.span);
10591059
}
1060-
ast::TyKind::AnonymousUnion(fields, _recovered) => {
1060+
ast::TyKind::AnonymousUnion(fields) => {
10611061
self.head("union");
10621062
self.print_record_struct_body(&fields, ty.span);
10631063
}

compiler/rustc_parse/src/parser/item.rs

+100-77
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
2-
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
2+
use super::ty::{AllowPlus, RecoverAnonymousStructOrUnion, RecoverQPath, RecoverReturnSign};
33
use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
44
use crate::errors::{self, MacroExpandsToAdtField};
55
use crate::fluent_generated as fluent;
@@ -602,7 +602,7 @@ impl<'a> Parser<'a> {
602602
Some(self.mk_ty(self.prev_token.span, TyKind::Err))
603603
} else if has_for || self.token.can_begin_type() {
604604
snapshot_before_last_ty = self.create_snapshot_for_diagnostic();
605-
Some(self.parse_ty_no_anon_recovery()?)
605+
Some(self.parse_ty()?)
606606
} else {
607607
None
608608
};
@@ -615,7 +615,7 @@ impl<'a> Parser<'a> {
615615
if let Some(mut err) = err {
616616
let mut snapshot = snapshot_before_last_ty;
617617

618-
if snapshot.can_start_anonymous_type() {
618+
if snapshot.can_start_anonymous_union() {
619619
let recover_result = {
620620
let recover_last_ty = match snapshot.parse_ty() {
621621
Ok(ty) => Some(ty),
@@ -1665,11 +1665,26 @@ impl<'a> Parser<'a> {
16651665
Ok((class_name, ItemKind::Union(vdata, generics)))
16661666
}
16671667

1668-
pub(crate) fn parse_record_struct_body(
1668+
fn parse_record_struct_body(
16691669
&mut self,
16701670
adt_ty: &str,
16711671
ident_span: Span,
16721672
parsed_where: bool,
1673+
) -> PResult<'a, (ThinVec<FieldDef>, /* recovered */ bool)> {
1674+
self.parse_record_struct_body_common(
1675+
adt_ty,
1676+
ident_span,
1677+
parsed_where,
1678+
RecoverAnonymousStructOrUnion::No,
1679+
)
1680+
}
1681+
1682+
pub(crate) fn parse_record_struct_body_common(
1683+
&mut self,
1684+
adt_ty: &str,
1685+
ident_span: Span,
1686+
parsed_where: bool,
1687+
recover_anonymous_struct_or_union: RecoverAnonymousStructOrUnion,
16731688
) -> PResult<'a, (ThinVec<FieldDef>, /* recovered */ bool)> {
16741689
let mut fields = ThinVec::new();
16751690
let mut recovered = false;
@@ -1683,6 +1698,16 @@ impl<'a> Parser<'a> {
16831698
match field {
16841699
Ok(field) => fields.push(field),
16851700
Err(mut err) => {
1701+
// When recovering the anonymous structs or unions, we should't emit the error
1702+
// immediately, because it may also be a type path `union` followed by a block,
1703+
// such as `impl union { fn foo() {} }`. Here we are actaully not parsing a
1704+
// record struct body but an `impl` body.
1705+
//
1706+
// Instead, the error should be thrown and handled by the caller
1707+
// `parse_anonymous_struct_or_union`.
1708+
if recover_anonymous_struct_or_union == RecoverAnonymousStructOrUnion::Yes {
1709+
return Err(err);
1710+
}
16861711
err.span_label(ident_span, format!("while parsing this {adt_ty}"));
16871712
err.emit();
16881713
break;
@@ -1965,85 +1990,83 @@ impl<'a> Parser<'a> {
19651990
/// for better diagnostics and suggestions.
19661991
fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
19671992
let (ident, is_raw) = self.ident_or_err(true)?;
1968-
if !is_raw && ident.is_reserved() {
1993+
if ident.name == kw::Underscore {
1994+
self.sess.gated_spans.gate(sym::unnamed_fields, lo);
1995+
} else if !is_raw && ident.is_reserved() {
19691996
let snapshot = self.create_snapshot_for_diagnostic();
1970-
if ident.name == kw::Underscore {
1971-
self.sess.gated_spans.gate(sym::unnamed_fields, lo);
1972-
} else {
1973-
let err = if self.check_fn_front_matter(false, Case::Sensitive) {
1974-
let inherited_vis = Visibility {
1975-
span: rustc_span::DUMMY_SP,
1976-
kind: VisibilityKind::Inherited,
1977-
tokens: None,
1978-
};
1979-
// We use `parse_fn` to get a span for the function
1980-
let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
1981-
match self.parse_fn(
1982-
&mut AttrVec::new(),
1983-
fn_parse_mode,
1984-
lo,
1985-
&inherited_vis,
1986-
Case::Insensitive,
1987-
) {
1988-
Ok(_) => {
1989-
let mut err = self.struct_span_err(
1990-
lo.to(self.prev_token.span),
1991-
format!("functions are not allowed in {adt_ty} definitions"),
1992-
);
1993-
err.help(
1994-
"unlike in C++, Java, and C#, functions are declared in `impl` blocks",
1995-
);
1996-
err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
1997-
err
1998-
}
1999-
Err(err) => {
2000-
err.cancel();
2001-
self.restore_snapshot(snapshot);
2002-
self.expected_ident_found_err()
2003-
}
1997+
let err = if self.check_fn_front_matter(false, Case::Sensitive) {
1998+
let inherited_vis = Visibility {
1999+
span: rustc_span::DUMMY_SP,
2000+
kind: VisibilityKind::Inherited,
2001+
tokens: None,
2002+
};
2003+
// We use `parse_fn` to get a span for the function
2004+
let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
2005+
match self.parse_fn(
2006+
&mut AttrVec::new(),
2007+
fn_parse_mode,
2008+
lo,
2009+
&inherited_vis,
2010+
Case::Insensitive,
2011+
) {
2012+
Ok(_) => {
2013+
let mut err = self.struct_span_err(
2014+
lo.to(self.prev_token.span),
2015+
format!("functions are not allowed in {adt_ty} definitions"),
2016+
);
2017+
err.help(
2018+
"unlike in C++, Java, and C#, functions are declared in `impl` blocks",
2019+
);
2020+
err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
2021+
err
20042022
}
2005-
} else if self.eat_keyword(kw::Struct) {
2006-
match self.parse_item_struct() {
2007-
Ok((ident, _)) => {
2008-
let mut err = self.struct_span_err(
2009-
lo.with_hi(ident.span.hi()),
2010-
format!("structs are not allowed in {adt_ty} definitions"),
2011-
);
2012-
err.help("consider creating a new `struct` definition instead of nesting");
2013-
err
2014-
}
2015-
Err(err) => {
2016-
err.cancel();
2017-
self.restore_snapshot(snapshot);
2018-
self.expected_ident_found_err()
2019-
}
2023+
Err(err) => {
2024+
err.cancel();
2025+
self.restore_snapshot(snapshot);
2026+
self.expected_ident_found_err()
20202027
}
2021-
} else {
2022-
let mut err = self.expected_ident_found_err();
2023-
if self.eat_keyword_noexpect(kw::Let)
2024-
&& let removal_span = self.prev_token.span.until(self.token.span)
2025-
&& let Ok(ident) = self.parse_ident_common(false)
2026-
// Cancel this error, we don't need it.
2027-
.map_err(|err| err.cancel())
2028-
&& self.token.kind == TokenKind::Colon
2029-
{
2030-
err.span_suggestion(
2031-
removal_span,
2032-
"remove this `let` keyword",
2033-
String::new(),
2034-
Applicability::MachineApplicable,
2028+
}
2029+
} else if self.eat_keyword(kw::Struct) {
2030+
match self.parse_item_struct() {
2031+
Ok((ident, _)) => {
2032+
let mut err = self.struct_span_err(
2033+
lo.with_hi(ident.span.hi()),
2034+
format!("structs are not allowed in {adt_ty} definitions"),
20352035
);
2036-
err.note("the `let` keyword is not allowed in `struct` fields");
2037-
err.note("see <https://doc.rust-lang.org/book/ch05-01-defining-structs.html> for more information");
2038-
err.emit();
2039-
return Ok(ident);
2040-
} else {
2036+
err.help("consider creating a new `struct` definition instead of nesting");
2037+
err
2038+
}
2039+
Err(err) => {
2040+
err.cancel();
20412041
self.restore_snapshot(snapshot);
2042+
self.expected_ident_found_err()
20422043
}
2043-
err
2044-
};
2045-
return Err(err);
2046-
}
2044+
}
2045+
} else {
2046+
let mut err = self.expected_ident_found_err();
2047+
if self.eat_keyword_noexpect(kw::Let)
2048+
&& let removal_span = self.prev_token.span.until(self.token.span)
2049+
&& let Ok(ident) = self.parse_ident_common(false)
2050+
// Cancel this error, we don't need it.
2051+
.map_err(|err| err.cancel())
2052+
&& self.token.kind == TokenKind::Colon
2053+
{
2054+
err.span_suggestion(
2055+
removal_span,
2056+
"remove this `let` keyword",
2057+
String::new(),
2058+
Applicability::MachineApplicable,
2059+
);
2060+
err.note("the `let` keyword is not allowed in `struct` fields");
2061+
err.note("see <https://doc.rust-lang.org/book/ch05-01-defining-structs.html> for more information");
2062+
err.emit();
2063+
return Ok(ident);
2064+
} else {
2065+
self.restore_snapshot(snapshot);
2066+
}
2067+
err
2068+
};
2069+
return Err(err);
20472070
}
20482071
self.bump();
20492072
Ok(ident)

0 commit comments

Comments
 (0)