diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 4d6255aa08f8f..55e2d77ad18f0 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -545,4 +545,18 @@ impl<'a> Parser<'a> { Ok(()) } + + /// Parse inner attributes and error if they are present + /// Returns whether any inner attributes were discarded + pub fn recover_inner_attributes(&mut self) -> PResult<'a, bool> { + let attributes = self.parse_inner_attributes()?; + for attr in &attributes { + self.error_on_forbidden_inner_attr( + attr.span, + InnerAttrPolicy::Forbidden(Some(InnerAttrForbiddenReason::InCodeBlock)), + true, + ); + } + Ok(!attributes.is_empty()) + } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index b252a378722f3..7f49a786d66ad 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1936,6 +1936,9 @@ impl<'a> Parser<'a> { } fn parse_enum_variant(&mut self, span: Span) -> PResult<'a, Option> { + if self.recover_inner_attributes()? && self.check(exp![CloseBrace]) { + return Ok(None); + } self.recover_vcs_conflict_marker(); let variant_attrs = self.parse_outer_attributes()?; self.recover_vcs_conflict_marker(); @@ -2139,6 +2142,7 @@ impl<'a> Parser<'a> { let mut fields = ThinVec::new(); let mut recovered = Recovered::No; if self.eat(exp!(OpenBrace)) { + self.recover_inner_attributes()?; while self.token != token::CloseBrace { match self.parse_field_def(adt_ty, ident_span) { Ok(field) => { diff --git a/tests/ui/parser/empty-adt-inner-attributes.rs b/tests/ui/parser/empty-adt-inner-attributes.rs new file mode 100644 index 0000000000000..f463fbf9f4fdc --- /dev/null +++ b/tests/ui/parser/empty-adt-inner-attributes.rs @@ -0,0 +1,17 @@ +struct Test1 { + #![inline] + //~^ ERROR an inner attribute is not permitted in this context +} + +enum Test2 { + #![inline] + //~^ ERROR an inner attribute is not permitted in this context +} + +union Test3 { + //~^ ERROR unions cannot have zero fields + #![inline] + //~^ ERROR an inner attribute is not permitted in this context +} + +fn main() { } diff --git a/tests/ui/parser/empty-adt-inner-attributes.stderr b/tests/ui/parser/empty-adt-inner-attributes.stderr new file mode 100644 index 0000000000000..a6cb17804626c --- /dev/null +++ b/tests/ui/parser/empty-adt-inner-attributes.stderr @@ -0,0 +1,39 @@ +error: an inner attribute is not permitted in this context + --> $DIR/empty-adt-inner-attributes.rs:2:5 + | +LL | #![inline] + | ^^^^^^^^^^ + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them + +error: an inner attribute is not permitted in this context + --> $DIR/empty-adt-inner-attributes.rs:7:5 + | +LL | #![inline] + | ^^^^^^^^^^ + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them + +error: an inner attribute is not permitted in this context + --> $DIR/empty-adt-inner-attributes.rs:13:5 + | +LL | #![inline] + | ^^^^^^^^^^ + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + = note: outer attributes, like `#[test]`, annotate the item following them + +error: unions cannot have zero fields + --> $DIR/empty-adt-inner-attributes.rs:11:1 + | +LL | / union Test3 { +LL | | +LL | | #![inline] +LL | | +LL | | } + | |_^ + +error: aborting due to 4 previous errors +