summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_parse/src/parser/ty.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src/parser/ty.rs')
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs84
1 files changed, 72 insertions, 12 deletions
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 2d888efb1..a25b0f1f8 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`.
@@ -845,18 +891,32 @@ impl<'a> Parser<'a> {
// that we do not use the try operator when parsing the type because
// if it fails then we get a parser error which we don't want (we're trying
// to recover from errors, not make more).
- let path = if self.may_recover()
- && matches!(ty.kind, TyKind::Ptr(..) | TyKind::Ref(..))
- && let TyKind::Path(_, path) = &ty.peel_refs().kind {
- // Just get the indirection part of the type.
- let span = ty.span.until(path.span);
-
- err.span_suggestion_verbose(
- span,
- "consider removing the indirection",
- "",
- Applicability::MaybeIncorrect,
- );
+ let path = if self.may_recover() {
+ let (span, message, sugg, path, applicability) = match &ty.kind {
+ TyKind::Ptr(..) | TyKind::Ref(..) if let TyKind::Path(_, path) = &ty.peel_refs().kind => {
+ (
+ ty.span.until(path.span),
+ "consider removing the indirection",
+ "",
+ path,
+ Applicability::MaybeIncorrect
+ )
+ }
+ TyKind::ImplTrait(_, bounds)
+ if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() =>
+ {
+ (
+ ty.span.until(tr.span),
+ "use the trait bounds directly",
+ "",
+ &tr.trait_ref.path,
+ Applicability::MachineApplicable
+ )
+ }
+ _ => return Err(err)
+ };
+
+ err.span_suggestion_verbose(span, message, sugg, applicability);
path.clone()
} else {