forked from OSchip/llvm-project
Implement PR6180, substantially improving the diagnostics we get from
forgetting a ';' at the end of a struct. For something like: class c { } void foo() {} we now produce: t.cc:3:2: error: expected ';' after class } ^ ; instead of: t.cc:4:1: error: cannot combine with previous 'class' declaration specifier void foo() {} ^ t.cc:2:7: error: 'class c' can not be defined in the result type of a function class c { ^ GCC produces: t.cc:4: error: new types may not be defined in a return type t.cc:4: note: (perhaps a semicolon is missing after the definition of ‘c’) t.cc:4: error: two or more data types in declaration of ‘foo’ I *think* I got the follow set right, but if I forgot anything, we'll start getting spurious "expected ';' after class" errors, let me know if you see any. llvm-svn: 95042
This commit is contained in:
parent
13ad81bd70
commit
cf25141d14
|
@ -305,6 +305,9 @@ def err_out_of_line_type_names_constructor : Error<
|
|||
|
||||
def err_expected_qualified_after_typename : Error<
|
||||
"expected a qualified name after 'typename'">;
|
||||
def err_expected_semi_after_tagdecl : Error<
|
||||
"expected ';' after %0">;
|
||||
|
||||
def err_typename_refers_to_non_type_template : Error<
|
||||
"typename specifier refers to a non-template">;
|
||||
def err_expected_type_name_after_typename : Error<
|
||||
|
|
|
@ -924,6 +924,42 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
if (DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID,
|
||||
Result, Owned))
|
||||
Diag(StartLoc, DiagID) << PrevSpec;
|
||||
|
||||
// At this point, we've successfully parsed a class-specifier in 'definition'
|
||||
// form (e.g. "struct foo { int x; }". While we could just return here, we're
|
||||
// going to look at what comes after it to improve error recovery. If an
|
||||
// impossible token occurs next, we assume that the programmer forgot a ; at
|
||||
// the end of the declaration and recover that way.
|
||||
//
|
||||
// This switch enumerates the valid "follow" set for definition.
|
||||
if (TUK == Action::TUK_Definition) {
|
||||
switch (Tok.getKind()) {
|
||||
case tok::semi: // struct foo {...} ;
|
||||
case tok::star: // struct foo {...} * P;
|
||||
case tok::amp: // struct foo {...} & R = ...
|
||||
case tok::identifier: // struct foo {...} V ;
|
||||
case tok::r_paren: //(struct foo {...} ) {4}
|
||||
case tok::annot_cxxscope: // struct foo {...} a:: b;
|
||||
case tok::annot_typename: // struct foo {...} a ::b;
|
||||
case tok::annot_template_id: // struct foo {...} a<int> ::b;
|
||||
break;
|
||||
|
||||
case tok::r_brace: // struct bar { struct foo {...} }
|
||||
// Missing ';' at end of struct is accepted as an extension in C mode.
|
||||
if (!getLang().CPlusPlus) break;
|
||||
// FALL THROUGH.
|
||||
default:
|
||||
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
|
||||
TagType == DeclSpec::TST_class ? "class"
|
||||
: TagType == DeclSpec::TST_struct? "struct" : "union");
|
||||
// Push this token back into the preprocessor and change our current token
|
||||
// to ';' so that the rest of the code recovers as though there were an
|
||||
// ';' after the definition.
|
||||
PP.EnterToken(Tok);
|
||||
Tok.setKind(tok::semi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived].
|
||||
|
@ -1168,7 +1204,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
return ParseCXXClassMemberDeclaration(AS, TemplateInfo);
|
||||
}
|
||||
|
||||
// Don't parse FOO:BAR as if it were a typo for FOO::BAR.
|
||||
// Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
|
||||
// is a bitfield.
|
||||
ColonProtectionRAIIObject X(*this);
|
||||
|
||||
CXX0XAttributeList AttrList;
|
||||
|
|
|
@ -7,11 +7,10 @@ void foof(const char *, ...) __attribute__((__format__(__printf__, 1, 2))), barf
|
|||
|
||||
int typedef validTypeDecl() { } // expected-error {{function definition declared 'typedef'}}
|
||||
|
||||
struct _zend_module_entry { }
|
||||
typedef struct _zend_function_entry { } // expected-error {{cannot combine with previous 'struct' declaration specifier}}
|
||||
static void buggy(int *x) { } // expected-error {{function definition declared 'typedef'}} \
|
||||
// expected-error {{cannot combine with previous 'typedef' declaration specifier}} \
|
||||
// expected-error {{cannot combine with previous 'struct' declaration specifier}}
|
||||
struct _zend_module_entry { } // expected-error {{expected ';' after struct}}
|
||||
typedef struct _zend_function_entry { } // expected-error {{expected ';' after struct}} \
|
||||
// expected-error {{declaration does not declare anything}}
|
||||
static void buggy(int *x) { }
|
||||
|
||||
// Type qualifiers.
|
||||
typedef int f(void);
|
||||
|
@ -22,3 +21,10 @@ __restrict__ fptr v3; // expected-error {{pointer to function type 'f' (aka 'int
|
|||
f *__restrict__ v4; // expected-error {{pointer to function type 'f' (aka 'int (void)') may not be 'restrict' qualified}}
|
||||
|
||||
restrict struct hallo; // expected-error {{restrict requires a pointer or reference}}
|
||||
|
||||
// PR6180
|
||||
struct test1 {
|
||||
} // expected-error {{expected ';' after struct}}
|
||||
|
||||
void test2() {}
|
||||
|
||||
|
|
Loading…
Reference in New Issue