aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Redl <sebastian.redl@getdesigned.at>2011-09-30 08:32:17 +0000
committerSebastian Redl <sebastian.redl@getdesigned.at>2011-09-30 08:32:17 +0000
commita891a32d3762ee641a29c091d286f2a7432671a5 (patch)
tree46d7bf8dc01e934f17288c34fde07b78c183db20
parent8dfac0baaf0f81d3945bcb306480e358ba8d1f08 (diff)
Fix a bug in the token caching for inline constructors in C++11, and improve error recovery in both dialects. This should fix the GCC test suite failures as well.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140847 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Parse/Parser.h2
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp69
-rw-r--r--lib/Parse/ParseTemplate.cpp21
-rw-r--r--test/Parser/cxx-member-initializers.cpp5
-rw-r--r--test/Parser/cxx0x-member-initializers.cpp14
5 files changed, 69 insertions, 42 deletions
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 73e157bf31..93812c3863 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -1060,7 +1060,7 @@ private:
void ParseLexedMemberInitializers(ParsingClass &Class);
void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI);
Decl *ParseLexedObjCMethodDefs(LexedMethod &LM);
- bool ConsumeAndStoreTryAndInitializers(CachedTokens &Toks);
+ bool ConsumeAndStoreFunctionPrologue(CachedTokens &Toks);
bool ConsumeAndStoreUntil(tok::TokenKind T1,
CachedTokens &Toks,
bool StopAtSemi = true,
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 923a5587e6..40e36f0a0b 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -123,31 +123,24 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
CachedTokens &Toks = LM->Toks;
tok::TokenKind kind = Tok.getKind();
- // We may have a constructor initializer or function-try-block here.
- if (kind == tok::colon || kind == tok::kw_try) {
- // Consume everything up to (and including) the left brace of the
- // function body.
- if (ConsumeAndStoreTryAndInitializers(Toks)) {
- // We didn't find the left-brace we expected after the
- // constructor initializer.
- if (Tok.is(tok::semi)) {
- // We found a semicolon; complain, consume the semicolon, and
- // don't try to parse this method later.
- Diag(Tok.getLocation(), diag::err_expected_lbrace);
- ConsumeAnyToken();
- delete getCurrentClass().LateParsedDeclarations.back();
- getCurrentClass().LateParsedDeclarations.pop_back();
- return FnD;
- }
+ // Consume everything up to (and including) the left brace of the
+ // function body.
+ if (ConsumeAndStoreFunctionPrologue(Toks)) {
+ // We didn't find the left-brace we expected after the
+ // constructor initializer.
+ if (Tok.is(tok::semi)) {
+ // We found a semicolon; complain, consume the semicolon, and
+ // don't try to parse this method later.
+ Diag(Tok.getLocation(), diag::err_expected_lbrace);
+ ConsumeAnyToken();
+ delete getCurrentClass().LateParsedDeclarations.back();
+ getCurrentClass().LateParsedDeclarations.pop_back();
+ return FnD;
}
-
} else {
- // Begin by storing the '{' token.
- Toks.push_back(Tok);
- ConsumeBrace();
+ // Consume everything up to (and including) the matching right brace.
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
}
- // Consume everything up to (and including) the matching right brace.
- ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
// If we're in a function-try-block, we need to store all the catch blocks.
if (kind == tok::kw_try) {
@@ -583,10 +576,11 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
/// \brief Consume tokens and store them in the passed token container until
/// we've passed the try keyword and constructor initializers and have consumed
-/// the opening brace of the function body.
+/// the opening brace of the function body. The opening brace will be consumed
+/// if and only if there was no error.
///
-/// \return True on error.
-bool Parser::ConsumeAndStoreTryAndInitializers(CachedTokens &Toks) {
+/// \return True on error.
+bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
if (Tok.is(tok::kw_try)) {
Toks.push_back(Tok);
ConsumeToken();
@@ -613,6 +607,10 @@ bool Parser::ConsumeAndStoreTryAndInitializers(CachedTokens &Toks) {
else {
assert(kind == tok::l_brace && "Must be left paren or brace here.");
ConsumeBrace();
+ // In C++03, this has to be the start of the function body, which
+ // means the initializer is malformed.
+ if (!getLang().CPlusPlus0x)
+ return false;
}
// Grab the initializer
@@ -620,10 +618,25 @@ bool Parser::ConsumeAndStoreTryAndInitializers(CachedTokens &Toks) {
tok::r_brace,
Toks, /*StopAtSemi=*/true))
return true;
+
+ // Grab the separating comma, if any.
+ if (Tok.is(tok::comma)) {
+ Toks.push_back(Tok);
+ ConsumeToken();
+ }
}
}
- // Grab any remaining garbage to be diagnosed later, and the opening
- // brace of the function body.
- return !ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/true);
+ // Grab any remaining garbage to be diagnosed later. We stop when we reach a
+ // brace: an opening one is the function body, while a closing one probably
+ // means we've reached the end of the class.
+ if (!ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks,
+ /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false))
+ return true;
+ if(Tok.isNot(tok::l_brace))
+ return true;
+
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ return false;
}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 5ffd535337..4509662c65 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -1181,13 +1181,13 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
for (; II != DeclContextToReenter.rend(); ++II) {
if (ClassTemplatePartialSpecializationDecl* MD =
dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(*II)) {
- TemplateParamScopeStack.push_back(new ParseScope(this,
- Scope::TemplateParamScope));
+ TemplateParamScopeStack.push_back(new ParseScope(this,
+ Scope::TemplateParamScope));
Actions.ActOnReenterTemplateScope(getCurScope(), MD);
} else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(*II)) {
- TemplateParamScopeStack.push_back(new ParseScope(this,
- Scope::TemplateParamScope,
- MD->getDescribedClassTemplate() != 0 ));
+ TemplateParamScopeStack.push_back(new ParseScope(this,
+ Scope::TemplateParamScope,
+ MD->getDescribedClassTemplate() != 0 ));
Actions.ActOnReenterTemplateScope(getCurScope(),
MD->getDescribedClassTemplate());
}
@@ -1250,15 +1250,10 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
/// \brief Lex a delayed template function for late parsing.
void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) {
tok::TokenKind kind = Tok.getKind();
- // We may have a constructor initializer or function-try-block here.
- if (kind == tok::colon || kind == tok::kw_try)
- ConsumeAndStoreTryAndInitializers(Toks);
- else {
- Toks.push_back(Tok);
- ConsumeBrace();
+ if (!ConsumeAndStoreFunctionPrologue(Toks)) {
+ // Consume everything up to (and including) the matching right brace.
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
}
- // Consume everything up to (and including) the matching right brace.
- ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
// If we're in a function-try-block, we need to store all the catch blocks.
if (kind == tok::kw_try) {
diff --git a/test/Parser/cxx-member-initializers.cpp b/test/Parser/cxx-member-initializers.cpp
index 34a725ff43..5c3906836c 100644
--- a/test/Parser/cxx-member-initializers.cpp
+++ b/test/Parser/cxx-member-initializers.cpp
@@ -8,3 +8,8 @@ struct y {
int a;
y() : a(4) ; // expected-error {{expected '{'}}
};
+
+struct z {
+ int a;
+ z() : a {} // expected-error {{expected '('}}
+};
diff --git a/test/Parser/cxx0x-member-initializers.cpp b/test/Parser/cxx0x-member-initializers.cpp
index 6c3492ef21..b5714c1782 100644
--- a/test/Parser/cxx0x-member-initializers.cpp
+++ b/test/Parser/cxx0x-member-initializers.cpp
@@ -13,3 +13,17 @@ struct T {
int b = 2;
int c = b; // expected-error {{undeclared identifier}}
};
+
+// Test recovery for bad constructor initializers
+
+struct R1 {
+ int a;
+ R1() : a {}
+}; // expected-error {{expected '{' or ','}}
+
+// Test correct parsing.
+
+struct V1 {
+ int a, b;
+ V1() : a(), b{} {}
+};