summaryrefslogtreecommitdiffstats
path: root/clang/lib/Parse
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2010-02-02 01:23:29 +0000
committerChris Lattner <sabre@nondot.org>2010-02-02 01:23:29 +0000
commitcf25141d1442c04f36fc8e8342763cd043218b7b (patch)
treea26fd93990ad3993a18124fe066d50e560257d7c /clang/lib/Parse
parent13ad81bd70afaf35d54a080893dc6beb7e1c1b0c (diff)
downloadbcm5719-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/lib/Parse')
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp39
1 files changed, 38 insertions, 1 deletions
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;
OpenPOWER on IntegriCloud