diff options
Diffstat (limited to 'compiler/rustc_parse')
| -rw-r--r-- | compiler/rustc_parse/src/lib.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 46 |
3 files changed, 52 insertions, 4 deletions
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 892be36aae7..598adbe7985 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -8,7 +8,7 @@ #![feature(never_type)] #![feature(rustc_attrs)] #![recursion_limit = "256"] -#![cfg_attr(not(bootstrap), allow(internal_features))] +#![allow(internal_features)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 24c65d061f9..5db31c23478 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1594,7 +1594,7 @@ impl<'a> Parser<'a> { Ok((class_name, ItemKind::Union(vdata, generics))) } - fn parse_record_struct_body( + pub(crate) fn parse_record_struct_body( &mut self, adt_ty: &str, ident_span: Span, @@ -1869,7 +1869,7 @@ impl<'a> Parser<'a> { } } self.expect_field_ty_separator()?; - let ty = self.parse_ty()?; + let ty = self.parse_ty_for_field_def()?; if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) { self.sess.emit_err(errors::SingleColonStructType { span: self.token.span }); } @@ -1894,7 +1894,9 @@ impl<'a> Parser<'a> { /// for better diagnostics and suggestions. fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> { let (ident, is_raw) = self.ident_or_err(true)?; - if !is_raw && ident.is_reserved() { + if ident.name == kw::Underscore { + self.sess.gated_spans.gate(sym::unnamed_fields, lo); + } else if !is_raw && ident.is_reserved() { let snapshot = self.create_snapshot_for_diagnostic(); let err = if self.check_fn_front_matter(false, Case::Sensitive) { let inherited_vis = Visibility { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 2d888efb1f3..661113666cd 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -136,6 +136,17 @@ impl<'a> Parser<'a> { ) } + /// Parse a type suitable for a field defintion. + /// The difference from `parse_ty` is that this version + /// allows anonymous structs and unions. + pub fn parse_ty_for_field_def(&mut self) -> PResult<'a, P<Ty>> { + if self.can_begin_anon_struct_or_union() { + self.parse_anon_struct_or_union() + } else { + self.parse_ty() + } + } + /// Parse a type suitable for a function or function pointer parameter. /// The difference from `parse_ty` is that this version allows `...` /// (`CVarArgs`) at the top level of the type. @@ -336,6 +347,36 @@ impl<'a> Parser<'a> { if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) } } + /// Parse an anonymous struct or union (only for field definitions): + /// ```ignore (feature-not-ready) + /// #[repr(C)] + /// struct Foo { + /// _: struct { // anonymous struct + /// x: u32, + /// y: f64, + /// } + /// _: union { // anonymous union + /// z: u32, + /// w: f64, + /// } + /// } + /// ``` + fn parse_anon_struct_or_union(&mut self) -> PResult<'a, P<Ty>> { + assert!(self.token.is_keyword(kw::Union) || self.token.is_keyword(kw::Struct)); + let is_union = self.token.is_keyword(kw::Union); + + let lo = self.token.span; + self.bump(); + + let (fields, _recovered) = + self.parse_record_struct_body(if is_union { "union" } else { "struct" }, lo, false)?; + let span = lo.to(self.prev_token.span); + self.sess.gated_spans.gate(sym::unnamed_fields, span); + // These can be rejected during AST validation in `deny_anon_struct_or_union`. + let kind = if is_union { TyKind::AnonUnion(fields) } else { TyKind::AnonStruct(fields) }; + Ok(self.mk_ty(span, kind)) + } + /// Parses either: /// - `(TYPE)`, a parenthesized type. /// - `(TYPE,)`, a tuple with a single field of type TYPE. @@ -696,6 +737,11 @@ impl<'a> Parser<'a> { Ok(bounds) } + pub(super) fn can_begin_anon_struct_or_union(&mut self) -> bool { + (self.token.is_keyword(kw::Struct) || self.token.is_keyword(kw::Union)) + && self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace)) + } + /// Can the current token begin a bound? fn can_begin_bound(&mut self) -> bool { // This needs to be synchronized with `TokenKind::can_begin_bound`. |
