Skip to content

Commit

Permalink
Also take unions and enums into account
Browse files Browse the repository at this point in the history
  • Loading branch information
LeSeulArtichaut committed May 7, 2021
1 parent 1e642f0 commit 6717f81
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 19 deletions.
33 changes: 19 additions & 14 deletions compiler/rustc_parse/src/parser/item.rs
Expand Up @@ -1124,11 +1124,11 @@ impl<'a> Parser<'a> {
if !this.recover_nested_adt_item(kw::Enum)? {
return Ok((None, TrailingToken::None));
}
let ident = this.parse_ident()?;
let ident = this.parse_field_ident("enum", vlo)?;

let struct_def = if this.check(&token::OpenDelim(token::Brace)) {
// Parse a struct variant.
let (fields, recovered) = this.parse_record_struct_body()?;
let (fields, recovered) = this.parse_record_struct_body("struct")?;
VariantData::Struct(fields, recovered)
} else if this.check(&token::OpenDelim(token::Paren)) {
VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID)
Expand Down Expand Up @@ -1182,15 +1182,15 @@ impl<'a> Parser<'a> {
VariantData::Unit(DUMMY_NODE_ID)
} else {
// If we see: `struct Foo<T> where T: Copy { ... }`
let (fields, recovered) = self.parse_record_struct_body()?;
let (fields, recovered) = self.parse_record_struct_body("struct")?;
VariantData::Struct(fields, recovered)
}
// No `where` so: `struct Foo<T>;`
} else if self.eat(&token::Semi) {
VariantData::Unit(DUMMY_NODE_ID)
// Record-style struct definition
} else if self.token == token::OpenDelim(token::Brace) {
let (fields, recovered) = self.parse_record_struct_body()?;
let (fields, recovered) = self.parse_record_struct_body("struct")?;
VariantData::Struct(fields, recovered)
// Tuple-style struct definition with optional where-clause.
} else if self.token == token::OpenDelim(token::Paren) {
Expand Down Expand Up @@ -1220,10 +1220,10 @@ impl<'a> Parser<'a> {

let vdata = if self.token.is_keyword(kw::Where) {
generics.where_clause = self.parse_where_clause()?;
let (fields, recovered) = self.parse_record_struct_body()?;
let (fields, recovered) = self.parse_record_struct_body("union")?;
VariantData::Struct(fields, recovered)
} else if self.token == token::OpenDelim(token::Brace) {
let (fields, recovered) = self.parse_record_struct_body()?;
let (fields, recovered) = self.parse_record_struct_body("union")?;
VariantData::Struct(fields, recovered)
} else {
let token_str = super::token_descr(&self.token);
Expand All @@ -1236,12 +1236,15 @@ impl<'a> Parser<'a> {
Ok((class_name, ItemKind::Union(vdata, generics)))
}

fn parse_record_struct_body(&mut self) -> PResult<'a, (Vec<FieldDef>, /* recovered */ bool)> {
fn parse_record_struct_body(
&mut self,
adt_ty: &str,
) -> PResult<'a, (Vec<FieldDef>, /* recovered */ bool)> {
let mut fields = Vec::new();
let mut recovered = false;
if self.eat(&token::OpenDelim(token::Brace)) {
while self.token != token::CloseDelim(token::Brace) {
let field = self.parse_field_def().map_err(|e| {
let field = self.parse_field_def(adt_ty).map_err(|e| {
self.consume_block(token::Brace, ConsumeClosingDelim::No);
recovered = true;
e
Expand Down Expand Up @@ -1294,24 +1297,25 @@ impl<'a> Parser<'a> {
}

/// Parses an element of a struct declaration.
fn parse_field_def(&mut self) -> PResult<'a, FieldDef> {
fn parse_field_def(&mut self, adt_ty: &str) -> PResult<'a, FieldDef> {
let attrs = self.parse_outer_attributes()?;
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
let lo = this.token.span;
let vis = this.parse_visibility(FollowedByType::No)?;
Ok((this.parse_single_struct_field(lo, vis, attrs)?, TrailingToken::None))
Ok((this.parse_single_struct_field(adt_ty, lo, vis, attrs)?, TrailingToken::None))
})
}

/// Parses a structure field declaration.
fn parse_single_struct_field(
&mut self,
adt_ty: &str,
lo: Span,
vis: Visibility,
attrs: Vec<Attribute>,
) -> PResult<'a, FieldDef> {
let mut seen_comma: bool = false;
let a_var = self.parse_name_and_ty(lo, vis, attrs)?;
let a_var = self.parse_name_and_ty(adt_ty, lo, vis, attrs)?;
if self.token == token::Comma {
seen_comma = true;
}
Expand Down Expand Up @@ -1398,11 +1402,12 @@ impl<'a> Parser<'a> {
/// Parses a structure field.
fn parse_name_and_ty(
&mut self,
adt_ty: &str,
lo: Span,
vis: Visibility,
attrs: Vec<Attribute>,
) -> PResult<'a, FieldDef> {
let name = self.parse_field_ident(lo)?;
let name = self.parse_field_ident(adt_ty, lo)?;
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;
Ok(FieldDef {
Expand All @@ -1418,14 +1423,14 @@ impl<'a> Parser<'a> {

/// Parses a field identifier. Specialized version of `parse_ident_common`
/// for better diagnostics and suggestions.
fn parse_field_ident(&mut self, lo: Span) -> PResult<'a, Ident> {
fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
let (ident, is_raw) = self.ident_or_err()?;
if !is_raw && ident.is_reserved() {
let err = if self.check_fn_front_matter(false) {
let _ = self.parse_fn(&mut Vec::new(), |_| true, lo);
let mut err = self.struct_span_err(
lo.to(self.prev_token.span),
"functions are not allowed in struct definitions",
&format!("functions are not allowed in {} definitions", adt_ty),
);
err.help("unlike in C++, Java, and C#, functions are declared in `impl` blocks");
err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
Expand Down
21 changes: 20 additions & 1 deletion src/test/ui/structs/struct-fn-in-definition.rs
Expand Up @@ -5,10 +5,29 @@

struct S {
field: usize,
fn do_something() {}

fn foo() {}
//~^ ERROR functions are not allowed in struct definitions
//~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks
//~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
}

union U {
variant: usize,

fn foo() {}
//~^ ERROR functions are not allowed in union definitions
//~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks
//~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
}

enum E {
Variant,

fn foo() {}
//~^ ERROR functions are not allowed in enum definitions
//~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks
//~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
}

fn main() {}
26 changes: 22 additions & 4 deletions src/test/ui/structs/struct-fn-in-definition.stderr
@@ -1,11 +1,29 @@
error: functions are not allowed in struct definitions
--> $DIR/struct-fn-in-definition.rs:5:5
--> $DIR/struct-fn-in-definition.rs:9:5
|
LL | fn do_something() {}
| ^^^^^^^^^^^^^^^^^^^^
LL | fn foo() {}
| ^^^^^^^^^^^
|
= help: unlike in C++, Java, and C#, functions are declared in `impl` blocks
= help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information

error: aborting due to previous error
error: functions are not allowed in union definitions
--> $DIR/struct-fn-in-definition.rs:18:5
|
LL | fn foo() {}
| ^^^^^^^^^^^
|
= help: unlike in C++, Java, and C#, functions are declared in `impl` blocks
= help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information

error: functions are not allowed in enum definitions
--> $DIR/struct-fn-in-definition.rs:27:5
|
LL | fn foo() {}
| ^^^^^^^^^^^
|
= help: unlike in C++, Java, and C#, functions are declared in `impl` blocks
= help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information

error: aborting due to 3 previous errors

0 comments on commit 6717f81

Please sign in to comment.