From: Sebastian Redl Date: Fri, 30 Sep 2011 08:32:17 +0000 (+0000) Subject: Fix a bug in the token caching for inline constructors in C++11, and improve error... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a891a32d3762ee641a29c091d286f2a7432671a5;p=clang 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 --- 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(*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(*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{} {} +};