diff options
author | Chris Lattner <sabre@nondot.org> | 2010-02-02 01:23:29 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2010-02-02 01:23:29 +0000 |
commit | cf25141d1442c04f36fc8e8342763cd043218b7b (patch) | |
tree | a26fd93990ad3993a18124fe066d50e560257d7c /clang | |
parent | 13ad81bd70afaf35d54a080893dc6beb7e1c1b0c (diff) | |
download | bcm5719-llvm-cf25141d1442c04f36fc8e8342763cd043218b7b.tar.gz bcm5719-llvm-cf25141d1442c04f36fc8e8342763cd043218b7b.zip |
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
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Basic/DiagnosticParseKinds.td | 3 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 39 | ||||
-rw-r--r-- | clang/test/Sema/declspec.c | 16 |
3 files changed, 52 insertions, 6 deletions
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 6093282423d..dc83e87e967 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -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< diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index e83743cd67c..234ec4c8b59 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -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; diff --git a/clang/test/Sema/declspec.c b/clang/test/Sema/declspec.c index 5b119601603..e1f2bf4911a 100644 --- a/clang/test/Sema/declspec.c +++ b/clang/test/Sema/declspec.c @@ -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() {} + |