From 222e2a7620e6520ffaf4fc4e69d79c18da31542e Mon Sep 17 00:00:00 2001 From: "Zancanaro; Carlo" Date: Mon, 24 Sep 2012 09:58:17 +1000 Subject: Add the clang library to the repo (with some of my changes, too). --- clang/lib/Parse/CMakeLists.txt | 19 + clang/lib/Parse/Makefile | 18 + clang/lib/Parse/ParseAST.cpp | 119 + clang/lib/Parse/ParseCXXInlineMethods.cpp | 697 +++++ clang/lib/Parse/ParseDecl.cpp | 4860 +++++++++++++++++++++++++++++ clang/lib/Parse/ParseDeclCXX.cpp | 3020 ++++++++++++++++++ clang/lib/Parse/ParseExpr.cpp | 2431 +++++++++++++++ clang/lib/Parse/ParseExprCXX.cpp | 2846 +++++++++++++++++ clang/lib/Parse/ParseInit.cpp | 547 ++++ clang/lib/Parse/ParseObjc.cpp | 2846 +++++++++++++++++ clang/lib/Parse/ParsePragma.cpp | 568 ++++ clang/lib/Parse/ParsePragma.h | 127 + clang/lib/Parse/ParseStmt.cpp | 2222 +++++++++++++ clang/lib/Parse/ParseTemplate.cpp | 1293 ++++++++ clang/lib/Parse/ParseTentative.cpp | 1444 +++++++++ clang/lib/Parse/Parser.cpp | 1720 ++++++++++ clang/lib/Parse/RAIIObjectsForParser.h | 142 + 17 files changed, 24919 insertions(+) create mode 100644 clang/lib/Parse/CMakeLists.txt create mode 100644 clang/lib/Parse/Makefile create mode 100644 clang/lib/Parse/ParseAST.cpp create mode 100644 clang/lib/Parse/ParseCXXInlineMethods.cpp create mode 100644 clang/lib/Parse/ParseDecl.cpp create mode 100644 clang/lib/Parse/ParseDeclCXX.cpp create mode 100644 clang/lib/Parse/ParseExpr.cpp create mode 100644 clang/lib/Parse/ParseExprCXX.cpp create mode 100644 clang/lib/Parse/ParseInit.cpp create mode 100644 clang/lib/Parse/ParseObjc.cpp create mode 100644 clang/lib/Parse/ParsePragma.cpp create mode 100644 clang/lib/Parse/ParsePragma.h create mode 100644 clang/lib/Parse/ParseStmt.cpp create mode 100644 clang/lib/Parse/ParseTemplate.cpp create mode 100644 clang/lib/Parse/ParseTentative.cpp create mode 100644 clang/lib/Parse/Parser.cpp create mode 100644 clang/lib/Parse/RAIIObjectsForParser.h (limited to 'clang/lib/Parse') diff --git a/clang/lib/Parse/CMakeLists.txt b/clang/lib/Parse/CMakeLists.txt new file mode 100644 index 0000000..6c980ce --- /dev/null +++ b/clang/lib/Parse/CMakeLists.txt @@ -0,0 +1,19 @@ +set(LLVM_USED_LIBS clangBasic clangAST clangLex clangSema) + +add_clang_library(clangParse + ParseAST.cpp + ParseCXXInlineMethods.cpp + ParseDecl.cpp + ParseDeclCXX.cpp + ParseExpr.cpp + ParseExprCXX.cpp + ParseInit.cpp + ParseObjc.cpp + ParsePragma.cpp + ParseStmt.cpp + ParseTemplate.cpp + ParseTentative.cpp + Parser.cpp + ) + +add_dependencies(clangParse ClangAttrClasses ClangAttrList ClangDeclNodes ClangDiagnosticParse ClangStmtNodes ClangAttrLateParsed) diff --git a/clang/lib/Parse/Makefile b/clang/lib/Parse/Makefile new file mode 100644 index 0000000..5ec7c33 --- /dev/null +++ b/clang/lib/Parse/Makefile @@ -0,0 +1,18 @@ +##===- clang/lib/Parse/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements the Parser library for the C-Language front-end. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../.. +LIBRARYNAME := clangParse + +include $(CLANG_LEVEL)/Makefile + diff --git a/clang/lib/Parse/ParseAST.cpp b/clang/lib/Parse/ParseAST.cpp new file mode 100644 index 0000000..d1c2624 --- /dev/null +++ b/clang/lib/Parse/ParseAST.cpp @@ -0,0 +1,119 @@ +//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the clang::ParseAST method. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/ParseAST.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/Sema/SemaConsumer.h" +#include "clang/Sema/ExternalSemaSource.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/Stmt.h" +#include "clang/Parse/Parser.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/CrashRecoveryContext.h" +#include + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Public interface to the file +//===----------------------------------------------------------------------===// + +/// ParseAST - Parse the entire file specified, notifying the ASTConsumer as +/// the file is parsed. This inserts the parsed decls into the translation unit +/// held by Ctx. +/// +void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, + ASTContext &Ctx, bool PrintStats, + TranslationUnitKind TUKind, + CodeCompleteConsumer *CompletionConsumer, + bool SkipFunctionBodies) { + + OwningPtr S(new Sema(PP, Ctx, *Consumer, + TUKind, + CompletionConsumer)); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar CleanupSema(S.get()); + + ParseAST(*S.get(), PrintStats, SkipFunctionBodies); +} + +void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { + // Collect global stats on Decls/Stmts (until we have a module streamer). + if (PrintStats) { + Decl::EnableStatistics(); + Stmt::EnableStatistics(); + } + + // Also turn on collection of stats inside of the Sema object. + bool OldCollectStats = PrintStats; + std::swap(OldCollectStats, S.CollectStats); + + ASTConsumer *Consumer = &S.getASTConsumer(); + + OwningPtr ParseOP(new Parser(S.getPreprocessor(), S, + SkipFunctionBodies)); + Parser &P = *ParseOP.get(); + + PrettyStackTraceParserEntry CrashInfo(P); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar + CleanupParser(ParseOP.get()); + + S.getPreprocessor().EnterMainSourceFile(); + P.Initialize(); + S.Initialize(); + + if (ExternalASTSource *External = S.getASTContext().getExternalSource()) + External->StartTranslationUnit(Consumer); + + bool Abort = false; + Parser::DeclGroupPtrTy ADecl; + + while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. + // If we got a null return and something *was* parsed, ignore it. This + // is due to a top-level semicolon, an action override, or a parse error + // skipping something. + if (ADecl) { + if (!Consumer->HandleTopLevelDecl(ADecl.get())) { + Abort = true; + break; + } + } + }; + + if (Abort) + return; + + // Process any TopLevelDecls generated by #pragma weak. + for (SmallVector::iterator + I = S.WeakTopLevelDecls().begin(), + E = S.WeakTopLevelDecls().end(); I != E; ++I) + Consumer->HandleTopLevelDecl(DeclGroupRef(*I)); + + Consumer->HandleTranslationUnit(S.getASTContext()); + + std::swap(OldCollectStats, S.CollectStats); + if (PrintStats) { + llvm::errs() << "\nSTATISTICS:\n"; + P.getActions().PrintStats(); + S.getASTContext().PrintStats(); + Decl::PrintStats(); + Stmt::PrintStats(); + Consumer->PrintStats(); + } +} diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp new file mode 100644 index 0000000..c7b29d9 --- /dev/null +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -0,0 +1,697 @@ +//===--- ParseCXXInlineMethods.cpp - C++ class inline methods parsing------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements parsing for C++ class inline methods. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Scope.h" +#include "clang/AST/DeclTemplate.h" +using namespace clang; + +/// ParseCXXInlineMethodDef - We parsed and verified that the specified +/// Declarator is a well formed C++ inline method definition. Now lex its body +/// and store its tokens for parsing after the C++ class is complete. +Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, + AttributeList *AccessAttrs, + ParsingDeclarator &D, + const ParsedTemplateInfo &TemplateInfo, + const VirtSpecifiers& VS, + FunctionDefinitionKind DefinitionKind, + ExprResult& Init) { + assert(D.isFunctionDeclarator() && "This isn't a function declarator!"); + assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try) || + Tok.is(tok::equal)) && + "Current token not a '{', ':', '=', or 'try'!"); + + MultiTemplateParamsArg TemplateParams(Actions, + TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0, + TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0); + + Decl *FnD; + D.setFunctionDefinitionKind(DefinitionKind); + if (D.getDeclSpec().isFriendSpecified()) + FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, + move(TemplateParams)); + else { + FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D, + move(TemplateParams), 0, + VS, /*HasDeferredInit=*/false); + if (FnD) { + Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, + false, true); + bool TypeSpecContainsAuto + = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + if (Init.isUsable()) + Actions.AddInitializerToDecl(FnD, Init.get(), false, + TypeSpecContainsAuto); + else + Actions.ActOnUninitializedDecl(FnD, TypeSpecContainsAuto); + } + } + + HandleMemberFunctionDeclDelays(D, FnD); + + D.complete(FnD); + + if (Tok.is(tok::equal)) { + ConsumeToken(); + + if (!FnD) { + SkipUntil(tok::semi); + return 0; + } + + bool Delete = false; + SourceLocation KWLoc; + if (Tok.is(tok::kw_delete)) { + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_deleted_function : + diag::ext_deleted_function); + + KWLoc = ConsumeToken(); + Actions.SetDeclDeleted(FnD, KWLoc); + Delete = true; + } else if (Tok.is(tok::kw_default)) { + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_defaulted_function : + diag::ext_defaulted_function); + + KWLoc = ConsumeToken(); + Actions.SetDeclDefaulted(FnD, KWLoc); + } else { + llvm_unreachable("function definition after = not 'delete' or 'default'"); + } + + if (Tok.is(tok::comma)) { + Diag(KWLoc, diag::err_default_delete_in_multiple_declaration) + << Delete; + SkipUntil(tok::semi); + } else { + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, + Delete ? "delete" : "default", tok::semi); + } + + return FnD; + } + + // In delayed template parsing mode, if we are within a class template + // or if we are about to parse function member template then consume + // the tokens and store them for parsing at the end of the translation unit. + if (getLangOpts().DelayedTemplateParsing && + ((Actions.CurContext->isDependentContext() || + TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) && + !Actions.IsInsideALocalClassWithinATemplateFunction())) { + + if (FnD) { + LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(FnD); + + FunctionDecl *FD = 0; + if (FunctionTemplateDecl *FunTmpl = dyn_cast(FnD)) + FD = FunTmpl->getTemplatedDecl(); + else + FD = cast(FnD); + Actions.CheckForFunctionRedefinition(FD); + + LateParsedTemplateMap[FD] = LPT; + Actions.MarkAsLateParsedTemplate(FD); + LexTemplateFunctionForLateParsing(LPT->Toks); + } else { + CachedTokens Toks; + LexTemplateFunctionForLateParsing(Toks); + } + + return FnD; + } + + // Consume the tokens and store them for later parsing. + + LexedMethod* LM = new LexedMethod(this, FnD); + getCurrentClass().LateParsedDeclarations.push_back(LM); + LM->TemplateScope = getCurScope()->isTemplateParamScope(); + CachedTokens &Toks = LM->Toks; + + tok::TokenKind kind = Tok.getKind(); + // 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; we already printed an error, and it's likely + // impossible to recover, so don't try to parse this method later. + // If we stopped at a semicolon, consume it to avoid an extra warning. + if (Tok.is(tok::semi)) + ConsumeToken(); + delete getCurrentClass().LateParsedDeclarations.back(); + getCurrentClass().LateParsedDeclarations.pop_back(); + return FnD; + } else { + // 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) { + while (Tok.is(tok::kw_catch)) { + ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); + } + } + + + if (!FnD) { + // If semantic analysis could not build a function declaration, + // just throw away the late-parsed declaration. + delete getCurrentClass().LateParsedDeclarations.back(); + getCurrentClass().LateParsedDeclarations.pop_back(); + } + + return FnD; +} + +/// ParseCXXNonStaticMemberInitializer - We parsed and verified that the +/// specified Declarator is a well formed C++ non-static data member +/// declaration. Now lex its initializer and store its tokens for parsing +/// after the class is complete. +void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) { + assert((Tok.is(tok::l_brace) || Tok.is(tok::equal)) && + "Current token not a '{' or '='!"); + + LateParsedMemberInitializer *MI = + new LateParsedMemberInitializer(this, VarD); + getCurrentClass().LateParsedDeclarations.push_back(MI); + CachedTokens &Toks = MI->Toks; + + tok::TokenKind kind = Tok.getKind(); + if (kind == tok::equal) { + Toks.push_back(Tok); + ConsumeToken(); + } + + if (kind == tok::l_brace) { + // 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=*/true); + } else { + // Consume everything up to (but excluding) the comma or semicolon. + ConsumeAndStoreUntil(tok::comma, Toks, /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/false); + } + + // Store an artificial EOF token to ensure that we don't run off the end of + // the initializer when we come to parse it. + Token Eof; + Eof.startToken(); + Eof.setKind(tok::eof); + Eof.setLocation(Tok.getLocation()); + Toks.push_back(Eof); +} + +Parser::LateParsedDeclaration::~LateParsedDeclaration() {} +void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {} +void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {} +void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {} + +Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C) + : Self(P), Class(C) {} + +Parser::LateParsedClass::~LateParsedClass() { + Self->DeallocateParsedClasses(Class); +} + +void Parser::LateParsedClass::ParseLexedMethodDeclarations() { + Self->ParseLexedMethodDeclarations(*Class); +} + +void Parser::LateParsedClass::ParseLexedMemberInitializers() { + Self->ParseLexedMemberInitializers(*Class); +} + +void Parser::LateParsedClass::ParseLexedMethodDefs() { + Self->ParseLexedMethodDefs(*Class); +} + +void Parser::LateParsedMethodDeclaration::ParseLexedMethodDeclarations() { + Self->ParseLexedMethodDeclaration(*this); +} + +void Parser::LexedMethod::ParseLexedMethodDefs() { + Self->ParseLexedMethodDef(*this); +} + +void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() { + Self->ParseLexedMemberInitializer(*this); +} + +/// ParseLexedMethodDeclarations - We finished parsing the member +/// specification of a top (non-nested) C++ class. Now go over the +/// stack of method declarations with some parts for which parsing was +/// delayed (such as default arguments) and parse them. +void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { + bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; + ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); + if (HasTemplateScope) + Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); + + // The current scope is still active if we're the top-level class. + // Otherwise we'll need to push and enter a new scope. + bool HasClassScope = !Class.TopLevelClass; + ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, + HasClassScope); + if (HasClassScope) + Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); + + for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { + Class.LateParsedDeclarations[i]->ParseLexedMethodDeclarations(); + } + + if (HasClassScope) + Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); +} + +void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { + // If this is a member template, introduce the template parameter scope. + ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); + if (LM.TemplateScope) + Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method); + + // Start the delayed C++ method declaration + Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method); + + // Introduce the parameters into scope and parse their default + // arguments. + ParseScope PrototypeScope(this, + Scope::FunctionPrototypeScope|Scope::DeclScope); + for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { + // Introduce the parameter into scope. + Actions.ActOnDelayedCXXMethodParameter(getCurScope(), + LM.DefaultArgs[I].Param); + + if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { + // Save the current token position. + SourceLocation origLoc = Tok.getLocation(); + + // Parse the default argument from its saved token stream. + Toks->push_back(Tok); // So that the current token doesn't get lost + PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false); + + // Consume the previously-pushed token. + ConsumeAnyToken(); + + // Consume the '='. + assert(Tok.is(tok::equal) && "Default argument not starting with '='"); + SourceLocation EqualLoc = ConsumeToken(); + + // The argument isn't actually potentially evaluated unless it is + // used. + EnterExpressionEvaluationContext Eval(Actions, + Sema::PotentiallyEvaluatedIfUsed, + LM.DefaultArgs[I].Param); + + ExprResult DefArgResult; + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + DefArgResult = ParseBraceInitializer(); + } else + DefArgResult = ParseAssignmentExpression(); + if (DefArgResult.isInvalid()) + Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param); + else { + if (Tok.is(tok::cxx_defaultarg_end)) + ConsumeToken(); + else + Diag(Tok.getLocation(), diag::err_default_arg_unparsed); + Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc, + DefArgResult.take()); + } + + assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, + Tok.getLocation()) && + "ParseAssignmentExpression went over the default arg tokens!"); + // There could be leftover tokens (e.g. because of an error). + // Skip through until we reach the original token position. + while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) + ConsumeAnyToken(); + + delete Toks; + LM.DefaultArgs[I].Toks = 0; + } + } + + PrototypeScope.Exit(); + + // Finish the delayed C++ method declaration. + Actions.ActOnFinishDelayedCXXMethodDeclaration(getCurScope(), LM.Method); +} + +/// ParseLexedMethodDefs - We finished parsing the member specification of a top +/// (non-nested) C++ class. Now go over the stack of lexed methods that were +/// collected during its parsing and parse them all. +void Parser::ParseLexedMethodDefs(ParsingClass &Class) { + bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; + ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); + if (HasTemplateScope) + Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); + + bool HasClassScope = !Class.TopLevelClass; + ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, + HasClassScope); + + for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { + Class.LateParsedDeclarations[i]->ParseLexedMethodDefs(); + } +} + +void Parser::ParseLexedMethodDef(LexedMethod &LM) { + // If this is a member template, introduce the template parameter scope. + ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); + if (LM.TemplateScope) + Actions.ActOnReenterTemplateScope(getCurScope(), LM.D); + + // Save the current token position. + SourceLocation origLoc = Tok.getLocation(); + + assert(!LM.Toks.empty() && "Empty body!"); + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + LM.Toks.push_back(Tok); + PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); + + // Consume the previously pushed token. + ConsumeAnyToken(); + assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) + && "Inline method not starting with '{', ':' or 'try'"); + + // Parse the method body. Function body parsing code is similar enough + // to be re-used for method bodies as well. + ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); + Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D); + + if (Tok.is(tok::kw_try)) { + ParseFunctionTryBlock(LM.D, FnScope); + assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, + Tok.getLocation()) && + "ParseFunctionTryBlock went over the cached tokens!"); + // There could be leftover tokens (e.g. because of an error). + // Skip through until we reach the original token position. + while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) + ConsumeAnyToken(); + return; + } + if (Tok.is(tok::colon)) { + ParseConstructorInitializer(LM.D); + + // Error recovery. + if (!Tok.is(tok::l_brace)) { + FnScope.Exit(); + Actions.ActOnFinishFunctionBody(LM.D, 0); + while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) + ConsumeAnyToken(); + return; + } + } else + Actions.ActOnDefaultCtorInitializers(LM.D); + + ParseFunctionStatementBody(LM.D, FnScope); + + if (Tok.getLocation() != origLoc) { + // Due to parsing error, we either went over the cached tokens or + // there are still cached tokens left. If it's the latter case skip the + // leftover tokens. + // Since this is an uncommon situation that should be avoided, use the + // expensive isBeforeInTranslationUnit call. + if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(), + origLoc)) + while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) + ConsumeAnyToken(); + } +} + +/// ParseLexedMemberInitializers - We finished parsing the member specification +/// of a top (non-nested) C++ class. Now go over the stack of lexed data member +/// initializers that were collected during its parsing and parse them all. +void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { + bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; + ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, + HasTemplateScope); + if (HasTemplateScope) + Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); + + // Set or update the scope flags. + bool AlreadyHasClassScope = Class.TopLevelClass; + unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope; + ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope); + ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope); + + if (!AlreadyHasClassScope) + Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), + Class.TagOrTemplate); + + { + // C++11 [expr.prim.general]p4: + // Otherwise, if a member-declarator declares a non-static data member + // (9.2) of a class X, the expression this is a prvalue of type "pointer + // to X" within the optional brace-or-equal-initializer. It shall not + // appear elsewhere in the member-declarator. + Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate, + /*TypeQuals=*/(unsigned)0); + + for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { + Class.LateParsedDeclarations[i]->ParseLexedMemberInitializers(); + } + } + + if (!AlreadyHasClassScope) + Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), + Class.TagOrTemplate); + + Actions.ActOnFinishDelayedMemberInitializers(Class.TagOrTemplate); +} + +void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { + if (!MI.Field || MI.Field->isInvalidDecl()) + return; + + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + MI.Toks.push_back(Tok); + PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false); + + // Consume the previously pushed token. + ConsumeAnyToken(); + + SourceLocation EqualLoc; + + ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false, + EqualLoc); + + Actions.ActOnCXXInClassMemberInitializer(MI.Field, EqualLoc, Init.release()); + + // The next token should be our artificial terminating EOF token. + if (Tok.isNot(tok::eof)) { + SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation); + if (!EndLoc.isValid()) + EndLoc = Tok.getLocation(); + // No fixit; we can't recover as if there were a semicolon here. + Diag(EndLoc, diag::err_expected_semi_decl_list); + + // Consume tokens until we hit the artificial EOF. + while (Tok.isNot(tok::eof)) + ConsumeAnyToken(); + } + ConsumeAnyToken(); +} + +/// ConsumeAndStoreUntil - Consume and store the token at the passed token +/// container until the token 'T' is reached (which gets +/// consumed/stored too, if ConsumeFinalToken). +/// If StopAtSemi is true, then we will stop early at a ';' character. +/// Returns true if token 'T1' or 'T2' was found. +/// NOTE: This is a specialized version of Parser::SkipUntil. +bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, + CachedTokens &Toks, + bool StopAtSemi, bool ConsumeFinalToken) { + // We always want this function to consume at least one token if the first + // token isn't T and if not at EOF. + bool isFirstTokenConsumed = true; + while (1) { + // If we found one of the tokens, stop and return true. + if (Tok.is(T1) || Tok.is(T2)) { + if (ConsumeFinalToken) { + Toks.push_back(Tok); + ConsumeAnyToken(); + } + return true; + } + + switch (Tok.getKind()) { + case tok::eof: + // Ran out of tokens. + return false; + + case tok::l_paren: + // Recursively consume properly-nested parens. + Toks.push_back(Tok); + ConsumeParen(); + ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false); + break; + case tok::l_square: + // Recursively consume properly-nested square brackets. + Toks.push_back(Tok); + ConsumeBracket(); + ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/false); + break; + case tok::l_brace: + // Recursively consume properly-nested braces. + Toks.push_back(Tok); + ConsumeBrace(); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); + break; + + // Okay, we found a ']' or '}' or ')', which we think should be balanced. + // Since the user wasn't looking for this token (if they were, it would + // already be handled), this isn't balanced. If there is a LHS token at a + // higher level, we will assume that this matches the unbalanced token + // and return it. Otherwise, this is a spurious RHS token, which we skip. + case tok::r_paren: + if (ParenCount && !isFirstTokenConsumed) + return false; // Matches something. + Toks.push_back(Tok); + ConsumeParen(); + break; + case tok::r_square: + if (BracketCount && !isFirstTokenConsumed) + return false; // Matches something. + Toks.push_back(Tok); + ConsumeBracket(); + break; + case tok::r_brace: + if (BraceCount && !isFirstTokenConsumed) + return false; // Matches something. + Toks.push_back(Tok); + ConsumeBrace(); + break; + + case tok::code_completion: + Toks.push_back(Tok); + ConsumeCodeCompletionToken(); + break; + + case tok::string_literal: + case tok::wide_string_literal: + case tok::utf8_string_literal: + case tok::utf16_string_literal: + case tok::utf32_string_literal: + Toks.push_back(Tok); + ConsumeStringToken(); + break; + case tok::semi: + if (StopAtSemi) + return false; + // FALL THROUGH. + default: + // consume this token. + Toks.push_back(Tok); + ConsumeToken(); + break; + } + isFirstTokenConsumed = false; + } +} + +/// \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 will be consumed +/// if and only if there was no error. +/// +/// \return True on error. +bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { + if (Tok.is(tok::kw_try)) { + Toks.push_back(Tok); + ConsumeToken(); + } + bool ReadInitializer = false; + if (Tok.is(tok::colon)) { + // Initializers can contain braces too. + Toks.push_back(Tok); + ConsumeToken(); + + while (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) { + if (Tok.is(tok::eof) || Tok.is(tok::semi)) + return Diag(Tok.getLocation(), diag::err_expected_lbrace); + + // Grab the identifier. + if (!ConsumeAndStoreUntil(tok::l_paren, tok::l_brace, Toks, + /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/false)) + return Diag(Tok.getLocation(), diag::err_expected_lparen); + + tok::TokenKind kind = Tok.getKind(); + Toks.push_back(Tok); + bool IsLParen = (kind == tok::l_paren); + SourceLocation LOpen = Tok.getLocation(); + + if (IsLParen) { + ConsumeParen(); + } 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; we'll diagnose it later. + if (!getLangOpts().CPlusPlus0x) + return false; + } + + // Grab the initializer + if (!ConsumeAndStoreUntil(IsLParen ? tok::r_paren : tok::r_brace, + Toks, /*StopAtSemi=*/true)) { + Diag(Tok, IsLParen ? diag::err_expected_rparen : + diag::err_expected_rbrace); + Diag(LOpen, diag::note_matching) << (IsLParen ? "(" : "{"); + return true; + } + + // Grab pack ellipsis, if present + if (Tok.is(tok::ellipsis)) { + Toks.push_back(Tok); + ConsumeToken(); + } + + // Grab the separating comma, if any. + if (Tok.is(tok::comma)) { + Toks.push_back(Tok); + ConsumeToken(); + } else if (Tok.isNot(tok::l_brace)) { + ReadInitializer = true; + break; + } + } + } + + // 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. + ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks, + /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/false); + if (Tok.isNot(tok::l_brace)) { + if (ReadInitializer) + return Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma); + return Diag(Tok.getLocation(), diag::err_expected_lbrace); + } + + Toks.push_back(Tok); + ConsumeBrace(); + return false; +} diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp new file mode 100644 index 0000000..7995e68 --- /dev/null +++ b/clang/lib/Parse/ParseDecl.cpp @@ -0,0 +1,4860 @@ +//===--- ParseDecl.cpp - Declaration Parsing ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Declaration portions of the Parser interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Basic/OpenCL.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/PrettyDeclStackTrace.h" +#include "RAIIObjectsForParser.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// C99 6.7: Declarations. +//===----------------------------------------------------------------------===// + +/// ParseTypeName +/// type-name: [C99 6.7.6] +/// specifier-qualifier-list abstract-declarator[opt] +/// +/// Called type-id in C++. +TypeResult Parser::ParseTypeName(SourceRange *Range, + Declarator::TheContext Context, + AccessSpecifier AS, + Decl **OwnedType) { + DeclSpecContext DSC = getDeclSpecContextFromDeclaratorContext(Context); + + // Parse the common declaration-specifiers piece. + DeclSpec DS(AttrFactory); + ParseSpecifierQualifierList(DS, AS, DSC); + if (OwnedType) + *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0; + + // Parse the abstract-declarator, if present. + Declarator DeclaratorInfo(DS, Context); + ParseDeclarator(DeclaratorInfo); + if (Range) + *Range = DeclaratorInfo.getSourceRange(); + + if (DeclaratorInfo.isInvalidType()) + return true; + + return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); +} + + +/// isAttributeLateParsed - Return true if the attribute has arguments that +/// require late parsing. +static bool isAttributeLateParsed(const IdentifierInfo &II) { + return llvm::StringSwitch(II.getName()) +#include "clang/Parse/AttrLateParsed.inc" + .Default(false); +} + + +/// ParseGNUAttributes - Parse a non-empty attributes list. +/// +/// [GNU] attributes: +/// attribute +/// attributes attribute +/// +/// [GNU] attribute: +/// '__attribute__' '(' '(' attribute-list ')' ')' +/// +/// [GNU] attribute-list: +/// attrib +/// attribute_list ',' attrib +/// +/// [GNU] attrib: +/// empty +/// attrib-name +/// attrib-name '(' identifier ')' +/// attrib-name '(' identifier ',' nonempty-expr-list ')' +/// attrib-name '(' argument-expression-list [C99 6.5.2] ')' +/// +/// [GNU] attrib-name: +/// identifier +/// typespec +/// typequal +/// storageclass +/// +/// FIXME: The GCC grammar/code for this construct implies we need two +/// token lookahead. Comment from gcc: "If they start with an identifier +/// which is followed by a comma or close parenthesis, then the arguments +/// start with that identifier; otherwise they are an expression list." +/// +/// GCC does not require the ',' between attribs in an attribute-list. +/// +/// At the moment, I am not doing 2 token lookahead. I am also unaware of +/// any attributes that don't work (based on my limited testing). Most +/// attributes are very simple in practice. Until we find a bug, I don't see +/// a pressing need to implement the 2 token lookahead. + +void Parser::ParseGNUAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc, + LateParsedAttrList *LateAttrs) { + assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); + + while (Tok.is(tok::kw___attribute)) { + ConsumeToken(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, + "attribute")) { + SkipUntil(tok::r_paren, true); // skip until ) or ; + return; + } + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) { + SkipUntil(tok::r_paren, true); // skip until ) or ; + return; + } + // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") )) + while (Tok.is(tok::identifier) || isDeclarationSpecifier() || + Tok.is(tok::comma)) { + if (Tok.is(tok::comma)) { + // allows for empty/non-empty attributes. ((__vector_size__(16),,,,)) + ConsumeToken(); + continue; + } + // we have an identifier or declaration specifier (const, int, etc.) + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + + if (Tok.is(tok::l_paren)) { + // handle "parameterized" attributes + if (LateAttrs && isAttributeLateParsed(*AttrName)) { + LateParsedAttribute *LA = + new LateParsedAttribute(this, *AttrName, AttrNameLoc); + LateAttrs->push_back(LA); + + // Attributes in a class are parsed at the end of the class, along + // with other late-parsed declarations. + if (!ClassStack.empty()) + getCurrentClass().LateParsedDeclarations.push_back(LA); + + // consume everything up to and including the matching right parens + ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false); + + Token Eof; + Eof.startToken(); + Eof.setLocation(Tok.getLocation()); + LA->Toks.push_back(Eof); + } else { + ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc); + } + } else { + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0); + } + } + if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) + SkipUntil(tok::r_paren, false); + SourceLocation Loc = Tok.getLocation(); + if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { + SkipUntil(tok::r_paren, false); + } + if (endLoc) + *endLoc = Loc; + } +} + + +/// Parse the arguments to a parameterized GNU attribute +void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc) { + + assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); + + // Availability attributes have their own grammar. + if (AttrName->isStr("availability")) { + ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); + return; + } + // Thread safety attributes fit into the FIXME case above, so we + // just parse the arguments as a list of expressions + if (IsThreadSafetyAttribute(AttrName->getName())) { + ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); + return; + } + + ConsumeParen(); // ignore the left paren loc for now + + IdentifierInfo *ParmName = 0; + SourceLocation ParmLoc; + bool BuiltinType = false; + + switch (Tok.getKind()) { + case tok::kw_char: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_bool: + case tok::kw_short: + case tok::kw_int: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_float: + case tok::kw_double: + case tok::kw_void: + case tok::kw_typeof: + // __attribute__(( vec_type_hint(char) )) + // FIXME: Don't just discard the builtin type token. + ConsumeToken(); + BuiltinType = true; + break; + + case tok::identifier: + ParmName = Tok.getIdentifierInfo(); + ParmLoc = ConsumeToken(); + break; + + default: + break; + } + + ExprVector ArgExprs(Actions); + + if (!BuiltinType && + (ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) { + // Eat the comma. + if (ParmLoc.isValid()) + ConsumeToken(); + + // Parse the non-empty comma-separated list of expressions. + while (1) { + ExprResult ArgExpr(ParseAssignmentExpression()); + if (ArgExpr.isInvalid()) { + SkipUntil(tok::r_paren); + return; + } + ArgExprs.push_back(ArgExpr.release()); + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // Eat the comma, move to the next argument + } + } + else if (Tok.is(tok::less) && AttrName->isStr("iboutletcollection")) { + if (!ExpectAndConsume(tok::less, diag::err_expected_less_after, "<", + tok::greater)) { + while (Tok.is(tok::identifier)) { + ConsumeToken(); + if (Tok.is(tok::greater)) + break; + if (Tok.is(tok::comma)) { + ConsumeToken(); + continue; + } + } + if (Tok.isNot(tok::greater)) + Diag(Tok, diag::err_iboutletcollection_with_protocol); + SkipUntil(tok::r_paren, false, true); // skip until ')' + } + } + + SourceLocation RParen = Tok.getLocation(); + if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { + AttributeList *attr = + Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc, + ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size()); + if (BuiltinType && attr->getKind() == AttributeList::AT_iboutletcollection) + Diag(Tok, diag::err_iboutletcollection_builtintype); + } +} + + +/// ParseMicrosoftDeclSpec - Parse an __declspec construct +/// +/// [MS] decl-specifier: +/// __declspec ( extended-decl-modifier-seq ) +/// +/// [MS] extended-decl-modifier-seq: +/// extended-decl-modifier[opt] +/// extended-decl-modifier extended-decl-modifier-seq + +void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) { + assert(Tok.is(tok::kw___declspec) && "Not a declspec!"); + + ConsumeToken(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, + "declspec")) { + SkipUntil(tok::r_paren, true); // skip until ) or ; + return; + } + + while (Tok.getIdentifierInfo()) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + + // FIXME: Remove this when we have proper __declspec(property()) support. + // Just skip everything inside property(). + if (AttrName->getName() == "property") { + ConsumeParen(); + SkipUntil(tok::r_paren); + } + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + // FIXME: This doesn't parse __declspec(property(get=get_func_name)) + // correctly. + ExprResult ArgExpr(ParseAssignmentExpression()); + if (!ArgExpr.isInvalid()) { + Expr *ExprList = ArgExpr.take(); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), &ExprList, 1, true); + } + if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) + SkipUntil(tok::r_paren, false); + } else { + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0, true); + } + } + if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) + SkipUntil(tok::r_paren, false); + return; +} + +void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { + // Treat these like attributes + // FIXME: Allow Sema to distinguish between these and real attributes! + while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) || + Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) || + Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) || + Tok.is(tok::kw___ptr32) || + Tok.is(tok::kw___unaligned)) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) || + Tok.is(tok::kw___ptr32)) + // FIXME: Support these properly! + continue; + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, true); + } +} + +void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { + // Treat these like attributes + while (Tok.is(tok::kw___pascal)) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, true); + } +} + +void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) { + // Treat these like attributes + while (Tok.is(tok::kw___kernel)) { + SourceLocation AttrNameLoc = ConsumeToken(); + attrs.addNew(PP.getIdentifierInfo("opencl_kernel_function"), + AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, false); + } +} + +void Parser::ParseOpenCLQualifiers(DeclSpec &DS) { + SourceLocation Loc = Tok.getLocation(); + switch(Tok.getKind()) { + // OpenCL qualifiers: + case tok::kw___private: + case tok::kw_private: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("address_space"), Loc, 0); + break; + + case tok::kw___global: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_global); + break; + + case tok::kw___local: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_local); + break; + + case tok::kw___constant: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_constant); + break; + + case tok::kw___read_only: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_only); + break; + + case tok::kw___write_only: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_write_only); + break; + + case tok::kw___read_write: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_write); + break; + default: break; + } +} + +/// \brief Parse a version number. +/// +/// version: +/// simple-integer +/// simple-integer ',' simple-integer +/// simple-integer ',' simple-integer ',' simple-integer +VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { + Range = Tok.getLocation(); + + if (!Tok.is(tok::numeric_constant)) { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + + // Parse the major (and possibly minor and subminor) versions, which + // are stored in the numeric constant. We utilize a quirk of the + // lexer, which is that it handles something like 1.2.3 as a single + // numeric constant, rather than two separate tokens. + SmallString<512> Buffer; + Buffer.resize(Tok.getLength()+1); + const char *ThisTokBegin = &Buffer[0]; + + // Get the spelling of the token, which eliminates trigraphs, etc. + bool Invalid = false; + unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin, &Invalid); + if (Invalid) + return VersionTuple(); + + // Parse the major version. + unsigned AfterMajor = 0; + unsigned Major = 0; + while (AfterMajor < ActualLength && isdigit(ThisTokBegin[AfterMajor])) { + Major = Major * 10 + ThisTokBegin[AfterMajor] - '0'; + ++AfterMajor; + } + + if (AfterMajor == 0) { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + + if (AfterMajor == ActualLength) { + ConsumeToken(); + + // We only had a single version component. + if (Major == 0) { + Diag(Tok, diag::err_zero_version); + return VersionTuple(); + } + + return VersionTuple(Major); + } + + if (ThisTokBegin[AfterMajor] != '.' || (AfterMajor + 1 == ActualLength)) { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + + // Parse the minor version. + unsigned AfterMinor = AfterMajor + 1; + unsigned Minor = 0; + while (AfterMinor < ActualLength && isdigit(ThisTokBegin[AfterMinor])) { + Minor = Minor * 10 + ThisTokBegin[AfterMinor] - '0'; + ++AfterMinor; + } + + if (AfterMinor == ActualLength) { + ConsumeToken(); + + // We had major.minor. + if (Major == 0 && Minor == 0) { + Diag(Tok, diag::err_zero_version); + return VersionTuple(); + } + + return VersionTuple(Major, Minor); + } + + // If what follows is not a '.', we have a problem. + if (ThisTokBegin[AfterMinor] != '.') { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + + // Parse the subminor version. + unsigned AfterSubminor = AfterMinor + 1; + unsigned Subminor = 0; + while (AfterSubminor < ActualLength && isdigit(ThisTokBegin[AfterSubminor])) { + Subminor = Subminor * 10 + ThisTokBegin[AfterSubminor] - '0'; + ++AfterSubminor; + } + + if (AfterSubminor != ActualLength) { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + ConsumeToken(); + return VersionTuple(Major, Minor, Subminor); +} + +/// \brief Parse the contents of the "availability" attribute. +/// +/// availability-attribute: +/// 'availability' '(' platform ',' version-arg-list, opt-message')' +/// +/// platform: +/// identifier +/// +/// version-arg-list: +/// version-arg +/// version-arg ',' version-arg-list +/// +/// version-arg: +/// 'introduced' '=' version +/// 'deprecated' '=' version +/// 'obsoleted' = version +/// 'unavailable' +/// opt-message: +/// 'message' '=' +void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, + SourceLocation AvailabilityLoc, + ParsedAttributes &attrs, + SourceLocation *endLoc) { + SourceLocation PlatformLoc; + IdentifierInfo *Platform = 0; + + enum { Introduced, Deprecated, Obsoleted, Unknown }; + AvailabilityChange Changes[Unknown]; + ExprResult MessageExpr; + + // Opening '('. + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { + Diag(Tok, diag::err_expected_lparen); + return; + } + + // Parse the platform name, + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_availability_expected_platform); + SkipUntil(tok::r_paren); + return; + } + Platform = Tok.getIdentifierInfo(); + PlatformLoc = ConsumeToken(); + + // Parse the ',' following the platform name. + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::r_paren)) + return; + + // If we haven't grabbed the pointers for the identifiers + // "introduced", "deprecated", and "obsoleted", do so now. + if (!Ident_introduced) { + Ident_introduced = PP.getIdentifierInfo("introduced"); + Ident_deprecated = PP.getIdentifierInfo("deprecated"); + Ident_obsoleted = PP.getIdentifierInfo("obsoleted"); + Ident_unavailable = PP.getIdentifierInfo("unavailable"); + Ident_message = PP.getIdentifierInfo("message"); + } + + // Parse the set of introductions/deprecations/removals. + SourceLocation UnavailableLoc; + do { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_availability_expected_change); + SkipUntil(tok::r_paren); + return; + } + IdentifierInfo *Keyword = Tok.getIdentifierInfo(); + SourceLocation KeywordLoc = ConsumeToken(); + + if (Keyword == Ident_unavailable) { + if (UnavailableLoc.isValid()) { + Diag(KeywordLoc, diag::err_availability_redundant) + << Keyword << SourceRange(UnavailableLoc); + } + UnavailableLoc = KeywordLoc; + + if (Tok.isNot(tok::comma)) + break; + + ConsumeToken(); + continue; + } + + if (Tok.isNot(tok::equal)) { + Diag(Tok, diag::err_expected_equal_after) + << Keyword; + SkipUntil(tok::r_paren); + return; + } + ConsumeToken(); + if (Keyword == Ident_message) { + if (!isTokenStringLiteral()) { + Diag(Tok, diag::err_expected_string_literal); + SkipUntil(tok::r_paren); + return; + } + MessageExpr = ParseStringLiteralExpression(); + break; + } + + SourceRange VersionRange; + VersionTuple Version = ParseVersionTuple(VersionRange); + + if (Version.empty()) { + SkipUntil(tok::r_paren); + return; + } + + unsigned Index; + if (Keyword == Ident_introduced) + Index = Introduced; + else if (Keyword == Ident_deprecated) + Index = Deprecated; + else if (Keyword == Ident_obsoleted) + Index = Obsoleted; + else + Index = Unknown; + + if (Index < Unknown) { + if (!Changes[Index].KeywordLoc.isInvalid()) { + Diag(KeywordLoc, diag::err_availability_redundant) + << Keyword + << SourceRange(Changes[Index].KeywordLoc, + Changes[Index].VersionRange.getEnd()); + } + + Changes[Index].KeywordLoc = KeywordLoc; + Changes[Index].Version = Version; + Changes[Index].VersionRange = VersionRange; + } else { + Diag(KeywordLoc, diag::err_availability_unknown_change) + << Keyword << VersionRange; + } + + if (Tok.isNot(tok::comma)) + break; + + ConsumeToken(); + } while (true); + + // Closing ')'. + if (T.consumeClose()) + return; + + if (endLoc) + *endLoc = T.getCloseLocation(); + + // The 'unavailable' availability cannot be combined with any other + // availability changes. Make sure that hasn't happened. + if (UnavailableLoc.isValid()) { + bool Complained = false; + for (unsigned Index = Introduced; Index != Unknown; ++Index) { + if (Changes[Index].KeywordLoc.isValid()) { + if (!Complained) { + Diag(UnavailableLoc, diag::warn_availability_and_unavailable) + << SourceRange(Changes[Index].KeywordLoc, + Changes[Index].VersionRange.getEnd()); + Complained = true; + } + + // Clear out the availability. + Changes[Index] = AvailabilityChange(); + } + } + } + + // Record this attribute + attrs.addNew(&Availability, + SourceRange(AvailabilityLoc, T.getCloseLocation()), + 0, AvailabilityLoc, + Platform, PlatformLoc, + Changes[Introduced], + Changes[Deprecated], + Changes[Obsoleted], + UnavailableLoc, MessageExpr.take(), + false, false); +} + + +// Late Parsed Attributes: +// See other examples of late parsing in lib/Parse/ParseCXXInlineMethods + +void Parser::LateParsedDeclaration::ParseLexedAttributes() {} + +void Parser::LateParsedClass::ParseLexedAttributes() { + Self->ParseLexedAttributes(*Class); +} + +void Parser::LateParsedAttribute::ParseLexedAttributes() { + Self->ParseLexedAttribute(*this, true, false); +} + +/// Wrapper class which calls ParseLexedAttribute, after setting up the +/// scope appropriately. +void Parser::ParseLexedAttributes(ParsingClass &Class) { + // Deal with templates + // FIXME: Test cases to make sure this does the right thing for templates. + bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; + ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, + HasTemplateScope); + if (HasTemplateScope) + Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); + + // Set or update the scope flags. + bool AlreadyHasClassScope = Class.TopLevelClass; + unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope; + ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope); + ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope); + + // Enter the scope of nested classes + if (!AlreadyHasClassScope) + Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), + Class.TagOrTemplate); + { + // Allow 'this' within late-parsed attributes. + Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate, + /*TypeQuals=*/0); + + for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i){ + Class.LateParsedDeclarations[i]->ParseLexedAttributes(); + } + } + + if (!AlreadyHasClassScope) + Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), + Class.TagOrTemplate); +} + + +/// \brief Parse all attributes in LAs, and attach them to Decl D. +void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D, + bool EnterScope, bool OnDefinition) { + for (unsigned i = 0, ni = LAs.size(); i < ni; ++i) { + LAs[i]->addDecl(D); + ParseLexedAttribute(*LAs[i], EnterScope, OnDefinition); + delete LAs[i]; + } + LAs.clear(); +} + + +/// \brief Finish parsing an attribute for which parsing was delayed. +/// This will be called at the end of parsing a class declaration +/// for each LateParsedAttribute. We consume the saved tokens and +/// create an attribute with the arguments filled in. We add this +/// to the Attribute list for the decl. +void Parser::ParseLexedAttribute(LateParsedAttribute &LA, + bool EnterScope, bool OnDefinition) { + // Save the current token position. + SourceLocation OrigLoc = Tok.getLocation(); + + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + LA.Toks.push_back(Tok); + PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false); + // Consume the previously pushed token. + ConsumeAnyToken(); + + if (OnDefinition && !IsThreadSafetyAttribute(LA.AttrName.getName())) { + Diag(Tok, diag::warn_attribute_on_function_definition) + << LA.AttrName.getName(); + } + + ParsedAttributes Attrs(AttrFactory); + SourceLocation endLoc; + + if (LA.Decls.size() == 1) { + Decl *D = LA.Decls[0]; + + // If the Decl is templatized, add template parameters to scope. + bool HasTemplateScope = EnterScope && D->isTemplateDecl(); + ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope); + if (HasTemplateScope) + Actions.ActOnReenterTemplateScope(Actions.CurScope, D); + + // If the Decl is on a function, add function parameters to the scope. + bool HasFunctionScope = EnterScope && D->isFunctionOrFunctionTemplate(); + ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunctionScope); + if (HasFunctionScope) + Actions.ActOnReenterFunctionContext(Actions.CurScope, D); + + ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc); + + if (HasFunctionScope) { + Actions.ActOnExitFunctionContext(); + FnScope.Exit(); // Pop scope, and remove Decls from IdResolver + } + if (HasTemplateScope) { + TempScope.Exit(); + } + } else if (LA.Decls.size() > 0) { + // If there are multiple decls, then the decl cannot be within the + // function scope. + ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc); + } else { + Diag(Tok, diag::warn_attribute_no_decl) << LA.AttrName.getName(); + } + + for (unsigned i = 0, ni = LA.Decls.size(); i < ni; ++i) { + Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.Decls[i], Attrs); + } + + if (Tok.getLocation() != OrigLoc) { + // Due to a parsing error, we either went over the cached tokens or + // there are still cached tokens left, so we skip the leftover tokens. + // Since this is an uncommon situation that should be avoided, use the + // expensive isBeforeInTranslationUnit call. + if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(), + OrigLoc)) + while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof)) + ConsumeAnyToken(); + } +} + +/// \brief Wrapper around a case statement checking if AttrName is +/// one of the thread safety attributes +bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){ + return llvm::StringSwitch(AttrName) + .Case("guarded_by", true) + .Case("guarded_var", true) + .Case("pt_guarded_by", true) + .Case("pt_guarded_var", true) + .Case("lockable", true) + .Case("scoped_lockable", true) + .Case("no_thread_safety_analysis", true) + .Case("acquired_after", true) + .Case("acquired_before", true) + .Case("exclusive_lock_function", true) + .Case("shared_lock_function", true) + .Case("exclusive_trylock_function", true) + .Case("shared_trylock_function", true) + .Case("unlock_function", true) + .Case("lock_returned", true) + .Case("locks_excluded", true) + .Case("exclusive_locks_required", true) + .Case("shared_locks_required", true) + .Default(false); +} + +/// \brief Parse the contents of thread safety attributes. These +/// should always be parsed as an expression list. +/// +/// We need to special case the parsing due to the fact that if the first token +/// of the first argument is an identifier, the main parse loop will store +/// that token as a "parameter" and the rest of +/// the arguments will be added to a list of "arguments". However, +/// subsequent tokens in the first argument are lost. We instead parse each +/// argument as an expression and add all arguments to the list of "arguments". +/// In future, we will take advantage of this special case to also +/// deal with some argument scoping issues here (for example, referring to a +/// function parameter in the attribute on that function). +void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc) { + assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); + + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + ExprVector ArgExprs(Actions); + bool ArgExprsOk = true; + + // now parse the list of expressions + while (Tok.isNot(tok::r_paren)) { + ExprResult ArgExpr(ParseAssignmentExpression()); + if (ArgExpr.isInvalid()) { + ArgExprsOk = false; + T.consumeClose(); + break; + } else { + ArgExprs.push_back(ArgExpr.release()); + } + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // Eat the comma, move to the next argument + } + // Match the ')'. + if (ArgExprsOk && !T.consumeClose()) { + Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), + ArgExprs.take(), ArgExprs.size()); + } + if (EndLoc) + *EndLoc = T.getCloseLocation(); +} + +/// DiagnoseProhibitedCXX11Attribute - We have found the opening square brackets +/// of a C++11 attribute-specifier in a location where an attribute is not +/// permitted. By C++11 [dcl.attr.grammar]p6, this is ill-formed. Diagnose this +/// situation. +/// +/// \return \c true if we skipped an attribute-like chunk of tokens, \c false if +/// this doesn't appear to actually be an attribute-specifier, and the caller +/// should try to parse it. +bool Parser::DiagnoseProhibitedCXX11Attribute() { + assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)); + + switch (isCXX11AttributeSpecifier(/*Disambiguate*/true)) { + case CAK_NotAttributeSpecifier: + // No diagnostic: we're in Obj-C++11 and this is not actually an attribute. + return false; + + case CAK_InvalidAttributeSpecifier: + Diag(Tok.getLocation(), diag::err_l_square_l_square_not_attribute); + return false; + + case CAK_AttributeSpecifier: + // Parse and discard the attributes. + SourceLocation BeginLoc = ConsumeBracket(); + ConsumeBracket(); + SkipUntil(tok::r_square, /*StopAtSemi*/ false); + assert(Tok.is(tok::r_square) && "isCXX11AttributeSpecifier lied"); + SourceLocation EndLoc = ConsumeBracket(); + Diag(BeginLoc, diag::err_attributes_not_allowed) + << SourceRange(BeginLoc, EndLoc); + return true; + } + llvm_unreachable("All cases handled above."); +} + +void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { + Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) + << attrs.Range; +} + +/// ParseDeclaration - Parse a full 'declaration', which consists of +/// declaration-specifiers, some number of declarators, and a semicolon. +/// 'Context' should be a Declarator::TheContext value. This returns the +/// location of the semicolon in DeclEnd. +/// +/// declaration: [C99 6.7] +/// block-declaration -> +/// simple-declaration +/// others [FIXME] +/// [C++] template-declaration +/// [C++] namespace-definition +/// [C++] using-directive +/// [C++] using-declaration +/// [C++11/C11] static_assert-declaration +/// others... [FIXME] +/// +Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, + unsigned Context, + SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs) { + ParenBraceBracketBalancer BalancerRAIIObj(*this); + // Must temporarily exit the objective-c container scope for + // parsing c none objective-c decls. + ObjCDeclContextSwitch ObjCDC(*this); + + Decl *SingleDecl = 0; + Decl *OwnedType = 0; + switch (Tok.getKind()) { + case tok::kw_template: + case tok::kw_export: + ProhibitAttributes(attrs); + SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd); + break; + case tok::kw_inline: + // Could be the start of an inline namespace. Allowed as an ext in C++03. + if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) { + ProhibitAttributes(attrs); + SourceLocation InlineLoc = ConsumeToken(); + SingleDecl = ParseNamespace(Context, DeclEnd, InlineLoc); + break; + } + return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs, + true); + case tok::kw_namespace: + ProhibitAttributes(attrs); + SingleDecl = ParseNamespace(Context, DeclEnd); + break; + case tok::kw_using: + SingleDecl = ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(), + DeclEnd, attrs, &OwnedType); + break; + case tok::kw_static_assert: + case tok::kw__Static_assert: + ProhibitAttributes(attrs); + SingleDecl = ParseStaticAssertDeclaration(DeclEnd); + break; + default: + return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs, true); + } + + // This routine returns a DeclGroup, if the thing we parsed only contains a + // single decl, convert it now. Alias declarations can also declare a type; + // include that too if it is present. + return Actions.ConvertDeclToDeclGroup(SingleDecl, OwnedType); +} + +/// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl] +/// declaration-specifiers init-declarator-list[opt] ';' +///[C90/C++]init-declarator-list ';' [TODO] +/// [OMP] threadprivate-directive [TODO] +/// +/// for-range-declaration: [C++0x 6.5p1: stmt.ranged] +/// attribute-specifier-seq[opt] type-specifier-seq declarator +/// +/// If RequireSemi is false, this does not check for a ';' at the end of the +/// declaration. If it is true, it checks for and eats it. +/// +/// If FRI is non-null, we might be parsing a for-range-declaration instead +/// of a simple-declaration. If we find that we are, we also parse the +/// for-range-initializer, and place it here. +Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts, + unsigned Context, + SourceLocation &DeclEnd, + ParsedAttributes &attrs, + bool RequireSemi, + ForRangeInit *FRI) { + // Parse the common declaration-specifiers piece. + ParsingDeclSpec DS(*this); + DS.takeAttributesFrom(attrs); + + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, + getDeclSpecContextFromDeclaratorContext(Context)); + + // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" + // declaration-specifiers init-declarator-list[opt] ';' + if (Tok.is(tok::semi)) { + if (RequireSemi) ConsumeToken(); + Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, + DS); + DS.complete(TheDecl); + return Actions.ConvertDeclToDeclGroup(TheDecl); + } + + return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI); +} + +/// Returns true if this might be the start of a declarator, or a common typo +/// for a declarator. +bool Parser::MightBeDeclarator(unsigned Context) { + switch (Tok.getKind()) { + case tok::annot_cxxscope: + case tok::annot_template_id: + case tok::caret: + case tok::code_completion: + case tok::coloncolon: + case tok::ellipsis: + case tok::kw___attribute: + case tok::kw_operator: + case tok::l_paren: + case tok::star: + return true; + + case tok::amp: + case tok::ampamp: + return getLangOpts().CPlusPlus; + + case tok::l_square: // Might be an attribute on an unnamed bit-field. + return Context == Declarator::MemberContext && getLangOpts().CPlusPlus0x && + NextToken().is(tok::l_square); + + case tok::colon: // Might be a typo for '::' or an unnamed bit-field. + return Context == Declarator::MemberContext || getLangOpts().CPlusPlus; + + case tok::identifier: + switch (NextToken().getKind()) { + case tok::code_completion: + case tok::coloncolon: + case tok::comma: + case tok::equal: + case tok::equalequal: // Might be a typo for '='. + case tok::kw_alignas: + case tok::kw_asm: + case tok::kw___attribute: + case tok::l_brace: + case tok::l_paren: + case tok::l_square: + case tok::less: + case tok::r_brace: + case tok::r_paren: + case tok::r_square: + case tok::semi: + return true; + + case tok::colon: + // At namespace scope, 'identifier:' is probably a typo for 'identifier::' + // and in block scope it's probably a label. Inside a class definition, + // this is a bit-field. + return Context == Declarator::MemberContext || + (getLangOpts().CPlusPlus && Context == Declarator::FileContext); + + case tok::identifier: // Possible virt-specifier. + return getLangOpts().CPlusPlus0x && isCXX0XVirtSpecifier(NextToken()); + + default: + return false; + } + + default: + return false; + } +} + +/// Skip until we reach something which seems like a sensible place to pick +/// up parsing after a malformed declaration. This will sometimes stop sooner +/// than SkipUntil(tok::r_brace) would, but will never stop later. +void Parser::SkipMalformedDecl() { + while (true) { + switch (Tok.getKind()) { + case tok::l_brace: + // Skip until matching }, then stop. We've probably skipped over + // a malformed class or function definition or similar. + ConsumeBrace(); + SkipUntil(tok::r_brace, /*StopAtSemi*/false); + if (Tok.is(tok::comma) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try)) { + // This declaration isn't over yet. Keep skipping. + continue; + } + if (Tok.is(tok::semi)) + ConsumeToken(); + return; + + case tok::l_square: + ConsumeBracket(); + SkipUntil(tok::r_square, /*StopAtSemi*/false); + continue; + + case tok::l_paren: + ConsumeParen(); + SkipUntil(tok::r_paren, /*StopAtSemi*/false); + continue; + + case tok::r_brace: + return; + + case tok::semi: + ConsumeToken(); + return; + + case tok::kw_inline: + // 'inline namespace' at the start of a line is almost certainly + // a good place to pick back up parsing. + if (Tok.isAtStartOfLine() && NextToken().is(tok::kw_namespace)) + return; + break; + + case tok::kw_namespace: + // 'namespace' at the start of a line is almost certainly a good + // place to pick back up parsing. + if (Tok.isAtStartOfLine()) + return; + break; + + case tok::eof: + return; + + default: + break; + } + + ConsumeAnyToken(); + } +} + +/// ParseDeclGroup - Having concluded that this is either a function +/// definition or a group of object declarations, actually parse the +/// result. +Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, + unsigned Context, + bool AllowFunctionDefinitions, + SourceLocation *DeclEnd, + ForRangeInit *FRI) { + // Parse the first declarator. + ParsingDeclarator D(*this, DS, static_cast(Context)); + ParseDeclarator(D); + + // Bail out if the first declarator didn't seem well-formed. + if (!D.hasName() && !D.mayOmitIdentifier()) { + SkipMalformedDecl(); + return DeclGroupPtrTy(); + } + + // Save late-parsed attributes for now; they need to be parsed in the + // appropriate function scope after the function Decl has been constructed. + LateParsedAttrList LateParsedAttrs; + if (D.isFunctionDeclarator()) + MaybeParseGNUAttributes(D, &LateParsedAttrs); + + // Check to see if we have a function *definition* which must have a body. + if (AllowFunctionDefinitions && D.isFunctionDeclarator() && + // Look at the next token to make sure that this isn't a function + // declaration. We have to check this because __attribute__ might be the + // start of a function definition in GCC-extended K&R C. + !isDeclarationAfterDeclarator()) { + + if (isStartOfFunctionDefinition(D)) { + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { + Diag(Tok, diag::err_function_declared_typedef); + + // Recover by treating the 'typedef' as spurious. + DS.ClearStorageClassSpecs(); + } + + Decl *TheDecl = + ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs); + return Actions.ConvertDeclToDeclGroup(TheDecl); + } + + if (isDeclarationSpecifier()) { + // If there is an invalid declaration specifier right after the function + // prototype, then we must be in a missing semicolon case where this isn't + // actually a body. Just fall through into the code that handles it as a + // prototype, and let the top-level code handle the erroneous declspec + // where it would otherwise expect a comma or semicolon. + } else { + Diag(Tok, diag::err_expected_fn_body); + SkipUntil(tok::semi); + return DeclGroupPtrTy(); + } + } + + if (ParseAsmAttributesAfterDeclarator(D)) + return DeclGroupPtrTy(); + + // C++0x [stmt.iter]p1: Check if we have a for-range-declarator. If so, we + // must parse and analyze the for-range-initializer before the declaration is + // analyzed. + if (FRI && Tok.is(tok::colon)) { + FRI->ColonLoc = ConsumeToken(); + if (Tok.is(tok::l_brace)) + FRI->RangeExpr = ParseBraceInitializer(); + else + FRI->RangeExpr = ParseExpression(); + Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); + Actions.ActOnCXXForRangeDecl(ThisDecl); + Actions.FinalizeDeclaration(ThisDecl); + D.complete(ThisDecl); + return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1); + } + + SmallVector DeclsInGroup; + Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D); + if (LateParsedAttrs.size() > 0) + ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false); + D.complete(FirstDecl); + if (FirstDecl) + DeclsInGroup.push_back(FirstDecl); + + bool ExpectSemi = Context != Declarator::ForContext; + + // If we don't have a comma, it is either the end of the list (a ';') or an + // error, bail out. + while (Tok.is(tok::comma)) { + SourceLocation CommaLoc = ConsumeToken(); + + if (Tok.isAtStartOfLine() && ExpectSemi && !MightBeDeclarator(Context)) { + // This comma was followed by a line-break and something which can't be + // the start of a declarator. The comma was probably a typo for a + // semicolon. + Diag(CommaLoc, diag::err_expected_semi_declaration) + << FixItHint::CreateReplacement(CommaLoc, ";"); + ExpectSemi = false; + break; + } + + // Parse the next declarator. + D.clear(); + D.setCommaLoc(CommaLoc); + + // Accept attributes in an init-declarator. In the first declarator in a + // declaration, these would be part of the declspec. In subsequent + // declarators, they become part of the declarator itself, so that they + // don't apply to declarators after *this* one. Examples: + // short __attribute__((common)) var; -> declspec + // short var __attribute__((common)); -> declarator + // short x, __attribute__((common)) var; -> declarator + MaybeParseGNUAttributes(D); + + ParseDeclarator(D); + if (!D.isInvalidType()) { + Decl *ThisDecl = ParseDeclarationAfterDeclarator(D); + D.complete(ThisDecl); + if (ThisDecl) + DeclsInGroup.push_back(ThisDecl); + } + } + + if (DeclEnd) + *DeclEnd = Tok.getLocation(); + + if (ExpectSemi && + ExpectAndConsume(tok::semi, + Context == Declarator::FileContext + ? diag::err_invalid_token_after_toplevel_declarator + : diag::err_expected_semi_declaration)) { + // Okay, there was no semicolon and one was expected. If we see a + // declaration specifier, just assume it was missing and continue parsing. + // Otherwise things are very confused and we skip to recover. + if (!isDeclarationSpecifier()) { + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + } + } + + return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, + DeclsInGroup.data(), + DeclsInGroup.size()); +} + +/// Parse an optional simple-asm-expr and attributes, and attach them to a +/// declarator. Returns true on an error. +bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) { + // If a simple-asm-expr is present, parse it. + if (Tok.is(tok::kw_asm)) { + SourceLocation Loc; + ExprResult AsmLabel(ParseSimpleAsm(&Loc)); + if (AsmLabel.isInvalid()) { + SkipUntil(tok::semi, true, true); + return true; + } + + D.setAsmLabel(AsmLabel.release()); + D.SetRangeEnd(Loc); + } + + MaybeParseGNUAttributes(D); + return false; +} + +/// \brief Parse 'declaration' after parsing 'declaration-specifiers +/// declarator'. This method parses the remainder of the declaration +/// (including any attributes or initializer, among other things) and +/// finalizes the declaration. +/// +/// init-declarator: [C99 6.7] +/// declarator +/// declarator '=' initializer +/// [GNU] declarator simple-asm-expr[opt] attributes[opt] +/// [GNU] declarator simple-asm-expr[opt] attributes[opt] '=' initializer +/// [C++] declarator initializer[opt] +/// +/// [C++] initializer: +/// [C++] '=' initializer-clause +/// [C++] '(' expression-list ')' +/// [C++0x] '=' 'default' [TODO] +/// [C++0x] '=' 'delete' +/// [C++0x] braced-init-list +/// +/// According to the standard grammar, =default and =delete are function +/// definitions, but that definitely doesn't fit with the parser here. +/// +Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, + const ParsedTemplateInfo &TemplateInfo) { + if (ParseAsmAttributesAfterDeclarator(D)) + return 0; + + return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo); +} + +Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, + const ParsedTemplateInfo &TemplateInfo) { + // Inform the current actions module that we just parsed this declarator. + Decl *ThisDecl = 0; + switch (TemplateInfo.Kind) { + case ParsedTemplateInfo::NonTemplate: + ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); + break; + + case ParsedTemplateInfo::Template: + case ParsedTemplateInfo::ExplicitSpecialization: + ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(), + MultiTemplateParamsArg(Actions, + TemplateInfo.TemplateParams->data(), + TemplateInfo.TemplateParams->size()), + D); + break; + + case ParsedTemplateInfo::ExplicitInstantiation: { + DeclResult ThisRes + = Actions.ActOnExplicitInstantiation(getCurScope(), + TemplateInfo.ExternLoc, + TemplateInfo.TemplateLoc, + D); + if (ThisRes.isInvalid()) { + SkipUntil(tok::semi, true, true); + return 0; + } + + ThisDecl = ThisRes.get(); + break; + } + } + + bool TypeContainsAuto = + D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + + // Parse declarator '=' initializer. + // If a '==' or '+=' is found, suggest a fixit to '='. + if (isTokenEqualOrEqualTypo()) { + ConsumeToken(); + if (Tok.is(tok::kw_delete)) { + if (D.isFunctionDeclarator()) + Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) + << 1 /* delete */; + else + Diag(ConsumeToken(), diag::err_deleted_non_function); + } else if (Tok.is(tok::kw_default)) { + if (D.isFunctionDeclarator()) + Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) + << 0 /* default */; + else + Diag(ConsumeToken(), diag::err_default_special_members); + } else { + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { + EnterScope(0); + Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); + } + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteInitializer(getCurScope(), ThisDecl); + cutOffParsing(); + return 0; + } + + ExprResult Init(ParseInitializer()); + + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { + Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); + ExitScope(); + } + + if (Init.isInvalid()) { + SkipUntil(tok::comma, true, true); + Actions.ActOnInitializerError(ThisDecl); + } else + Actions.AddInitializerToDecl(ThisDecl, Init.take(), + /*DirectInit=*/false, TypeContainsAuto); + } + } else if (Tok.is(tok::l_paren)) { + // Parse C++ direct initializer: '(' expression-list ')' + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + ExprVector Exprs(Actions); + CommaLocsTy CommaLocs; + + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { + EnterScope(0); + Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); + } + + if (ParseExpressionList(Exprs, CommaLocs)) { + SkipUntil(tok::r_paren); + + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { + Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); + ExitScope(); + } + } else { + // Match the ')'. + T.consumeClose(); + + assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() && + "Unexpected number of commas!"); + + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { + Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); + ExitScope(); + } + + ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(), + T.getCloseLocation(), + move_arg(Exprs)); + Actions.AddInitializerToDecl(ThisDecl, Initializer.take(), + /*DirectInit=*/true, TypeContainsAuto); + } + } else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + // Parse C++0x braced-init-list. + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + + if (D.getCXXScopeSpec().isSet()) { + EnterScope(0); + Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); + } + + ExprResult Init(ParseBraceInitializer()); + + if (D.getCXXScopeSpec().isSet()) { + Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); + ExitScope(); + } + + if (Init.isInvalid()) { + Actions.ActOnInitializerError(ThisDecl); + } else + Actions.AddInitializerToDecl(ThisDecl, Init.take(), + /*DirectInit=*/true, TypeContainsAuto); + + } else { + Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto); + } + + Actions.FinalizeDeclaration(ThisDecl); + + return ThisDecl; +} + +/// ParseSpecifierQualifierList +/// specifier-qualifier-list: +/// type-specifier specifier-qualifier-list[opt] +/// type-qualifier specifier-qualifier-list[opt] +/// [GNU] attributes specifier-qualifier-list[opt] +/// +void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, + DeclSpecContext DSC) { + /// specifier-qualifier-list is a subset of declaration-specifiers. Just + /// parse declaration-specifiers and complain about extra stuff. + /// TODO: diagnose attribute-specifiers and alignment-specifiers. + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC); + + // Validate declspec for type-name. + unsigned Specs = DS.getParsedSpecifiers(); + if (DSC == DSC_type_specifier && !DS.hasTypeSpecifier()) { + Diag(Tok, diag::err_expected_type); + DS.SetTypeSpecError(); + } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() && + !DS.hasAttributes()) { + Diag(Tok, diag::err_typename_requires_specqual); + if (!DS.hasTypeSpecifier()) + DS.SetTypeSpecError(); + } + + // Issue diagnostic and remove storage class if present. + if (Specs & DeclSpec::PQ_StorageClassSpecifier) { + if (DS.getStorageClassSpecLoc().isValid()) + Diag(DS.getStorageClassSpecLoc(),diag::err_typename_invalid_storageclass); + else + Diag(DS.getThreadSpecLoc(), diag::err_typename_invalid_storageclass); + DS.ClearStorageClassSpecs(); + } + + // Issue diagnostic and remove function specfier if present. + if (Specs & DeclSpec::PQ_FunctionSpecifier) { + if (DS.isInlineSpecified()) + Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec); + if (DS.isVirtualSpecified()) + Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec); + if (DS.isExplicitSpecified()) + Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec); + DS.ClearFunctionSpecs(); + } + + // Issue diagnostic and remove constexpr specfier if present. + if (DS.isConstexprSpecified()) { + Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr); + DS.ClearConstexprSpec(); + } +} + +/// isValidAfterIdentifierInDeclaratorAfterDeclSpec - Return true if the +/// specified token is valid after the identifier in a declarator which +/// immediately follows the declspec. For example, these things are valid: +/// +/// int x [ 4]; // direct-declarator +/// int x ( int y); // direct-declarator +/// int(int x ) // direct-declarator +/// int x ; // simple-declaration +/// int x = 17; // init-declarator-list +/// int x , y; // init-declarator-list +/// int x __asm__ ("foo"); // init-declarator-list +/// int x : 4; // struct-declarator +/// int x { 5}; // C++'0x unified initializers +/// +/// This is not, because 'x' does not immediately follow the declspec (though +/// ')' happens to be valid anyway). +/// int (x) +/// +static bool isValidAfterIdentifierInDeclarator(const Token &T) { + return T.is(tok::l_square) || T.is(tok::l_paren) || T.is(tok::r_paren) || + T.is(tok::semi) || T.is(tok::comma) || T.is(tok::equal) || + T.is(tok::kw_asm) || T.is(tok::l_brace) || T.is(tok::colon); +} + + +/// ParseImplicitInt - This method is called when we have an non-typename +/// identifier in a declspec (which normally terminates the decl spec) when +/// the declspec has no type specifier. In this case, the declspec is either +/// malformed or is "implicit int" (in K&R and C89). +/// +/// This method handles diagnosing this prettily and returns false if the +/// declspec is done being processed. If it recovers and thinks there may be +/// other pieces of declspec after it, it returns true. +/// +bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, + const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS, DeclSpecContext DSC) { + assert(Tok.is(tok::identifier) && "should have identifier"); + + SourceLocation Loc = Tok.getLocation(); + // If we see an identifier that is not a type name, we normally would + // parse it as the identifer being declared. However, when a typename + // is typo'd or the definition is not included, this will incorrectly + // parse the typename as the identifier name and fall over misparsing + // later parts of the diagnostic. + // + // As such, we try to do some look-ahead in cases where this would + // otherwise be an "implicit-int" case to see if this is invalid. For + // example: "static foo_t x = 4;" In this case, if we parsed foo_t as + // an identifier with implicit int, we'd get a parse error because the + // next token is obviously invalid for a type. Parse these as a case + // with an invalid type specifier. + assert(!DS.hasTypeSpecifier() && "Type specifier checked above"); + + // Since we know that this either implicit int (which is rare) or an + // error, do lookahead to try to do better recovery. This never applies within + // a type specifier. + // FIXME: Don't bail out here in languages with no implicit int (like + // C++ with no -fms-extensions). This is much more likely to be an undeclared + // type or typo than a use of implicit int. + if (DSC != DSC_type_specifier && + isValidAfterIdentifierInDeclarator(NextToken())) { + // If this token is valid for implicit int, e.g. "static x = 4", then + // we just avoid eating the identifier, so it will be parsed as the + // identifier in the declarator. + return false; + } + + // Otherwise, if we don't consume this token, we are going to emit an + // error anyway. Try to recover from various common problems. Check + // to see if this was a reference to a tag name without a tag specified. + // This is a common problem in C (saying 'foo' instead of 'struct foo'). + // + // C++ doesn't need this, and isTagName doesn't take SS. + if (SS == 0) { + const char *TagName = 0, *FixitTagName = 0; + tok::TokenKind TagKind = tok::unknown; + + switch (Actions.isTagName(*Tok.getIdentifierInfo(), getCurScope())) { + default: break; + case DeclSpec::TST_enum: + TagName="enum" ; FixitTagName = "enum " ; TagKind=tok::kw_enum ;break; + case DeclSpec::TST_union: + TagName="union" ; FixitTagName = "union " ;TagKind=tok::kw_union ;break; + case DeclSpec::TST_struct: + TagName="struct"; FixitTagName = "struct ";TagKind=tok::kw_struct;break; + case DeclSpec::TST_class: + TagName="class" ; FixitTagName = "class " ;TagKind=tok::kw_class ;break; + } + + if (TagName) { + Diag(Loc, diag::err_use_of_tag_name_without_tag) + << Tok.getIdentifierInfo() << TagName << getLangOpts().CPlusPlus + << FixItHint::CreateInsertion(Tok.getLocation(),FixitTagName); + + // Parse this as a tag as if the missing tag were present. + if (TagKind == tok::kw_enum) + ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSC_normal); + else + ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS, + /*EnteringContext*/ false, DSC_normal); + return true; + } + } + + // This is almost certainly an invalid type name. Let the action emit a + // diagnostic and attempt to recover. + ParsedType T; + if (Actions.DiagnoseUnknownTypeName(*Tok.getIdentifierInfo(), Loc, + getCurScope(), SS, T)) { + // The action emitted a diagnostic, so we don't have to. + if (T) { + // The action has suggested that the type T could be used. Set that as + // the type in the declaration specifiers, consume the would-be type + // name token, and we're done. + const char *PrevSpec; + unsigned DiagID; + DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T); + DS.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); + + // There may be other declaration specifiers after this. + return true; + } + + // Fall through; the action had no suggestion for us. + } else { + // The action did not emit a diagnostic, so emit one now. + SourceRange R; + if (SS) R = SS->getRange(); + Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R; + } + + // Mark this as an error. + DS.SetTypeSpecError(); + DS.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); + + // TODO: Could inject an invalid typedef decl in an enclosing scope to + // avoid rippling error messages on subsequent uses of the same type, + // could be useful if #include was forgotten. + return false; +} + +/// \brief Determine the declaration specifier context from the declarator +/// context. +/// +/// \param Context the declarator context, which is one of the +/// Declarator::TheContext enumerator values. +Parser::DeclSpecContext +Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { + if (Context == Declarator::MemberContext) + return DSC_class; + if (Context == Declarator::FileContext) + return DSC_top_level; + if (Context == Declarator::TrailingReturnContext) + return DSC_trailing; + return DSC_normal; +} + +/// ParseAlignArgument - Parse the argument to an alignment-specifier. +/// +/// FIXME: Simply returns an alignof() expression if the argument is a +/// type. Ideally, the type should be propagated directly into Sema. +/// +/// [C11] type-id +/// [C11] constant-expression +/// [C++0x] type-id ...[opt] +/// [C++0x] assignment-expression ...[opt] +ExprResult Parser::ParseAlignArgument(SourceLocation Start, + SourceLocation &EllipsisLoc) { + ExprResult ER; + if (isTypeIdInParens()) { + SourceLocation TypeLoc = Tok.getLocation(); + ParsedType Ty = ParseTypeName().get(); + SourceRange TypeRange(Start, Tok.getLocation()); + ER = Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true, + Ty.getAsOpaquePtr(), TypeRange); + } else + ER = ParseConstantExpression(); + + if (getLangOpts().CPlusPlus0x && Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + + return ER; +} + +/// ParseAlignmentSpecifier - Parse an alignment-specifier, and add the +/// attribute to Attrs. +/// +/// alignment-specifier: +/// [C11] '_Alignas' '(' type-id ')' +/// [C11] '_Alignas' '(' constant-expression ')' +/// [C++0x] 'alignas' '(' type-id ...[opt] ')' +/// [C++0x] 'alignas' '(' assignment-expression ...[opt] ')' +void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, + SourceLocation *endLoc) { + assert((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) && + "Not an alignment-specifier!"); + + SourceLocation KWLoc = Tok.getLocation(); + ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) + return; + + SourceLocation EllipsisLoc; + ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation(), EllipsisLoc); + if (ArgExpr.isInvalid()) { + SkipUntil(tok::r_paren); + return; + } + + T.consumeClose(); + if (endLoc) + *endLoc = T.getCloseLocation(); + + // FIXME: Handle pack-expansions here. + if (EllipsisLoc.isValid()) { + Diag(EllipsisLoc, diag::err_alignas_pack_exp_unsupported); + return; + } + + ExprVector ArgExprs(Actions); + ArgExprs.push_back(ArgExpr.release()); + Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc, + 0, T.getOpenLocation(), ArgExprs.take(), 1, false, true); +} + +/// ParseDeclarationSpecifiers +/// declaration-specifiers: [C99 6.7] +/// storage-class-specifier declaration-specifiers[opt] +/// type-specifier declaration-specifiers[opt] +/// [C99] function-specifier declaration-specifiers[opt] +/// [C11] alignment-specifier declaration-specifiers[opt] +/// [GNU] attributes declaration-specifiers[opt] +/// [Clang] '__module_private__' declaration-specifiers[opt] +/// +/// storage-class-specifier: [C99 6.7.1] +/// 'typedef' +/// 'extern' +/// 'static' +/// 'auto' +/// 'register' +/// [C++] 'mutable' +/// [GNU] '__thread' +/// function-specifier: [C99 6.7.4] +/// [C99] 'inline' +/// [C++] 'virtual' +/// [C++] 'explicit' +/// [OpenCL] '__kernel' +/// 'friend': [C++ dcl.friend] +/// 'constexpr': [C++0x dcl.constexpr] + +/// +void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, + const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS, + DeclSpecContext DSContext, + LateParsedAttrList *LateAttrs) { + if (DS.getSourceRange().isInvalid()) { + DS.SetRangeStart(Tok.getLocation()); + DS.SetRangeEnd(Tok.getLocation()); + } + + bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level); + while (1) { + bool isInvalid = false; + const char *PrevSpec = 0; + unsigned DiagID = 0; + + SourceLocation Loc = Tok.getLocation(); + + switch (Tok.getKind()) { + default: + DoneWithDeclSpec: + // [C++0x] decl-specifier-seq: decl-specifier attribute-specifier-seq[opt] + MaybeParseCXX0XAttributes(DS.getAttributes()); + + // If this is not a declaration specifier token, we're done reading decl + // specifiers. First verify that DeclSpec's are consistent. + DS.Finish(Diags, PP); + return; + + case tok::code_completion: { + Sema::ParserCompletionContext CCC = Sema::PCC_Namespace; + if (DS.hasTypeSpecifier()) { + bool AllowNonIdentifiers + = (getCurScope()->getFlags() & (Scope::ControlScope | + Scope::BlockScope | + Scope::TemplateParamScope | + Scope::FunctionPrototypeScope | + Scope::AtCatchScope)) == 0; + bool AllowNestedNameSpecifiers + = DSContext == DSC_top_level || + (DSContext == DSC_class && DS.isFriendSpecified()); + + Actions.CodeCompleteDeclSpec(getCurScope(), DS, + AllowNonIdentifiers, + AllowNestedNameSpecifiers); + return cutOffParsing(); + } + + if (getCurScope()->getFnParent() || getCurScope()->getBlockParent()) + CCC = Sema::PCC_LocalDeclarationSpecifiers; + else if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) + CCC = DSContext == DSC_class? Sema::PCC_MemberTemplate + : Sema::PCC_Template; + else if (DSContext == DSC_class) + CCC = Sema::PCC_Class; + else if (CurParsedObjCImpl) + CCC = Sema::PCC_ObjCImplementation; + + Actions.CodeCompleteOrdinaryName(getCurScope(), CCC); + return cutOffParsing(); + } + + case tok::coloncolon: // ::foo::bar + // C++ scope specifier. Annotate and loop, or bail out on error. + if (TryAnnotateCXXScopeToken(true)) { + if (!DS.hasTypeSpecifier()) + DS.SetTypeSpecError(); + goto DoneWithDeclSpec; + } + if (Tok.is(tok::coloncolon)) // ::new or ::delete + goto DoneWithDeclSpec; + continue; + + case tok::annot_cxxscope: { + if (DS.hasTypeSpecifier()) + goto DoneWithDeclSpec; + + CXXScopeSpec SS; + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); + + // We are looking for a qualified typename. + Token Next = NextToken(); + if (Next.is(tok::annot_template_id) && + static_cast(Next.getAnnotationValue()) + ->Kind == TNK_Type_template) { + // We have a qualified template-id, e.g., N::A + + // C++ [class.qual]p2: + // In a lookup in which the constructor is an acceptable lookup + // result and the nested-name-specifier nominates a class C: + // + // - if the name specified after the + // nested-name-specifier, when looked up in C, is the + // injected-class-name of C (Clause 9), or + // + // - if the name specified after the nested-name-specifier + // is the same as the identifier or the + // simple-template-id's template-name in the last + // component of the nested-name-specifier, + // + // the name is instead considered to name the constructor of + // class C. + // + // Thus, if the template-name is actually the constructor + // name, then the code is ill-formed; this interpretation is + // reinforced by the NAD status of core issue 635. + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next); + if ((DSContext == DSC_top_level || + (DSContext == DSC_class && DS.isFriendSpecified())) && + TemplateId->Name && + Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) { + if (isConstructorDeclarator()) { + // The user meant this to be an out-of-line constructor + // definition, but template arguments are not allowed + // there. Just allow this as a constructor; we'll + // complain about it later. + goto DoneWithDeclSpec; + } + + // The user meant this to name a type, but it actually names + // a constructor with some extraneous template + // arguments. Complain, then parse it as a type as the user + // intended. + Diag(TemplateId->TemplateNameLoc, + diag::err_out_of_line_template_id_names_constructor) + << TemplateId->Name; + } + + DS.getTypeSpecScope() = SS; + ConsumeToken(); // The C++ scope. + assert(Tok.is(tok::annot_template_id) && + "ParseOptionalCXXScopeSpecifier not working"); + AnnotateTemplateIdTokenAsType(); + continue; + } + + if (Next.is(tok::annot_typename)) { + DS.getTypeSpecScope() = SS; + ConsumeToken(); // The C++ scope. + if (Tok.getAnnotationValue()) { + ParsedType T = getTypeAnnotation(Tok); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, + Tok.getAnnotationEndLoc(), + PrevSpec, DiagID, T); + } + else + DS.SetTypeSpecError(); + DS.SetRangeEnd(Tok.getAnnotationEndLoc()); + ConsumeToken(); // The typename + } + + if (Next.isNot(tok::identifier)) + goto DoneWithDeclSpec; + + // If we're in a context where the identifier could be a class name, + // check whether this is a constructor declaration. + if ((DSContext == DSC_top_level || + (DSContext == DSC_class && DS.isFriendSpecified())) && + Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(), + &SS)) { + if (isConstructorDeclarator()) + goto DoneWithDeclSpec; + + // As noted in C++ [class.qual]p2 (cited above), when the name + // of the class is qualified in a context where it could name + // a constructor, its a constructor name. However, we've + // looked at the declarator, and the user probably meant this + // to be a type. Complain that it isn't supposed to be treated + // as a type, then proceed to parse it as a type. + Diag(Next.getLocation(), diag::err_out_of_line_type_names_constructor) + << Next.getIdentifierInfo(); + } + + ParsedType TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(), + Next.getLocation(), + getCurScope(), &SS, + false, false, ParsedType(), + /*IsCtorOrDtorName=*/false, + /*NonTrivialSourceInfo=*/true); + + // If the referenced identifier is not a type, then this declspec is + // erroneous: We already checked about that it has no type specifier, and + // C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the + // typename. + if (TypeRep == 0) { + ConsumeToken(); // Eat the scope spec so the identifier is current. + if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext)) continue; + goto DoneWithDeclSpec; + } + + DS.getTypeSpecScope() = SS; + ConsumeToken(); // The C++ scope. + + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, + DiagID, TypeRep); + if (isInvalid) + break; + + DS.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); // The typename. + + continue; + } + + case tok::annot_typename: { + if (Tok.getAnnotationValue()) { + ParsedType T = getTypeAnnotation(Tok); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, + DiagID, T); + } else + DS.SetTypeSpecError(); + + if (isInvalid) + break; + + DS.SetRangeEnd(Tok.getAnnotationEndLoc()); + ConsumeToken(); // The typename + + // Objective-C supports syntax of the form 'id' where 'id' + // is a specific typedef and 'itf' where 'itf' is an + // Objective-C interface. + if (Tok.is(tok::less) && getLangOpts().ObjC1) + ParseObjCProtocolQualifiers(DS); + + continue; + } + + case tok::kw___is_signed: + // GNU libstdc++ 4.4 uses __is_signed as an identifier, but Clang + // typically treats it as a trait. If we see __is_signed as it appears + // in libstdc++, e.g., + // + // static const bool __is_signed; + // + // then treat __is_signed as an identifier rather than as a keyword. + if (DS.getTypeSpecType() == TST_bool && + DS.getTypeQualifiers() == DeclSpec::TQ_const && + DS.getStorageClassSpec() == DeclSpec::SCS_static) { + Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); + Tok.setKind(tok::identifier); + } + + // We're done with the declaration-specifiers. + goto DoneWithDeclSpec; + + // typedef-name + case tok::kw_decltype: + case tok::identifier: { + // In C++, check to see if this is a scope specifier like foo::bar::, if + // so handle it as such. This is important for ctor parsing. + if (getLangOpts().CPlusPlus) { + if (TryAnnotateCXXScopeToken(true)) { + if (!DS.hasTypeSpecifier()) + DS.SetTypeSpecError(); + goto DoneWithDeclSpec; + } + if (!Tok.is(tok::identifier)) + continue; + } + + // This identifier can only be a typedef name if we haven't already seen + // a type-specifier. Without this check we misparse: + // typedef int X; struct Y { short X; }; as 'short int'. + if (DS.hasTypeSpecifier()) + goto DoneWithDeclSpec; + + // Check for need to substitute AltiVec keyword tokens. + if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) + break; + + ParsedType TypeRep = + Actions.getTypeName(*Tok.getIdentifierInfo(), + Tok.getLocation(), getCurScope()); + + // If this is not a typedef name, don't parse it as part of the declspec, + // it must be an implicit int or an error. + if (!TypeRep) { + if (ParseImplicitInt(DS, 0, TemplateInfo, AS, DSContext)) continue; + goto DoneWithDeclSpec; + } + + // If we're in a context where the identifier could be a class name, + // check whether this is a constructor declaration. + if (getLangOpts().CPlusPlus && DSContext == DSC_class && + Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) && + isConstructorDeclarator()) + goto DoneWithDeclSpec; + + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, + DiagID, TypeRep); + if (isInvalid) + break; + + DS.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); // The identifier + + // Objective-C supports syntax of the form 'id' where 'id' + // is a specific typedef and 'itf' where 'itf' is an + // Objective-C interface. + if (Tok.is(tok::less) && getLangOpts().ObjC1) + ParseObjCProtocolQualifiers(DS); + + // Need to support trailing type qualifiers (e.g. "id

const"). + // If a type specifier follows, it will be diagnosed elsewhere. + continue; + } + + // type-name + case tok::annot_template_id: { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (TemplateId->Kind != TNK_Type_template) { + // This template-id does not refer to a type name, so we're + // done with the type-specifiers. + goto DoneWithDeclSpec; + } + + // If we're in a context where the template-id could be a + // constructor name or specialization, check whether this is a + // constructor declaration. + if (getLangOpts().CPlusPlus && DSContext == DSC_class && + Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) && + isConstructorDeclarator()) + goto DoneWithDeclSpec; + + // Turn the template-id annotation token into a type annotation + // token, then try again to parse it as a type-specifier. + AnnotateTemplateIdTokenAsType(); + continue; + } + + // GNU attributes support. + case tok::kw___attribute: + ParseGNUAttributes(DS.getAttributes(), 0, LateAttrs); + continue; + + // Microsoft declspec support. + case tok::kw___declspec: + ParseMicrosoftDeclSpec(DS.getAttributes()); + continue; + + // Microsoft single token adornments. + case tok::kw___forceinline: + // FIXME: Add handling here! + break; + + case tok::kw___ptr64: + case tok::kw___ptr32: + case tok::kw___w64: + case tok::kw___cdecl: + case tok::kw___stdcall: + case tok::kw___fastcall: + case tok::kw___thiscall: + case tok::kw___unaligned: + ParseMicrosoftTypeAttributes(DS.getAttributes()); + continue; + + // Borland single token adornments. + case tok::kw___pascal: + ParseBorlandTypeAttributes(DS.getAttributes()); + continue; + + // OpenCL single token adornments. + case tok::kw___kernel: + ParseOpenCLAttributes(DS.getAttributes()); + continue; + + // storage-class-specifier + case tok::kw_typedef: + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc, + PrevSpec, DiagID); + break; + case tok::kw_extern: + if (DS.isThreadSpecified()) + Diag(Tok, diag::ext_thread_before) << "extern"; + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_extern, Loc, + PrevSpec, DiagID); + break; + case tok::kw___private_extern__: + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_private_extern, + Loc, PrevSpec, DiagID); + break; + case tok::kw_static: + if (DS.isThreadSpecified()) + Diag(Tok, diag::ext_thread_before) << "static"; + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc, + PrevSpec, DiagID); + break; + case tok::kw_auto: + if (getLangOpts().CPlusPlus0x) { + if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, + PrevSpec, DiagID); + if (!isInvalid) + Diag(Tok, diag::ext_auto_storage_class) + << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); + } else + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, + DiagID); + } else + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, + PrevSpec, DiagID); + break; + case tok::kw_register: + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_register, Loc, + PrevSpec, DiagID); + break; + case tok::kw_mutable: + isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_mutable, Loc, + PrevSpec, DiagID); + break; + case tok::kw___thread: + isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID); + break; + + // function-specifier + case tok::kw_inline: + isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID); + break; + case tok::kw_virtual: + isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec, DiagID); + break; + case tok::kw_explicit: + isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec, DiagID); + break; + + // alignment-specifier + case tok::kw__Alignas: + if (!getLangOpts().C11) + Diag(Tok, diag::ext_c11_alignas); + ParseAlignmentSpecifier(DS.getAttributes()); + continue; + + // friend + case tok::kw_friend: + if (DSContext == DSC_class) + isInvalid = DS.SetFriendSpec(Loc, PrevSpec, DiagID); + else { + PrevSpec = ""; // not actually used by the diagnostic + DiagID = diag::err_friend_invalid_in_context; + isInvalid = true; + } + break; + + // Modules + case tok::kw___module_private__: + isInvalid = DS.setModulePrivateSpec(Loc, PrevSpec, DiagID); + break; + + // constexpr + case tok::kw_constexpr: + isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID); + break; + + // type-specifier + case tok::kw_short: + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, + DiagID); + break; + case tok::kw_long: + if (DS.getTypeSpecWidth() != DeclSpec::TSW_long) + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, + DiagID); + else + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, + DiagID); + break; + case tok::kw___int64: + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, + DiagID); + break; + case tok::kw_signed: + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, + DiagID); + break; + case tok::kw_unsigned: + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, + DiagID); + break; + case tok::kw__Complex: + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec, + DiagID); + break; + case tok::kw__Imaginary: + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec, + DiagID); + break; + case tok::kw_void: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, + DiagID); + break; + case tok::kw_char: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, + DiagID); + break; + case tok::kw_int: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, + DiagID); + break; + case tok::kw___int128: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, + DiagID); + break; + case tok::kw_half: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, + DiagID); + break; + case tok::kw_float: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, + DiagID); + break; + case tok::kw_double: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, + DiagID); + break; + case tok::kw_wchar_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, + DiagID); + break; + case tok::kw_char16_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, + DiagID); + break; + case tok::kw_char32_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, + DiagID); + break; + case tok::kw_bool: + case tok::kw__Bool: + if (Tok.is(tok::kw_bool) && + DS.getTypeSpecType() != DeclSpec::TST_unspecified && + DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { + PrevSpec = ""; // Not used by the diagnostic. + DiagID = diag::err_bool_redeclaration; + // For better error recovery. + Tok.setKind(tok::identifier); + isInvalid = true; + } else { + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, + DiagID); + } + break; + case tok::kw__Decimal32: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec, + DiagID); + break; + case tok::kw__Decimal64: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec, + DiagID); + break; + case tok::kw__Decimal128: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec, + DiagID); + break; + case tok::kw___vector: + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + break; + case tok::kw___pixel: + isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); + break; + case tok::kw___unknown_anytype: + isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc, + PrevSpec, DiagID); + break; + + // class-specifier: + case tok::kw_class: + case tok::kw_struct: + case tok::kw_union: { + tok::TokenKind Kind = Tok.getKind(); + ConsumeToken(); + ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS, + EnteringContext, DSContext); + continue; + } + + // enum-specifier: + case tok::kw_enum: + ConsumeToken(); + ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSContext); + continue; + + // cv-qualifier: + case tok::kw_const: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID, + getLangOpts()); + break; + case tok::kw_volatile: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, + getLangOpts()); + break; + case tok::kw_restrict: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, + getLangOpts()); + break; + + // C++ typename-specifier: + case tok::kw_typename: + if (TryAnnotateTypeOrScopeToken()) { + DS.SetTypeSpecError(); + goto DoneWithDeclSpec; + } + if (!Tok.is(tok::kw_typename)) + continue; + break; + + // GNU typeof support. + case tok::kw_typeof: + ParseTypeofSpecifier(DS); + continue; + + case tok::annot_decltype: + ParseDecltypeSpecifier(DS); + continue; + + case tok::kw___underlying_type: + ParseUnderlyingTypeSpecifier(DS); + continue; + + case tok::kw__Atomic: + ParseAtomicSpecifier(DS); + continue; + + // OpenCL qualifiers: + case tok::kw_private: + if (!getLangOpts().OpenCL) + goto DoneWithDeclSpec; + case tok::kw___private: + case tok::kw___global: + case tok::kw___local: + case tok::kw___constant: + case tok::kw___read_only: + case tok::kw___write_only: + case tok::kw___read_write: + ParseOpenCLQualifiers(DS); + break; + + case tok::less: + // GCC ObjC supports types like "" as a synonym for + // "id". This is hopelessly old fashioned and dangerous, + // but we support it. + if (DS.hasTypeSpecifier() || !getLangOpts().ObjC1) + goto DoneWithDeclSpec; + + if (!ParseObjCProtocolQualifiers(DS)) + Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id) + << FixItHint::CreateInsertion(Loc, "id") + << SourceRange(Loc, DS.getSourceRange().getEnd()); + + // Need to support trailing type qualifiers (e.g. "id

const"). + // If a type specifier follows, it will be diagnosed elsewhere. + continue; + } + // If the specifier wasn't legal, issue a diagnostic. + if (isInvalid) { + assert(PrevSpec && "Method did not return previous specifier!"); + assert(DiagID); + + if (DiagID == diag::ext_duplicate_declspec) + Diag(Tok, DiagID) + << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); + else + Diag(Tok, DiagID) << PrevSpec; + } + + DS.SetRangeEnd(Tok.getLocation()); + if (DiagID != diag::err_bool_redeclaration) + ConsumeToken(); + } +} + +/// ParseStructDeclaration - Parse a struct declaration without the terminating +/// semicolon. +/// +/// struct-declaration: +/// specifier-qualifier-list struct-declarator-list +/// [GNU] __extension__ struct-declaration +/// [GNU] specifier-qualifier-list +/// struct-declarator-list: +/// struct-declarator +/// struct-declarator-list ',' struct-declarator +/// [GNU] struct-declarator-list ',' attributes[opt] struct-declarator +/// struct-declarator: +/// declarator +/// [GNU] declarator attributes[opt] +/// declarator[opt] ':' constant-expression +/// [GNU] declarator[opt] ':' constant-expression attributes[opt] +/// +void Parser:: +ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { + + if (Tok.is(tok::kw___extension__)) { + // __extension__ silences extension warnings in the subexpression. + ExtensionRAIIObject O(Diags); // Use RAII to do this. + ConsumeToken(); + return ParseStructDeclaration(DS, Fields); + } + + // Parse the common specifier-qualifiers-list piece. + ParseSpecifierQualifierList(DS); + + // If there are no declarators, this is a free-standing declaration + // specifier. Let the actions module cope with it. + if (Tok.is(tok::semi)) { + Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, DS); + return; + } + + // Read struct-declarators until we find the semicolon. + bool FirstDeclarator = true; + SourceLocation CommaLoc; + while (1) { + ParsingDeclRAIIObject PD(*this); + FieldDeclarator DeclaratorInfo(DS); + DeclaratorInfo.D.setCommaLoc(CommaLoc); + + // Attributes are only allowed here on successive declarators. + if (!FirstDeclarator) + MaybeParseGNUAttributes(DeclaratorInfo.D); + + /// struct-declarator: declarator + /// struct-declarator: declarator[opt] ':' constant-expression + if (Tok.isNot(tok::colon)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); + ParseDeclarator(DeclaratorInfo.D); + } + + if (Tok.is(tok::colon)) { + ConsumeToken(); + ExprResult Res(ParseConstantExpression()); + if (Res.isInvalid()) + SkipUntil(tok::semi, true, true); + else + DeclaratorInfo.BitfieldSize = Res.release(); + } + + // If attributes exist after the declarator, parse them. + MaybeParseGNUAttributes(DeclaratorInfo.D); + + // We're done with this declarator; invoke the callback. + Decl *D = Fields.invoke(DeclaratorInfo); + PD.complete(D); + + // If we don't have a comma, it is either the end of the list (a ';') + // or an error, bail out. + if (Tok.isNot(tok::comma)) + return; + + // Consume the comma. + CommaLoc = ConsumeToken(); + + FirstDeclarator = false; + } +} + +/// ParseStructUnionBody +/// struct-contents: +/// struct-declaration-list +/// [EXT] empty +/// [GNU] "struct-declaration-list" without terminatoring ';' +/// struct-declaration-list: +/// struct-declaration +/// struct-declaration-list struct-declaration +/// [OBC] '@' 'defs' '(' class-name ')' +/// +void Parser::ParseStructUnionBody(SourceLocation RecordLoc, + unsigned TagType, Decl *TagDecl) { + PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc, + "parsing struct/union body"); + + BalancedDelimiterTracker T(*this, tok::l_brace); + if (T.consumeOpen()) + return; + + ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); + Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); + + // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in + // C++. + if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) { + Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union); + Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union); + } + + SmallVector FieldDecls; + + // While we still have something to read, read the declarations in the struct. + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + // Each iteration of this loop reads one struct-declaration. + + // Check for extraneous top-level semicolon. + if (Tok.is(tok::semi)) { + Diag(Tok, diag::ext_extra_struct_semi) + << DeclSpec::getSpecifierName((DeclSpec::TST)TagType) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeToken(); + continue; + } + + // Parse all the comma separated declarators. + DeclSpec DS(AttrFactory); + + if (!Tok.is(tok::at)) { + struct CFieldCallback : FieldCallback { + Parser &P; + Decl *TagDecl; + SmallVectorImpl &FieldDecls; + + CFieldCallback(Parser &P, Decl *TagDecl, + SmallVectorImpl &FieldDecls) : + P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {} + + virtual Decl *invoke(FieldDeclarator &FD) { + // Install the declarator into the current TagDecl. + Decl *Field = P.Actions.ActOnField(P.getCurScope(), TagDecl, + FD.D.getDeclSpec().getSourceRange().getBegin(), + FD.D, FD.BitfieldSize); + FieldDecls.push_back(Field); + return Field; + } + } Callback(*this, TagDecl, FieldDecls); + + ParseStructDeclaration(DS, Callback); + } else { // Handle @defs + ConsumeToken(); + if (!Tok.isObjCAtKeyword(tok::objc_defs)) { + Diag(Tok, diag::err_unexpected_at); + SkipUntil(tok::semi, true); + continue; + } + ConsumeToken(); + ExpectAndConsume(tok::l_paren, diag::err_expected_lparen); + if (!Tok.is(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::semi, true); + continue; + } + SmallVector Fields; + Actions.ActOnDefs(getCurScope(), TagDecl, Tok.getLocation(), + Tok.getIdentifierInfo(), Fields); + FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end()); + ConsumeToken(); + ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); + } + + if (Tok.is(tok::semi)) { + ConsumeToken(); + } else if (Tok.is(tok::r_brace)) { + ExpectAndConsume(tok::semi, diag::ext_expected_semi_decl_list); + break; + } else { + ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list); + // Skip to end of block or statement to avoid ext-warning on extra ';'. + SkipUntil(tok::r_brace, true, true); + // If we stopped at a ';', eat it. + if (Tok.is(tok::semi)) ConsumeToken(); + } + } + + T.consumeClose(); + + ParsedAttributes attrs(AttrFactory); + // If attributes exist after struct contents, parse them. + MaybeParseGNUAttributes(attrs); + + Actions.ActOnFields(getCurScope(), + RecordLoc, TagDecl, FieldDecls, + T.getOpenLocation(), T.getCloseLocation(), + attrs.getList()); + StructScope.Exit(); + Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, + T.getCloseLocation()); +} + +/// ParseEnumSpecifier +/// enum-specifier: [C99 6.7.2.2] +/// 'enum' identifier[opt] '{' enumerator-list '}' +///[C99/C++]'enum' identifier[opt] '{' enumerator-list ',' '}' +/// [GNU] 'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt] +/// '}' attributes[opt] +/// [MS] 'enum' __declspec[opt] identifier[opt] '{' enumerator-list ',' [opt] +/// '}' +/// 'enum' identifier +/// [GNU] 'enum' attributes[opt] identifier +/// +/// [C++11] enum-head '{' enumerator-list[opt] '}' +/// [C++11] enum-head '{' enumerator-list ',' '}' +/// +/// enum-head: [C++11] +/// enum-key attribute-specifier-seq[opt] identifier[opt] enum-base[opt] +/// enum-key attribute-specifier-seq[opt] nested-name-specifier +/// identifier enum-base[opt] +/// +/// enum-key: [C++11] +/// 'enum' +/// 'enum' 'class' +/// 'enum' 'struct' +/// +/// enum-base: [C++11] +/// ':' type-specifier-seq +/// +/// [C++] elaborated-type-specifier: +/// [C++] 'enum' '::'[opt] nested-name-specifier[opt] identifier +/// +void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, + const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS, DeclSpecContext DSC) { + // Parse the tag portion of this. + if (Tok.is(tok::code_completion)) { + // Code completion for an enum name. + Actions.CodeCompleteTag(getCurScope(), DeclSpec::TST_enum); + return cutOffParsing(); + } + + SourceLocation ScopedEnumKWLoc; + bool IsScopedUsingClassTag = false; + + if (getLangOpts().CPlusPlus0x && + (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) { + Diag(Tok, diag::warn_cxx98_compat_scoped_enum); + IsScopedUsingClassTag = Tok.is(tok::kw_class); + ScopedEnumKWLoc = ConsumeToken(); + } + + // C++11 [temp.explicit]p12: The usual access controls do not apply to names + // used to specify explicit instantiations. We extend this to also cover + // explicit specializations. + Sema::SuppressAccessChecksRAII SuppressAccess(Actions, + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + + // If attributes exist after tag, parse them. + ParsedAttributes attrs(AttrFactory); + MaybeParseGNUAttributes(attrs); + + // If declspecs exist after tag, parse them. + while (Tok.is(tok::kw___declspec)) + ParseMicrosoftDeclSpec(attrs); + + // Enum definitions should not be parsed in a trailing-return-type. + bool AllowDeclaration = DSC != DSC_trailing; + + bool AllowFixedUnderlyingType = AllowDeclaration && + (getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt || + getLangOpts().ObjC2); + + CXXScopeSpec &SS = DS.getTypeSpecScope(); + if (getLangOpts().CPlusPlus) { + // "enum foo : bar;" is not a potential typo for "enum foo::bar;" + // if a fixed underlying type is allowed. + ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType); + + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*EnteringContext=*/false)) + return; + + if (SS.isSet() && Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + if (Tok.isNot(tok::l_brace)) { + // Has no name and is not a definition. + // Skip the rest of this declarator, up until the comma or semicolon. + SkipUntil(tok::comma, true); + return; + } + } + } + + // Must have either 'enum name' or 'enum {...}'. + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) && + !(AllowFixedUnderlyingType && Tok.is(tok::colon))) { + Diag(Tok, diag::err_expected_ident_lbrace); + + // Skip the rest of this declarator, up until the comma or semicolon. + SkipUntil(tok::comma, true); + return; + } + + // If an identifier is present, consume and remember it. + IdentifierInfo *Name = 0; + SourceLocation NameLoc; + if (Tok.is(tok::identifier)) { + Name = Tok.getIdentifierInfo(); + NameLoc = ConsumeToken(); + } + + if (!Name && ScopedEnumKWLoc.isValid()) { + // C++0x 7.2p2: The optional identifier shall not be omitted in the + // declaration of a scoped enumeration. + Diag(Tok, diag::err_scoped_enum_missing_identifier); + ScopedEnumKWLoc = SourceLocation(); + IsScopedUsingClassTag = false; + } + + // Stop suppressing access control now we've parsed the enum name. + SuppressAccess.done(); + + TypeResult BaseType; + + // Parse the fixed underlying type. + if (AllowFixedUnderlyingType && Tok.is(tok::colon)) { + bool PossibleBitfield = false; + if (getCurScope()->getFlags() & Scope::ClassScope) { + // If we're in class scope, this can either be an enum declaration with + // an underlying type, or a declaration of a bitfield member. We try to + // use a simple disambiguation scheme first to catch the common cases + // (integer literal, sizeof); if it's still ambiguous, we then consider + // anything that's a simple-type-specifier followed by '(' as an + // expression. This suffices because function types are not valid + // underlying types anyway. + TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind()); + // If the next token starts an expression, we know we're parsing a + // bit-field. This is the common case. + if (TPR == TPResult::True()) + PossibleBitfield = true; + // If the next token starts a type-specifier-seq, it may be either a + // a fixed underlying type or the start of a function-style cast in C++; + // lookahead one more token to see if it's obvious that we have a + // fixed underlying type. + else if (TPR == TPResult::False() && + GetLookAheadToken(2).getKind() == tok::semi) { + // Consume the ':'. + ConsumeToken(); + } else { + // We have the start of a type-specifier-seq, so we have to perform + // tentative parsing to determine whether we have an expression or a + // type. + TentativeParsingAction TPA(*this); + + // Consume the ':'. + ConsumeToken(); + + // If we see a type specifier followed by an open-brace, we have an + // ambiguity between an underlying type and a C++11 braced + // function-style cast. Resolve this by always treating it as an + // underlying type. + // FIXME: The standard is not entirely clear on how to disambiguate in + // this case. + if ((getLangOpts().CPlusPlus && + isCXXDeclarationSpecifier(TPResult::True()) != TPResult::True()) || + (!getLangOpts().CPlusPlus && !isDeclarationSpecifier(true))) { + // We'll parse this as a bitfield later. + PossibleBitfield = true; + TPA.Revert(); + } else { + // We have a type-specifier-seq. + TPA.Commit(); + } + } + } else { + // Consume the ':'. + ConsumeToken(); + } + + if (!PossibleBitfield) { + SourceRange Range; + BaseType = ParseTypeName(&Range); + + if (!getLangOpts().CPlusPlus0x && !getLangOpts().ObjC2) + Diag(StartLoc, diag::ext_ms_enum_fixed_underlying_type) + << Range; + if (getLangOpts().CPlusPlus0x) + Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type); + } + } + + // There are four options here. If we have 'friend enum foo;' then this is a + // friend declaration, and cannot have an accompanying definition. If we have + // 'enum foo;', then this is a forward declaration. If we have + // 'enum foo {...' then this is a definition. Otherwise we have something + // like 'enum foo xyz', a reference. + // + // This is needed to handle stuff like this right (C99 6.7.2.3p11): + // enum foo {..}; void bar() { enum foo; } <- new foo in bar. + // enum foo {..}; void bar() { enum foo x; } <- use of old foo. + // + Sema::TagUseKind TUK; + if (DS.isFriendSpecified()) + TUK = Sema::TUK_Friend; + else if (!AllowDeclaration) + TUK = Sema::TUK_Reference; + else if (Tok.is(tok::l_brace)) + TUK = Sema::TUK_Definition; + else if (Tok.is(tok::semi) && DSC != DSC_type_specifier) + TUK = Sema::TUK_Declaration; + else + TUK = Sema::TUK_Reference; + + MultiTemplateParamsArg TParams; + if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && + TUK != Sema::TUK_Reference) { + if (!getLangOpts().CPlusPlus0x || !SS.isSet()) { + // Skip the rest of this declarator, up until the comma or semicolon. + Diag(Tok, diag::err_enum_template); + SkipUntil(tok::comma, true); + return; + } + + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { + // Enumerations can't be explicitly instantiated. + DS.SetTypeSpecError(); + Diag(StartLoc, diag::err_explicit_instantiation_enum); + return; + } + + assert(TemplateInfo.TemplateParams && "no template parameters"); + TParams = MultiTemplateParamsArg(TemplateInfo.TemplateParams->data(), + TemplateInfo.TemplateParams->size()); + } + + if (!Name && TUK != Sema::TUK_Definition) { + Diag(Tok, diag::err_enumerator_unnamed_no_def); + + // Skip the rest of this declarator, up until the comma or semicolon. + SkipUntil(tok::comma, true); + return; + } + + bool Owned = false; + bool IsDependent = false; + const char *PrevSpec = 0; + unsigned DiagID; + Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, + StartLoc, SS, Name, NameLoc, attrs.getList(), + AS, DS.getModulePrivateSpecLoc(), TParams, + Owned, IsDependent, ScopedEnumKWLoc, + IsScopedUsingClassTag, BaseType); + + if (IsDependent) { + // This enum has a dependent nested-name-specifier. Handle it as a + // dependent tag. + if (!Name) { + DS.SetTypeSpecError(); + Diag(Tok, diag::err_expected_type_name_after_typename); + return; + } + + TypeResult Type = Actions.ActOnDependentTag(getCurScope(), DeclSpec::TST_enum, + TUK, SS, Name, StartLoc, + NameLoc); + if (Type.isInvalid()) { + DS.SetTypeSpecError(); + return; + } + + if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, + PrevSpec, DiagID, Type.get())) + Diag(StartLoc, DiagID) << PrevSpec; + + return; + } + + if (!TagDecl) { + // The action failed to produce an enumeration tag. If this is a + // definition, consume the entire definition. + if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { + ConsumeBrace(); + SkipUntil(tok::r_brace); + } + + DS.SetTypeSpecError(); + return; + } + + if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { + if (TUK == Sema::TUK_Friend) { + Diag(Tok, diag::err_friend_decl_defines_type) + << SourceRange(DS.getFriendSpecLoc()); + ConsumeBrace(); + SkipUntil(tok::r_brace); + } else { + ParseEnumBody(StartLoc, TagDecl); + } + } + + if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, + PrevSpec, DiagID, TagDecl, Owned)) + Diag(StartLoc, DiagID) << PrevSpec; +} + +/// ParseEnumBody - Parse a {} enclosed enumerator-list. +/// enumerator-list: +/// enumerator +/// enumerator-list ',' enumerator +/// enumerator: +/// enumeration-constant +/// enumeration-constant '=' constant-expression +/// enumeration-constant: +/// identifier +/// +void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { + // Enter the scope of the enum body and start the definition. + ParseScope EnumScope(this, Scope::DeclScope); + Actions.ActOnTagStartDefinition(getCurScope(), EnumDecl); + + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); + + // C does not allow an empty enumerator-list, C++ does [dcl.enum]. + if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) + Diag(Tok, diag::error_empty_enum); + + SmallVector EnumConstantDecls; + + Decl *LastEnumConstDecl = 0; + + // Parse the enumerator-list. + while (Tok.is(tok::identifier)) { + IdentifierInfo *Ident = Tok.getIdentifierInfo(); + SourceLocation IdentLoc = ConsumeToken(); + + // If attributes exist after the enumerator, parse them. + ParsedAttributes attrs(AttrFactory); + MaybeParseGNUAttributes(attrs); + + SourceLocation EqualLoc; + ExprResult AssignedVal; + ParsingDeclRAIIObject PD(*this); + + if (Tok.is(tok::equal)) { + EqualLoc = ConsumeToken(); + AssignedVal = ParseConstantExpression(); + if (AssignedVal.isInvalid()) + SkipUntil(tok::comma, tok::r_brace, true, true); + } + + // Install the enumerator constant into EnumDecl. + Decl *EnumConstDecl = Actions.ActOnEnumConstant(getCurScope(), EnumDecl, + LastEnumConstDecl, + IdentLoc, Ident, + attrs.getList(), EqualLoc, + AssignedVal.release()); + PD.complete(EnumConstDecl); + + EnumConstantDecls.push_back(EnumConstDecl); + LastEnumConstDecl = EnumConstDecl; + + if (Tok.is(tok::identifier)) { + // We're missing a comma between enumerators. + SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation); + Diag(Loc, diag::err_enumerator_list_missing_comma) + << FixItHint::CreateInsertion(Loc, ", "); + continue; + } + + if (Tok.isNot(tok::comma)) + break; + SourceLocation CommaLoc = ConsumeToken(); + + if (Tok.isNot(tok::identifier)) { + if (!getLangOpts().C99 && !getLangOpts().CPlusPlus0x) + Diag(CommaLoc, diag::ext_enumerator_list_comma) + << getLangOpts().CPlusPlus + << FixItHint::CreateRemoval(CommaLoc); + else if (getLangOpts().CPlusPlus0x) + Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma) + << FixItHint::CreateRemoval(CommaLoc); + } + } + + // Eat the }. + T.consumeClose(); + + // If attributes exist after the identifier list, parse them. + ParsedAttributes attrs(AttrFactory); + MaybeParseGNUAttributes(attrs); + + Actions.ActOnEnumBody(StartLoc, T.getOpenLocation(), T.getCloseLocation(), + EnumDecl, EnumConstantDecls.data(), + EnumConstantDecls.size(), getCurScope(), + attrs.getList()); + + EnumScope.Exit(); + Actions.ActOnTagFinishDefinition(getCurScope(), EnumDecl, + T.getCloseLocation()); +} + +/// isTypeSpecifierQualifier - Return true if the current token could be the +/// start of a type-qualifier-list. +bool Parser::isTypeQualifier() const { + switch (Tok.getKind()) { + default: return false; + + // type-qualifier only in OpenCL + case tok::kw_private: + return getLangOpts().OpenCL; + + // type-qualifier + case tok::kw_const: + case tok::kw_volatile: + case tok::kw_restrict: + case tok::kw___private: + case tok::kw___local: + case tok::kw___global: + case tok::kw___constant: + case tok::kw___read_only: + case tok::kw___read_write: + case tok::kw___write_only: + return true; + } +} + +/// isKnownToBeTypeSpecifier - Return true if we know that the specified token +/// is definitely a type-specifier. Return false if it isn't part of a type +/// specifier or if we're not sure. +bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { + switch (Tok.getKind()) { + default: return false; + // type-specifiers + case tok::kw_short: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw__Complex: + case tok::kw__Imaginary: + case tok::kw_void: + case tok::kw_char: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_int: + case tok::kw_half: + case tok::kw_float: + case tok::kw_double: + case tok::kw_bool: + case tok::kw__Bool: + case tok::kw__Decimal32: + case tok::kw__Decimal64: + case tok::kw__Decimal128: + case tok::kw___vector: + + // struct-or-union-specifier (C99) or class-specifier (C++) + case tok::kw_class: + case tok::kw_struct: + case tok::kw_union: + // enum-specifier + case tok::kw_enum: + + // typedef-name + case tok::annot_typename: + return true; + } +} + +/// isTypeSpecifierQualifier - Return true if the current token could be the +/// start of a specifier-qualifier-list. +bool Parser::isTypeSpecifierQualifier() { + switch (Tok.getKind()) { + default: return false; + + case tok::identifier: // foo::bar + if (TryAltiVecVectorToken()) + return true; + // Fall through. + case tok::kw_typename: // typename T::type + // Annotate typenames and C++ scope specifiers. If we get one, just + // recurse to handle whatever we get. + if (TryAnnotateTypeOrScopeToken()) + return true; + if (Tok.is(tok::identifier)) + return false; + return isTypeSpecifierQualifier(); + + case tok::coloncolon: // ::foo::bar + if (NextToken().is(tok::kw_new) || // ::new + NextToken().is(tok::kw_delete)) // ::delete + return false; + + if (TryAnnotateTypeOrScopeToken()) + return true; + return isTypeSpecifierQualifier(); + + // GNU attributes support. + case tok::kw___attribute: + // GNU typeof support. + case tok::kw_typeof: + + // type-specifiers + case tok::kw_short: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw__Complex: + case tok::kw__Imaginary: + case tok::kw_void: + case tok::kw_char: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_int: + case tok::kw_half: + case tok::kw_float: + case tok::kw_double: + case tok::kw_bool: + case tok::kw__Bool: + case tok::kw__Decimal32: + case tok::kw__Decimal64: + case tok::kw__Decimal128: + case tok::kw___vector: + + // struct-or-union-specifier (C99) or class-specifier (C++) + case tok::kw_class: + case tok::kw_struct: + case tok::kw_union: + // enum-specifier + case tok::kw_enum: + + // type-qualifier + case tok::kw_const: + case tok::kw_volatile: + case tok::kw_restrict: + + // typedef-name + case tok::annot_typename: + return true; + + // GNU ObjC bizarre protocol extension: with implicit 'id'. + case tok::less: + return getLangOpts().ObjC1; + + case tok::kw___cdecl: + case tok::kw___stdcall: + case tok::kw___fastcall: + case tok::kw___thiscall: + case tok::kw___w64: + case tok::kw___ptr64: + case tok::kw___ptr32: + case tok::kw___pascal: + case tok::kw___unaligned: + + case tok::kw___private: + case tok::kw___local: + case tok::kw___global: + case tok::kw___constant: + case tok::kw___read_only: + case tok::kw___read_write: + case tok::kw___write_only: + + return true; + + case tok::kw_private: + return getLangOpts().OpenCL; + + // C11 _Atomic() + case tok::kw__Atomic: + return true; + } +} + +/// isDeclarationSpecifier() - Return true if the current token is part of a +/// declaration specifier. +/// +/// \param DisambiguatingWithExpression True to indicate that the purpose of +/// this check is to disambiguate between an expression and a declaration. +bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { + switch (Tok.getKind()) { + default: return false; + + case tok::kw_private: + return getLangOpts().OpenCL; + + case tok::identifier: // foo::bar + // Unfortunate hack to support "Class.factoryMethod" notation. + if (getLangOpts().ObjC1 && NextToken().is(tok::period)) + return false; + if (TryAltiVecVectorToken()) + return true; + // Fall through. + case tok::kw_decltype: // decltype(T())::type + case tok::kw_typename: // typename T::type + // Annotate typenames and C++ scope specifiers. If we get one, just + // recurse to handle whatever we get. + if (TryAnnotateTypeOrScopeToken()) + return true; + if (Tok.is(tok::identifier)) + return false; + + // If we're in Objective-C and we have an Objective-C class type followed + // by an identifier and then either ':' or ']', in a place where an + // expression is permitted, then this is probably a class message send + // missing the initial '['. In this case, we won't consider this to be + // the start of a declaration. + if (DisambiguatingWithExpression && + isStartOfObjCClassMessageMissingOpenBracket()) + return false; + + return isDeclarationSpecifier(); + + case tok::coloncolon: // ::foo::bar + if (NextToken().is(tok::kw_new) || // ::new + NextToken().is(tok::kw_delete)) // ::delete + return false; + + // Annotate typenames and C++ scope specifiers. If we get one, just + // recurse to handle whatever we get. + if (TryAnnotateTypeOrScopeToken()) + return true; + return isDeclarationSpecifier(); + + // storage-class-specifier + case tok::kw_typedef: + case tok::kw_extern: + case tok::kw___private_extern__: + case tok::kw_static: + case tok::kw_auto: + case tok::kw_register: + case tok::kw___thread: + + // Modules + case tok::kw___module_private__: + + // type-specifiers + case tok::kw_short: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw__Complex: + case tok::kw__Imaginary: + case tok::kw_void: + case tok::kw_char: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + + case tok::kw_int: + case tok::kw_half: + case tok::kw_float: + case tok::kw_double: + case tok::kw_bool: + case tok::kw__Bool: + case tok::kw__Decimal32: + case tok::kw__Decimal64: + case tok::kw__Decimal128: + case tok::kw___vector: + + // struct-or-union-specifier (C99) or class-specifier (C++) + case tok::kw_class: + case tok::kw_struct: + case tok::kw_union: + // enum-specifier + case tok::kw_enum: + + // type-qualifier + case tok::kw_const: + case tok::kw_volatile: + case tok::kw_restrict: + + // function-specifier + case tok::kw_inline: + case tok::kw_virtual: + case tok::kw_explicit: + + // static_assert-declaration + case tok::kw__Static_assert: + + // GNU typeof support. + case tok::kw_typeof: + + // GNU attributes. + case tok::kw___attribute: + return true; + + // C++0x decltype. + case tok::annot_decltype: + return true; + + // C11 _Atomic() + case tok::kw__Atomic: + return true; + + // GNU ObjC bizarre protocol extension: with implicit 'id'. + case tok::less: + return getLangOpts().ObjC1; + + // typedef-name + case tok::annot_typename: + return !DisambiguatingWithExpression || + !isStartOfObjCClassMessageMissingOpenBracket(); + + case tok::kw___declspec: + case tok::kw___cdecl: + case tok::kw___stdcall: + case tok::kw___fastcall: + case tok::kw___thiscall: + case tok::kw___w64: + case tok::kw___ptr64: + case tok::kw___ptr32: + case tok::kw___forceinline: + case tok::kw___pascal: + case tok::kw___unaligned: + + case tok::kw___private: + case tok::kw___local: + case tok::kw___global: + case tok::kw___constant: + case tok::kw___read_only: + case tok::kw___read_write: + case tok::kw___write_only: + + return true; + } +} + +bool Parser::isConstructorDeclarator() { + TentativeParsingAction TPA(*this); + + // Parse the C++ scope specifier. + CXXScopeSpec SS; + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*EnteringContext=*/true)) { + TPA.Revert(); + return false; + } + + // Parse the constructor name. + if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { + // We already know that we have a constructor name; just consume + // the token. + ConsumeToken(); + } else { + TPA.Revert(); + return false; + } + + // Current class name must be followed by a left parenthesis. + if (Tok.isNot(tok::l_paren)) { + TPA.Revert(); + return false; + } + ConsumeParen(); + + // A right parenthesis, or ellipsis followed by a right parenthesis signals + // that we have a constructor. + if (Tok.is(tok::r_paren) || + (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren))) { + TPA.Revert(); + return true; + } + + // If we need to, enter the specified scope. + DeclaratorScopeObj DeclScopeObj(*this, SS); + if (SS.isSet() && Actions.ShouldEnterDeclaratorScope(getCurScope(), SS)) + DeclScopeObj.EnterDeclaratorScope(); + + // Optionally skip Microsoft attributes. + ParsedAttributes Attrs(AttrFactory); + MaybeParseMicrosoftAttributes(Attrs); + + // Check whether the next token(s) are part of a declaration + // specifier, in which case we have the start of a parameter and, + // therefore, we know that this is a constructor. + bool IsConstructor = false; + if (isDeclarationSpecifier()) + IsConstructor = true; + else if (Tok.is(tok::identifier) || + (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) { + // We've seen "C ( X" or "C ( X::Y", but "X" / "X::Y" is not a type. + // This might be a parenthesized member name, but is more likely to + // be a constructor declaration with an invalid argument type. Keep + // looking. + if (Tok.is(tok::annot_cxxscope)) + ConsumeToken(); + ConsumeToken(); + + // If this is not a constructor, we must be parsing a declarator, + // which must have one of the following syntactic forms (see the + // grammar extract at the start of ParseDirectDeclarator): + switch (Tok.getKind()) { + case tok::l_paren: + // C(X ( int)); + case tok::l_square: + // C(X [ 5]); + // C(X [ [attribute]]); + case tok::coloncolon: + // C(X :: Y); + // C(X :: *p); + case tok::r_paren: + // C(X ) + // Assume this isn't a constructor, rather than assuming it's a + // constructor with an unnamed parameter of an ill-formed type. + break; + + default: + IsConstructor = true; + break; + } + } + + TPA.Revert(); + return IsConstructor; +} + +/// ParseTypeQualifierListOpt +/// type-qualifier-list: [C99 6.7.5] +/// type-qualifier +/// [vendor] attributes +/// [ only if VendorAttributesAllowed=true ] +/// type-qualifier-list type-qualifier +/// [vendor] type-qualifier-list attributes +/// [ only if VendorAttributesAllowed=true ] +/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq +/// [ only if CXX0XAttributesAllowed=true ] +/// Note: vendor can be GNU, MS, etc. +/// +void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, + bool VendorAttributesAllowed, + bool CXX11AttributesAllowed) { + if (getLangOpts().CPlusPlus0x && CXX11AttributesAllowed && + isCXX11AttributeSpecifier()) { + ParsedAttributesWithRange attrs(AttrFactory); + ParseCXX11Attributes(attrs); + DS.takeAttributesFrom(attrs); + } + + SourceLocation EndLoc; + + while (1) { + bool isInvalid = false; + const char *PrevSpec = 0; + unsigned DiagID = 0; + SourceLocation Loc = Tok.getLocation(); + + switch (Tok.getKind()) { + case tok::code_completion: + Actions.CodeCompleteTypeQualifiers(DS); + return cutOffParsing(); + + case tok::kw_const: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID, + getLangOpts()); + break; + case tok::kw_volatile: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, + getLangOpts()); + break; + case tok::kw_restrict: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, + getLangOpts()); + break; + + // OpenCL qualifiers: + case tok::kw_private: + if (!getLangOpts().OpenCL) + goto DoneWithTypeQuals; + case tok::kw___private: + case tok::kw___global: + case tok::kw___local: + case tok::kw___constant: + case tok::kw___read_only: + case tok::kw___write_only: + case tok::kw___read_write: + ParseOpenCLQualifiers(DS); + break; + + case tok::kw___w64: + case tok::kw___ptr64: + case tok::kw___ptr32: + case tok::kw___cdecl: + case tok::kw___stdcall: + case tok::kw___fastcall: + case tok::kw___thiscall: + case tok::kw___unaligned: + if (VendorAttributesAllowed) { + ParseMicrosoftTypeAttributes(DS.getAttributes()); + continue; + } + goto DoneWithTypeQuals; + case tok::kw___pascal: + if (VendorAttributesAllowed) { + ParseBorlandTypeAttributes(DS.getAttributes()); + continue; + } + goto DoneWithTypeQuals; + case tok::kw___attribute: + if (VendorAttributesAllowed) { + ParseGNUAttributes(DS.getAttributes()); + continue; // do *not* consume the next token! + } + // otherwise, FALL THROUGH! + default: + DoneWithTypeQuals: + // If this is not a type-qualifier token, we're done reading type + // qualifiers. First verify that DeclSpec's are consistent. + DS.Finish(Diags, PP); + if (EndLoc.isValid()) + DS.SetRangeEnd(EndLoc); + return; + } + + // If the specifier combination wasn't legal, issue a diagnostic. + if (isInvalid) { + assert(PrevSpec && "Method did not return previous specifier!"); + Diag(Tok, DiagID) << PrevSpec; + } + EndLoc = ConsumeToken(); + } +} + + +/// ParseDeclarator - Parse and verify a newly-initialized declarator. +/// +void Parser::ParseDeclarator(Declarator &D) { + /// This implements the 'declarator' production in the C grammar, then checks + /// for well-formedness and issues diagnostics. + ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); +} + +static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang) { + if (Kind == tok::star || Kind == tok::caret) + return true; + + // We parse rvalue refs in C++03, because otherwise the errors are scary. + if (!Lang.CPlusPlus) + return false; + + return Kind == tok::amp || Kind == tok::ampamp; +} + +/// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator +/// is parsed by the function passed to it. Pass null, and the direct-declarator +/// isn't parsed at all, making this function effectively parse the C++ +/// ptr-operator production. +/// +/// If the grammar of this construct is extended, matching changes must also be +/// made to TryParseDeclarator and MightBeDeclarator, and possibly to +/// isConstructorDeclarator. +/// +/// declarator: [C99 6.7.5] [C++ 8p4, dcl.decl] +/// [C] pointer[opt] direct-declarator +/// [C++] direct-declarator +/// [C++] ptr-operator declarator +/// +/// pointer: [C99 6.7.5] +/// '*' type-qualifier-list[opt] +/// '*' type-qualifier-list[opt] pointer +/// +/// ptr-operator: +/// '*' cv-qualifier-seq[opt] +/// '&' +/// [C++0x] '&&' +/// [GNU] '&' restrict[opt] attributes[opt] +/// [GNU?] '&&' restrict[opt] attributes[opt] +/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] +void Parser::ParseDeclaratorInternal(Declarator &D, + DirectDeclParseFunction DirectDeclParser) { + if (Diags.hasAllExtensionsSilenced()) + D.setExtension(); + + // C++ member pointers start with a '::' or a nested-name. + // Member pointers get special handling, since there's no place for the + // scope spec in the generic path below. + if (getLangOpts().CPlusPlus && + (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) || + Tok.is(tok::annot_cxxscope))) { + bool EnteringContext = D.getContext() == Declarator::FileContext || + D.getContext() == Declarator::MemberContext; + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext); + + if (SS.isNotEmpty()) { + if (Tok.isNot(tok::star)) { + // The scope spec really belongs to the direct-declarator. + D.getCXXScopeSpec() = SS; + if (DirectDeclParser) + (this->*DirectDeclParser)(D); + return; + } + + SourceLocation Loc = ConsumeToken(); + D.SetRangeEnd(Loc); + DeclSpec DS(AttrFactory); + ParseTypeQualifierListOpt(DS); + D.ExtendWithDeclSpec(DS); + + // Recurse to parse whatever is left. + ParseDeclaratorInternal(D, DirectDeclParser); + + // Sema will have to catch (syntactically invalid) pointers into global + // scope. It has to catch pointers into namespace scope anyway. + D.AddTypeInfo(DeclaratorChunk::getMemberPointer(SS,DS.getTypeQualifiers(), + Loc), + DS.getAttributes(), + /* Don't replace range end. */SourceLocation()); + return; + } + } + + tok::TokenKind Kind = Tok.getKind(); + // Not a pointer, C++ reference, or block. + if (!isPtrOperatorToken(Kind, getLangOpts())) { + if (DirectDeclParser) + (this->*DirectDeclParser)(D); + return; + } + + // Otherwise, '*' -> pointer, '^' -> block, '&' -> lvalue reference, + // '&&' -> rvalue reference + SourceLocation Loc = ConsumeToken(); // Eat the *, ^, & or &&. + D.SetRangeEnd(Loc); + + if (Kind == tok::star || Kind == tok::caret) { + // Is a pointer. + DeclSpec DS(AttrFactory); + + // FIXME: GNU attributes are not allowed here in a new-type-id. + ParseTypeQualifierListOpt(DS); + D.ExtendWithDeclSpec(DS); + + // Recursively parse the declarator. + ParseDeclaratorInternal(D, DirectDeclParser); + if (Kind == tok::star) + // Remember that we parsed a pointer type, and remember the type-quals. + D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc, + DS.getConstSpecLoc(), + DS.getVolatileSpecLoc(), + DS.getRestrictSpecLoc()), + DS.getAttributes(), + SourceLocation()); + else + // Remember that we parsed a Block type, and remember the type-quals. + D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(), + Loc), + DS.getAttributes(), + SourceLocation()); + } else { + // Is a reference + DeclSpec DS(AttrFactory); + + // Complain about rvalue references in C++03, but then go on and build + // the declarator. + if (Kind == tok::ampamp) + Diag(Loc, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_rvalue_reference : + diag::ext_rvalue_reference); + + // GNU-style and C++11 attributes are allowed here, as is restrict. + ParseTypeQualifierListOpt(DS); + D.ExtendWithDeclSpec(DS); + + // C++ 8.3.2p1: cv-qualified references are ill-formed except when the + // cv-qualifiers are introduced through the use of a typedef or of a + // template type argument, in which case the cv-qualifiers are ignored. + if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) { + if (DS.getTypeQualifiers() & DeclSpec::TQ_const) + Diag(DS.getConstSpecLoc(), + diag::err_invalid_reference_qualifier_application) << "const"; + if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) + Diag(DS.getVolatileSpecLoc(), + diag::err_invalid_reference_qualifier_application) << "volatile"; + } + + // Recursively parse the declarator. + ParseDeclaratorInternal(D, DirectDeclParser); + + if (D.getNumTypeObjects() > 0) { + // C++ [dcl.ref]p4: There shall be no references to references. + DeclaratorChunk& InnerChunk = D.getTypeObject(D.getNumTypeObjects() - 1); + if (InnerChunk.Kind == DeclaratorChunk::Reference) { + if (const IdentifierInfo *II = D.getIdentifier()) + Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference) + << II; + else + Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference) + << "type name"; + + // Once we've complained about the reference-to-reference, we + // can go ahead and build the (technically ill-formed) + // declarator: reference collapsing will take care of it. + } + } + + // Remember that we parsed a reference type. It doesn't have type-quals. + D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc, + Kind == tok::amp), + DS.getAttributes(), + SourceLocation()); + } +} + +static void diagnoseMisplacedEllipsis(Parser &P, Declarator &D, + SourceLocation EllipsisLoc) { + if (EllipsisLoc.isValid()) { + FixItHint Insertion; + if (!D.getEllipsisLoc().isValid()) { + Insertion = FixItHint::CreateInsertion(D.getIdentifierLoc(), "..."); + D.setEllipsisLoc(EllipsisLoc); + } + P.Diag(EllipsisLoc, diag::err_misplaced_ellipsis_in_declaration) + << FixItHint::CreateRemoval(EllipsisLoc) << Insertion << !D.hasName(); + } +} + +/// ParseDirectDeclarator +/// direct-declarator: [C99 6.7.5] +/// [C99] identifier +/// '(' declarator ')' +/// [GNU] '(' attributes declarator ')' +/// [C90] direct-declarator '[' constant-expression[opt] ']' +/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']' +/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' +/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' +/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' +/// [C++11] direct-declarator '[' constant-expression[opt] ']' +/// attribute-specifier-seq[opt] +/// direct-declarator '(' parameter-type-list ')' +/// direct-declarator '(' identifier-list[opt] ')' +/// [GNU] direct-declarator '(' parameter-forward-declarations +/// parameter-type-list[opt] ')' +/// [C++] direct-declarator '(' parameter-declaration-clause ')' +/// cv-qualifier-seq[opt] exception-specification[opt] +/// [C++11] direct-declarator '(' parameter-declaration-clause ')' +/// attribute-specifier-seq[opt] cv-qualifier-seq[opt] +/// ref-qualifier[opt] exception-specification[opt] +/// [C++] declarator-id +/// [C++11] declarator-id attribute-specifier-seq[opt] +/// +/// declarator-id: [C++ 8] +/// '...'[opt] id-expression +/// '::'[opt] nested-name-specifier[opt] type-name +/// +/// id-expression: [C++ 5.1] +/// unqualified-id +/// qualified-id +/// +/// unqualified-id: [C++ 5.1] +/// identifier +/// operator-function-id +/// conversion-function-id +/// '~' class-name +/// template-id +/// +/// Note, any additional constructs added here may need corresponding changes +/// in isConstructorDeclarator. +void Parser::ParseDirectDeclarator(Declarator &D) { + DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); + + if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) { + // ParseDeclaratorInternal might already have parsed the scope. + if (D.getCXXScopeSpec().isEmpty()) { + bool EnteringContext = D.getContext() == Declarator::FileContext || + D.getContext() == Declarator::MemberContext; + ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(), + EnteringContext); + } + + if (D.getCXXScopeSpec().isValid()) { + if (Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) + // Change the declaration context for name lookup, until this function + // is exited (and the declarator has been parsed). + DeclScopeObj.EnterDeclaratorScope(); + } + + // C++0x [dcl.fct]p14: + // There is a syntactic ambiguity when an ellipsis occurs at the end + // of a parameter-declaration-clause without a preceding comma. In + // this case, the ellipsis is parsed as part of the + // abstract-declarator if the type of the parameter names a template + // parameter pack that has not been expanded; otherwise, it is parsed + // as part of the parameter-declaration-clause. + if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() && + !((D.getContext() == Declarator::PrototypeContext || + D.getContext() == Declarator::BlockLiteralContext) && + NextToken().is(tok::r_paren) && + !Actions.containsUnexpandedParameterPacks(D))) { + SourceLocation EllipsisLoc = ConsumeToken(); + if (isPtrOperatorToken(Tok.getKind(), getLangOpts())) { + // The ellipsis was put in the wrong place. Recover, and explain to + // the user what they should have done. + ParseDeclarator(D); + diagnoseMisplacedEllipsis(*this, D, EllipsisLoc); + return; + } else + D.setEllipsisLoc(EllipsisLoc); + + // The ellipsis can't be followed by a parenthesized declarator. We + // check for that in ParseParenDeclarator, after we have disambiguated + // the l_paren token. + } + + if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || + Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) { + // We found something that indicates the start of an unqualified-id. + // Parse that unqualified-id. + bool AllowConstructorName; + if (D.getDeclSpec().hasTypeSpecifier()) + AllowConstructorName = false; + else if (D.getCXXScopeSpec().isSet()) + AllowConstructorName = + (D.getContext() == Declarator::FileContext || + (D.getContext() == Declarator::MemberContext && + D.getDeclSpec().isFriendSpecified())); + else + AllowConstructorName = (D.getContext() == Declarator::MemberContext); + + SourceLocation TemplateKWLoc; + if (ParseUnqualifiedId(D.getCXXScopeSpec(), + /*EnteringContext=*/true, + /*AllowDestructorName=*/true, + AllowConstructorName, + ParsedType(), + TemplateKWLoc, + D.getName()) || + // Once we're past the identifier, if the scope was bad, mark the + // whole declarator bad. + D.getCXXScopeSpec().isInvalid()) { + D.SetIdentifier(0, Tok.getLocation()); + D.setInvalidType(true); + } else { + // Parsed the unqualified-id; update range information and move along. + if (D.getSourceRange().getBegin().isInvalid()) + D.SetRangeBegin(D.getName().getSourceRange().getBegin()); + D.SetRangeEnd(D.getName().getSourceRange().getEnd()); + } + goto PastIdentifier; + } + } else if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { + assert(!getLangOpts().CPlusPlus && + "There's a C++-specific check for tok::identifier above"); + assert(Tok.getIdentifierInfo() && "Not an identifier?"); + D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); + goto PastIdentifier; + } + + if (Tok.is(tok::l_paren)) { + // direct-declarator: '(' declarator ')' + // direct-declarator: '(' attributes declarator ')' + // Example: 'char (*X)' or 'int (*XX)(void)' + ParseParenDeclarator(D); + + // If the declarator was parenthesized, we entered the declarator + // scope when parsing the parenthesized declarator, then exited + // the scope already. Re-enter the scope, if we need to. + if (D.getCXXScopeSpec().isSet()) { + // If there was an error parsing parenthesized declarator, declarator + // scope may have been entered before. Don't do it again. + if (!D.isInvalidType() && + Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) + // Change the declaration context for name lookup, until this function + // is exited (and the declarator has been parsed). + DeclScopeObj.EnterDeclaratorScope(); + } + } else if (D.mayOmitIdentifier()) { + // This could be something simple like "int" (in which case the declarator + // portion is empty), if an abstract-declarator is allowed. + D.SetIdentifier(0, Tok.getLocation()); + } else { + if (D.getContext() == Declarator::MemberContext) + Diag(Tok, diag::err_expected_member_name_or_semi) + << D.getDeclSpec().getSourceRange(); + else if (getLangOpts().CPlusPlus) + Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus; + else + Diag(Tok, diag::err_expected_ident_lparen); + D.SetIdentifier(0, Tok.getLocation()); + D.setInvalidType(true); + } + + PastIdentifier: + assert(D.isPastIdentifier() && + "Haven't past the location of the identifier yet?"); + + // Don't parse attributes unless we have parsed an unparenthesized name. + if (D.hasName() && !D.getNumTypeObjects()) + MaybeParseCXX0XAttributes(D); + + while (1) { + if (Tok.is(tok::l_paren)) { + // Enter function-declaration scope, limiting any declarators to the + // function prototype scope, including parameter declarators. + ParseScope PrototypeScope(this, + Scope::FunctionPrototypeScope|Scope::DeclScope); + // The paren may be part of a C++ direct initializer, eg. "int x(1);". + // In such a case, check if we actually have a function declarator; if it + // is not, the declarator has been fully parsed. + if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { + // When not in file scope, warn for ambiguous function declarators, just + // in case the author intended it as a variable definition. + bool warnIfAmbiguous = D.getContext() != Declarator::FileContext; + if (!isCXXFunctionDeclarator(warnIfAmbiguous)) + break; + } + ParsedAttributes attrs(AttrFactory); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + ParseFunctionDeclarator(D, attrs, T); + PrototypeScope.Exit(); + } else if (Tok.is(tok::l_square)) { + ParseBracketDeclarator(D); + } else { + break; + } + } +} + +/// ParseParenDeclarator - We parsed the declarator D up to a paren. This is +/// only called before the identifier, so these are most likely just grouping +/// parens for precedence. If we find that these are actually function +/// parameter parens in an abstract-declarator, we call ParseFunctionDeclarator. +/// +/// direct-declarator: +/// '(' declarator ')' +/// [GNU] '(' attributes declarator ')' +/// direct-declarator '(' parameter-type-list ')' +/// direct-declarator '(' identifier-list[opt] ')' +/// [GNU] direct-declarator '(' parameter-forward-declarations +/// parameter-type-list[opt] ')' +/// +void Parser::ParseParenDeclarator(Declarator &D) { + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + assert(!D.isPastIdentifier() && "Should be called before passing identifier"); + + // Eat any attributes before we look at whether this is a grouping or function + // declarator paren. If this is a grouping paren, the attribute applies to + // the type being built up, for example: + // int (__attribute__(()) *x)(long y) + // If this ends up not being a grouping paren, the attribute applies to the + // first argument, for example: + // int (__attribute__(()) int x) + // In either case, we need to eat any attributes to be able to determine what + // sort of paren this is. + // + ParsedAttributes attrs(AttrFactory); + bool RequiresArg = false; + if (Tok.is(tok::kw___attribute)) { + ParseGNUAttributes(attrs); + + // We require that the argument list (if this is a non-grouping paren) be + // present even if the attribute list was empty. + RequiresArg = true; + } + // Eat any Microsoft extensions. + if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) || + Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___fastcall) || + Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr64) || + Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) { + ParseMicrosoftTypeAttributes(attrs); + } + // Eat any Borland extensions. + if (Tok.is(tok::kw___pascal)) + ParseBorlandTypeAttributes(attrs); + + // If we haven't past the identifier yet (or where the identifier would be + // stored, if this is an abstract declarator), then this is probably just + // grouping parens. However, if this could be an abstract-declarator, then + // this could also be the start of function arguments (consider 'void()'). + bool isGrouping; + + if (!D.mayOmitIdentifier()) { + // If this can't be an abstract-declarator, this *must* be a grouping + // paren, because we haven't seen the identifier yet. + isGrouping = true; + } else if (Tok.is(tok::r_paren) || // 'int()' is a function. + (getLangOpts().CPlusPlus && Tok.is(tok::ellipsis) && + NextToken().is(tok::r_paren)) || // C++ int(...) + isDeclarationSpecifier() || // 'int(int)' is a function. + isCXX11AttributeSpecifier()) { // 'int([[]]int)' is a function. + // This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is + // considered to be a type, not a K&R identifier-list. + isGrouping = false; + } else { + // Otherwise, this is a grouping paren, e.g. 'int (*X)' or 'int(X)'. + isGrouping = true; + } + + // If this is a grouping paren, handle: + // direct-declarator: '(' declarator ')' + // direct-declarator: '(' attributes declarator ')' + if (isGrouping) { + SourceLocation EllipsisLoc = D.getEllipsisLoc(); + D.setEllipsisLoc(SourceLocation()); + + bool hadGroupingParens = D.hasGroupingParens(); + D.setGroupingParens(true); + ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); + // Match the ')'. + T.consumeClose(); + D.AddTypeInfo(DeclaratorChunk::getParen(T.getOpenLocation(), + T.getCloseLocation()), + attrs, T.getCloseLocation()); + + D.setGroupingParens(hadGroupingParens); + + // An ellipsis cannot be placed outside parentheses. + if (EllipsisLoc.isValid()) + diagnoseMisplacedEllipsis(*this, D, EllipsisLoc); + + return; + } + + // Okay, if this wasn't a grouping paren, it must be the start of a function + // argument list. Recognize that this declarator will never have an + // identifier (and remember where it would have been), then call into + // ParseFunctionDeclarator to handle of argument list. + D.SetIdentifier(0, Tok.getLocation()); + + // Enter function-declaration scope, limiting any declarators to the + // function prototype scope, including parameter declarators. + ParseScope PrototypeScope(this, + Scope::FunctionPrototypeScope|Scope::DeclScope); + ParseFunctionDeclarator(D, attrs, T, RequiresArg); + PrototypeScope.Exit(); +} + +/// ParseFunctionDeclarator - We are after the identifier and have parsed the +/// declarator D up to a paren, which indicates that we are parsing function +/// arguments. +/// +/// If FirstArgAttrs is non-null, then the caller parsed those arguments +/// immediately after the open paren - they should be considered to be the +/// first argument of a parameter. +/// +/// If RequiresArg is true, then the first argument of the function is required +/// to be present and required to not be an identifier list. +/// +/// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt], +/// (C++11) ref-qualifier[opt], exception-specification[opt], +/// (C++11) attribute-specifier-seq[opt], and (C++11) trailing-return-type[opt]. +/// +/// [C++11] exception-specification: +/// dynamic-exception-specification +/// noexcept-specification +/// +void Parser::ParseFunctionDeclarator(Declarator &D, + ParsedAttributes &FirstArgAttrs, + BalancedDelimiterTracker &Tracker, + bool RequiresArg) { + assert(getCurScope()->isFunctionPrototypeScope() && + "Should call from a Function scope"); + // lparen is already consumed! + assert(D.isPastIdentifier() && "Should not call before identifier!"); + + // This should be true when the function has typed arguments. + // Otherwise, it is treated as a K&R-style function. + bool HasProto = false; + // Build up an array of information about the parsed arguments. + SmallVector ParamInfo; + // Remember where we see an ellipsis, if any. + SourceLocation EllipsisLoc; + + DeclSpec DS(AttrFactory); + bool RefQualifierIsLValueRef = true; + SourceLocation RefQualifierLoc; + SourceLocation ConstQualifierLoc; + SourceLocation VolatileQualifierLoc; + ExceptionSpecificationType ESpecType = EST_None; + SourceRange ESpecRange; + SmallVector DynamicExceptions; + SmallVector DynamicExceptionRanges; + ExprResult NoexceptExpr; + ParsedAttributes FnAttrs(AttrFactory); + ParsedType TrailingReturnType; + + Actions.ActOnStartFunctionDeclarator(); + + SourceLocation EndLoc; + if (isFunctionDeclaratorIdentifierList()) { + if (RequiresArg) + Diag(Tok, diag::err_argument_required_after_attribute); + + ParseFunctionDeclaratorIdentifierList(D, ParamInfo); + + Tracker.consumeClose(); + EndLoc = Tracker.getCloseLocation(); + } else { + if (Tok.isNot(tok::r_paren)) + ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc); + else if (RequiresArg) + Diag(Tok, diag::err_argument_required_after_attribute); + + HasProto = ParamInfo.size() || getLangOpts().CPlusPlus; + + // If we have the closing ')', eat it. + Tracker.consumeClose(); + EndLoc = Tracker.getCloseLocation(); + + if (getLangOpts().CPlusPlus) { + // FIXME: Accept these components in any order, and produce fixits to + // correct the order if the user gets it wrong. Ideally we should deal + // with the virt-specifier-seq and pure-specifier in the same way. + + // Parse cv-qualifier-seq[opt]. + ParseTypeQualifierListOpt(DS, false /*no attributes*/, false); + if (!DS.getSourceRange().getEnd().isInvalid()) { + EndLoc = DS.getSourceRange().getEnd(); + ConstQualifierLoc = DS.getConstSpecLoc(); + VolatileQualifierLoc = DS.getVolatileSpecLoc(); + } + + // Parse ref-qualifier[opt]. + if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_ref_qualifier : + diag::ext_ref_qualifier); + + RefQualifierIsLValueRef = Tok.is(tok::amp); + RefQualifierLoc = ConsumeToken(); + EndLoc = RefQualifierLoc; + } + + // C++11 [expr.prim.general]p3: + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type + // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq + // and the end of the function-definition, member-declarator, or + // declarator. + bool IsCXX11MemberFunction = + getLangOpts().CPlusPlus0x && + (D.getContext() == Declarator::MemberContext || + (D.getContext() == Declarator::FileContext && + D.getCXXScopeSpec().isValid() && + Actions.CurContext->isRecord())); + Sema::CXXThisScopeRAII ThisScope(Actions, + dyn_cast(Actions.CurContext), + DS.getTypeQualifiers(), + IsCXX11MemberFunction); + + // Parse exception-specification[opt]. + ESpecType = tryParseExceptionSpecification(ESpecRange, + DynamicExceptions, + DynamicExceptionRanges, + NoexceptExpr); + if (ESpecType != EST_None) + EndLoc = ESpecRange.getEnd(); + + // Parse attribute-specifier-seq[opt]. Per DR 979 and DR 1297, this goes + // after the exception-specification. + MaybeParseCXX0XAttributes(FnAttrs); + + // Parse trailing-return-type[opt]. + if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) { + Diag(Tok, diag::warn_cxx98_compat_trailing_return_type); + SourceRange Range; + TrailingReturnType = ParseTrailingReturnType(Range).get(); + if (Range.getEnd().isValid()) + EndLoc = Range.getEnd(); + } + } + } + + // Remember that we parsed a function type, and remember the attributes. + D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto, + /*isVariadic=*/EllipsisLoc.isValid(), + EllipsisLoc, + ParamInfo.data(), ParamInfo.size(), + DS.getTypeQualifiers(), + RefQualifierIsLValueRef, + RefQualifierLoc, ConstQualifierLoc, + VolatileQualifierLoc, + /*MutableLoc=*/SourceLocation(), + ESpecType, ESpecRange.getBegin(), + DynamicExceptions.data(), + DynamicExceptionRanges.data(), + DynamicExceptions.size(), + NoexceptExpr.isUsable() ? + NoexceptExpr.get() : 0, + Tracker.getOpenLocation(), + EndLoc, D, + TrailingReturnType), + FnAttrs, EndLoc); + + Actions.ActOnEndFunctionDeclarator(); +} + +/// isFunctionDeclaratorIdentifierList - This parameter list may have an +/// identifier list form for a K&R-style function: void foo(a,b,c) +/// +/// Note that identifier-lists are only allowed for normal declarators, not for +/// abstract-declarators. +bool Parser::isFunctionDeclaratorIdentifierList() { + return !getLangOpts().CPlusPlus + && Tok.is(tok::identifier) + && !TryAltiVecVectorToken() + // K&R identifier lists can't have typedefs as identifiers, per C99 + // 6.7.5.3p11. + && (TryAnnotateTypeOrScopeToken() || !Tok.is(tok::annot_typename)) + // Identifier lists follow a really simple grammar: the identifiers can + // be followed *only* by a ", identifier" or ")". However, K&R + // identifier lists are really rare in the brave new modern world, and + // it is very common for someone to typo a type in a non-K&R style + // list. If we are presented with something like: "void foo(intptr x, + // float y)", we don't want to start parsing the function declarator as + // though it is a K&R style declarator just because intptr is an + // invalid type. + // + // To handle this, we check to see if the token after the first + // identifier is a "," or ")". Only then do we parse it as an + // identifier list. + && (NextToken().is(tok::comma) || NextToken().is(tok::r_paren)); +} + +/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator +/// we found a K&R-style identifier list instead of a typed parameter list. +/// +/// After returning, ParamInfo will hold the parsed parameters. +/// +/// identifier-list: [C99 6.7.5] +/// identifier +/// identifier-list ',' identifier +/// +void Parser::ParseFunctionDeclaratorIdentifierList( + Declarator &D, + SmallVector &ParamInfo) { + // If there was no identifier specified for the declarator, either we are in + // an abstract-declarator, or we are in a parameter declarator which was found + // to be abstract. In abstract-declarators, identifier lists are not valid: + // diagnose this. + if (!D.getIdentifier()) + Diag(Tok, diag::ext_ident_list_in_param); + + // Maintain an efficient lookup of params we have seen so far. + llvm::SmallSet ParamsSoFar; + + while (1) { + // If this isn't an identifier, report the error and skip until ')'. + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true); + // Forget we parsed anything. + ParamInfo.clear(); + return; + } + + IdentifierInfo *ParmII = Tok.getIdentifierInfo(); + + // Reject 'typedef int y; int test(x, y)', but continue parsing. + if (Actions.getTypeName(*ParmII, Tok.getLocation(), getCurScope())) + Diag(Tok, diag::err_unexpected_typedef_ident) << ParmII; + + // Verify that the argument identifier has not already been mentioned. + if (!ParamsSoFar.insert(ParmII)) { + Diag(Tok, diag::err_param_redefinition) << ParmII; + } else { + // Remember this identifier in ParamInfo. + ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, + Tok.getLocation(), + 0)); + } + + // Eat the identifier. + ConsumeToken(); + + // The list continues if we see a comma. + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); + } +} + +/// ParseParameterDeclarationClause - Parse a (possibly empty) parameter-list +/// after the opening parenthesis. This function will not parse a K&R-style +/// identifier list. +/// +/// D is the declarator being parsed. If FirstArgAttrs is non-null, then the +/// caller parsed those arguments immediately after the open paren - they should +/// be considered to be part of the first parameter. +/// +/// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will +/// be the location of the ellipsis, if any was parsed. +/// +/// parameter-type-list: [C99 6.7.5] +/// parameter-list +/// parameter-list ',' '...' +/// [C++] parameter-list '...' +/// +/// parameter-list: [C99 6.7.5] +/// parameter-declaration +/// parameter-list ',' parameter-declaration +/// +/// parameter-declaration: [C99 6.7.5] +/// declaration-specifiers declarator +/// [C++] declaration-specifiers declarator '=' assignment-expression +/// [C++11] initializer-clause +/// [GNU] declaration-specifiers declarator attributes +/// declaration-specifiers abstract-declarator[opt] +/// [C++] declaration-specifiers abstract-declarator[opt] +/// '=' assignment-expression +/// [GNU] declaration-specifiers abstract-declarator[opt] attributes +/// [C++11] attribute-specifier-seq parameter-declaration +/// +void Parser::ParseParameterDeclarationClause( + Declarator &D, + ParsedAttributes &FirstArgAttrs, + SmallVector &ParamInfo, + SourceLocation &EllipsisLoc) { + + while (1) { + if (Tok.is(tok::ellipsis)) { + // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq + // before deciding this was a parameter-declaration-clause. + EllipsisLoc = ConsumeToken(); // Consume the ellipsis. + break; + } + + // Parse the declaration-specifiers. + // Just use the ParsingDeclaration "scope" of the declarator. + DeclSpec DS(AttrFactory); + + // Parse any C++11 attributes. + MaybeParseCXX0XAttributes(DS.getAttributes()); + + // Skip any Microsoft attributes before a param. + if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square)) + ParseMicrosoftAttributes(DS.getAttributes()); + + SourceLocation DSStart = Tok.getLocation(); + + // If the caller parsed attributes for the first argument, add them now. + // Take them so that we only apply the attributes to the first parameter. + // FIXME: If we can leave the attributes in the token stream somehow, we can + // get rid of a parameter (FirstArgAttrs) and this statement. It might be + // too much hassle. + DS.takeAttributesFrom(FirstArgAttrs); + + ParseDeclarationSpecifiers(DS); + + // Parse the declarator. This is "PrototypeContext", because we must + // accept either 'declarator' or 'abstract-declarator' here. + Declarator ParmDecl(DS, Declarator::PrototypeContext); + ParseDeclarator(ParmDecl); + + // Parse GNU attributes, if present. + MaybeParseGNUAttributes(ParmDecl); + + // Remember this parsed parameter in ParamInfo. + IdentifierInfo *ParmII = ParmDecl.getIdentifier(); + + // DefArgToks is used when the parsing of default arguments needs + // to be delayed. + CachedTokens *DefArgToks = 0; + + // If no parameter was specified, verify that *something* was specified, + // otherwise we have a missing type and identifier. + if (DS.isEmpty() && ParmDecl.getIdentifier() == 0 && + ParmDecl.getNumTypeObjects() == 0) { + // Completely missing, emit error. + Diag(DSStart, diag::err_missing_param); + } else { + // Otherwise, we have something. Add it and let semantic analysis try + // to grok it and add the result to the ParamInfo we are building. + + // Inform the actions module about the parameter declarator, so it gets + // added to the current scope. + Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl); + + // Parse the default argument, if any. We parse the default + // arguments in all dialects; the semantic analysis in + // ActOnParamDefaultArgument will reject the default argument in + // C. + if (Tok.is(tok::equal)) { + SourceLocation EqualLoc = Tok.getLocation(); + + // Parse the default argument + if (D.getContext() == Declarator::MemberContext) { + // If we're inside a class definition, cache the tokens + // corresponding to the default argument. We'll actually parse + // them when we see the end of the class definition. + // FIXME: Can we use a smart pointer for Toks? + DefArgToks = new CachedTokens; + + if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks, + /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/false)) { + delete DefArgToks; + DefArgToks = 0; + Actions.ActOnParamDefaultArgumentError(Param); + } else { + // Mark the end of the default argument so that we know when to + // stop when we parse it later on. + Token DefArgEnd; + DefArgEnd.startToken(); + DefArgEnd.setKind(tok::cxx_defaultarg_end); + DefArgEnd.setLocation(Tok.getLocation()); + DefArgToks->push_back(DefArgEnd); + Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc, + (*DefArgToks)[1].getLocation()); + } + } else { + // Consume the '='. + ConsumeToken(); + + // The argument isn't actually potentially evaluated unless it is + // used. + EnterExpressionEvaluationContext Eval(Actions, + Sema::PotentiallyEvaluatedIfUsed, + Param); + + ExprResult DefArgResult; + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + DefArgResult = ParseBraceInitializer(); + } else + DefArgResult = ParseAssignmentExpression(); + if (DefArgResult.isInvalid()) { + Actions.ActOnParamDefaultArgumentError(Param); + SkipUntil(tok::comma, tok::r_paren, true, true); + } else { + // Inform the actions module about the default argument + Actions.ActOnParamDefaultArgument(Param, EqualLoc, + DefArgResult.take()); + } + } + } + + ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, + ParmDecl.getIdentifierLoc(), Param, + DefArgToks)); + } + + // If the next token is a comma, consume it and keep reading arguments. + if (Tok.isNot(tok::comma)) { + if (Tok.is(tok::ellipsis)) { + EllipsisLoc = ConsumeToken(); // Consume the ellipsis. + + if (!getLangOpts().CPlusPlus) { + // We have ellipsis without a preceding ',', which is ill-formed + // in C. Complain and provide the fix. + Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis) + << FixItHint::CreateInsertion(EllipsisLoc, ", "); + } + } + + break; + } + + // Consume the comma. + ConsumeToken(); + } + +} + +/// [C90] direct-declarator '[' constant-expression[opt] ']' +/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']' +/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' +/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' +/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' +/// [C++11] direct-declarator '[' constant-expression[opt] ']' +/// attribute-specifier-seq[opt] +void Parser::ParseBracketDeclarator(Declarator &D) { + if (CheckProhibitedCXX11Attribute()) + return; + + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + + // C array syntax has many features, but by-far the most common is [] and [4]. + // This code does a fast path to handle some of the most obvious cases. + if (Tok.getKind() == tok::r_square) { + T.consumeClose(); + ParsedAttributes attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + + // Remember that we parsed the empty array type. + ExprResult NumElements; + D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, + T.getOpenLocation(), + T.getCloseLocation()), + attrs, T.getCloseLocation()); + return; + } else if (Tok.getKind() == tok::numeric_constant && + GetLookAheadToken(1).is(tok::r_square)) { + // [4] is very common. Parse the numeric constant expression. + ExprResult ExprRes(Actions.ActOnNumericConstant(Tok, getCurScope())); + ConsumeToken(); + + T.consumeClose(); + ParsedAttributes attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + + // Remember that we parsed a array type, and remember its features. + D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0, + ExprRes.release(), + T.getOpenLocation(), + T.getCloseLocation()), + attrs, T.getCloseLocation()); + return; + } + + // If valid, this location is the position where we read the 'static' keyword. + SourceLocation StaticLoc; + if (Tok.is(tok::kw_static)) + StaticLoc = ConsumeToken(); + + // If there is a type-qualifier-list, read it now. + // Type qualifiers in an array subscript are a C99 feature. + DeclSpec DS(AttrFactory); + ParseTypeQualifierListOpt(DS, false /*no attributes*/); + + // If we haven't already read 'static', check to see if there is one after the + // type-qualifier-list. + if (!StaticLoc.isValid() && Tok.is(tok::kw_static)) + StaticLoc = ConsumeToken(); + + // Handle "direct-declarator [ type-qual-list[opt] * ]". + bool isStar = false; + ExprResult NumElements; + + // Handle the case where we have '[*]' as the array size. However, a leading + // star could be the start of an expression, for example 'X[*p + 4]'. Verify + // the the token after the star is a ']'. Since stars in arrays are + // infrequent, use of lookahead is not costly here. + if (Tok.is(tok::star) && GetLookAheadToken(1).is(tok::r_square)) { + ConsumeToken(); // Eat the '*'. + + if (StaticLoc.isValid()) { + Diag(StaticLoc, diag::err_unspecified_vla_size_with_static); + StaticLoc = SourceLocation(); // Drop the static. + } + isStar = true; + } else if (Tok.isNot(tok::r_square)) { + // Note, in C89, this production uses the constant-expr production instead + // of assignment-expr. The only difference is that assignment-expr allows + // things like '=' and '*='. Sema rejects these in C89 mode because they + // are not i-c-e's, so we don't need to distinguish between the two here. + + // Parse the constant-expression or assignment-expression now (depending + // on dialect). + if (getLangOpts().CPlusPlus) { + NumElements = ParseConstantExpression(); + } else { + EnterExpressionEvaluationContext Unevaluated(Actions, + Sema::ConstantEvaluated); + NumElements = ParseAssignmentExpression(); + } + } + + // If there was an error parsing the assignment-expression, recover. + if (NumElements.isInvalid()) { + D.setInvalidType(true); + // If the expression was invalid, skip it. + SkipUntil(tok::r_square); + return; + } + + T.consumeClose(); + + ParsedAttributes attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + + // Remember that we parsed a array type, and remember its features. + D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), + StaticLoc.isValid(), isStar, + NumElements.release(), + T.getOpenLocation(), + T.getCloseLocation()), + attrs, T.getCloseLocation()); +} + +/// [GNU] typeof-specifier: +/// typeof ( expressions ) +/// typeof ( type-name ) +/// [GNU/C++] typeof unary-expression +/// +void Parser::ParseTypeofSpecifier(DeclSpec &DS) { + assert(Tok.is(tok::kw_typeof) && "Not a typeof specifier"); + Token OpTok = Tok; + SourceLocation StartLoc = ConsumeToken(); + + const bool hasParens = Tok.is(tok::l_paren); + + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + + bool isCastExpr; + ParsedType CastTy; + SourceRange CastRange; + ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, + CastTy, CastRange); + if (hasParens) + DS.setTypeofParensRange(CastRange); + + if (CastRange.getEnd().isInvalid()) + // FIXME: Not accurate, the range gets one token more than it should. + DS.SetRangeEnd(Tok.getLocation()); + else + DS.SetRangeEnd(CastRange.getEnd()); + + if (isCastExpr) { + if (!CastTy) { + DS.SetTypeSpecError(); + return; + } + + const char *PrevSpec = 0; + unsigned DiagID; + // Check for duplicate type specifiers (e.g. "int typeof(int)"). + if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec, + DiagID, CastTy)) + Diag(StartLoc, DiagID) << PrevSpec; + return; + } + + // If we get here, the operand to the typeof was an expresion. + if (Operand.isInvalid()) { + DS.SetTypeSpecError(); + return; + } + + // We might need to transform the operand if it is potentially evaluated. + Operand = Actions.HandleExprEvaluationContextForTypeof(Operand.get()); + if (Operand.isInvalid()) { + DS.SetTypeSpecError(); + return; + } + + const char *PrevSpec = 0; + unsigned DiagID; + // Check for duplicate type specifiers (e.g. "int typeof(int)"). + if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec, + DiagID, Operand.get())) + Diag(StartLoc, DiagID) << PrevSpec; +} + +/// [C11] atomic-specifier: +/// _Atomic ( type-name ) +/// +void Parser::ParseAtomicSpecifier(DeclSpec &DS) { + assert(Tok.is(tok::kw__Atomic) && "Not an atomic specifier"); + + SourceLocation StartLoc = ConsumeToken(); + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, "_Atomic")) { + SkipUntil(tok::r_paren); + return; + } + + TypeResult Result = ParseTypeName(); + if (Result.isInvalid()) { + SkipUntil(tok::r_paren); + return; + } + + // Match the ')' + T.consumeClose(); + + if (T.getCloseLocation().isInvalid()) + return; + + DS.setTypeofParensRange(T.getRange()); + DS.SetRangeEnd(T.getCloseLocation()); + + const char *PrevSpec = 0; + unsigned DiagID; + if (DS.SetTypeSpecType(DeclSpec::TST_atomic, StartLoc, PrevSpec, + DiagID, Result.release())) + Diag(StartLoc, DiagID) << PrevSpec; +} + + +/// TryAltiVecVectorTokenOutOfLine - Out of line body that should only be called +/// from TryAltiVecVectorToken. +bool Parser::TryAltiVecVectorTokenOutOfLine() { + Token Next = NextToken(); + switch (Next.getKind()) { + default: return false; + case tok::kw_short: + case tok::kw_long: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_float: + case tok::kw_double: + case tok::kw_bool: + case tok::kw___pixel: + Tok.setKind(tok::kw___vector); + return true; + case tok::identifier: + if (Next.getIdentifierInfo() == Ident_pixel) { + Tok.setKind(tok::kw___vector); + return true; + } + return false; + } +} + +bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + bool &isInvalid) { + if (Tok.getIdentifierInfo() == Ident_vector) { + Token Next = NextToken(); + switch (Next.getKind()) { + case tok::kw_short: + case tok::kw_long: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_float: + case tok::kw_double: + case tok::kw_bool: + case tok::kw___pixel: + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + return true; + case tok::identifier: + if (Next.getIdentifierInfo() == Ident_pixel) { + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + return true; + } + break; + default: + break; + } + } else if ((Tok.getIdentifierInfo() == Ident_pixel) && + DS.isTypeAltiVecVector()) { + isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); + return true; + } + return false; +} diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp new file mode 100644 index 0000000..5e6c4f5 --- /dev/null +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -0,0 +1,3020 @@ +//===--- ParseDeclCXX.cpp - C++ Declaration Parsing -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the C++ Declaration portions of the Parser interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/OperatorKinds.h" +#include "clang/Parse/Parser.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/PrettyDeclStackTrace.h" +#include "llvm/ADT/SmallString.h" +#include "RAIIObjectsForParser.h" +using namespace clang; + +/// ParseNamespace - We know that the current token is a namespace keyword. This +/// may either be a top level namespace or a block-level namespace alias. If +/// there was an inline keyword, it has already been parsed. +/// +/// namespace-definition: [C++ 7.3: basic.namespace] +/// named-namespace-definition +/// unnamed-namespace-definition +/// +/// unnamed-namespace-definition: +/// 'inline'[opt] 'namespace' attributes[opt] '{' namespace-body '}' +/// +/// named-namespace-definition: +/// original-namespace-definition +/// extension-namespace-definition +/// +/// original-namespace-definition: +/// 'inline'[opt] 'namespace' identifier attributes[opt] +/// '{' namespace-body '}' +/// +/// extension-namespace-definition: +/// 'inline'[opt] 'namespace' original-namespace-name +/// '{' namespace-body '}' +/// +/// namespace-alias-definition: [C++ 7.3.2: namespace.alias] +/// 'namespace' identifier '=' qualified-namespace-specifier ';' +/// +Decl *Parser::ParseNamespace(unsigned Context, + SourceLocation &DeclEnd, + SourceLocation InlineLoc) { + assert(Tok.is(tok::kw_namespace) && "Not a namespace!"); + SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'. + ObjCDeclContextSwitch ObjCDC(*this); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteNamespaceDecl(getCurScope()); + cutOffParsing(); + return 0; + } + + SourceLocation IdentLoc; + IdentifierInfo *Ident = 0; + std::vector ExtraIdentLoc; + std::vector ExtraIdent; + std::vector ExtraNamespaceLoc; + + Token attrTok; + + if (Tok.is(tok::identifier)) { + Ident = Tok.getIdentifierInfo(); + IdentLoc = ConsumeToken(); // eat the identifier. + while (Tok.is(tok::coloncolon) && NextToken().is(tok::identifier)) { + ExtraNamespaceLoc.push_back(ConsumeToken()); + ExtraIdent.push_back(Tok.getIdentifierInfo()); + ExtraIdentLoc.push_back(ConsumeToken()); + } + } + + // Read label attributes, if present. + ParsedAttributes attrs(AttrFactory); + if (Tok.is(tok::kw___attribute)) { + attrTok = Tok; + ParseGNUAttributes(attrs); + } + + if (Tok.is(tok::equal)) { + if (!attrs.empty()) + Diag(attrTok, diag::err_unexpected_namespace_attributes_alias); + if (InlineLoc.isValid()) + Diag(InlineLoc, diag::err_inline_namespace_alias) + << FixItHint::CreateRemoval(InlineLoc); + return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd); + } + + + BalancedDelimiterTracker T(*this, tok::l_brace); + if (T.consumeOpen()) { + if (!ExtraIdent.empty()) { + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); + } + Diag(Tok, Ident ? diag::err_expected_lbrace : + diag::err_expected_ident_lbrace); + return 0; + } + + if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() || + getCurScope()->isInObjcMethodScope() || getCurScope()->getBlockParent() || + getCurScope()->getFnParent()) { + if (!ExtraIdent.empty()) { + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); + } + Diag(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope); + SkipUntil(tok::r_brace, false); + return 0; + } + + if (!ExtraIdent.empty()) { + TentativeParsingAction TPA(*this); + SkipUntil(tok::r_brace, /*StopAtSemi*/false, /*DontConsume*/true); + Token rBraceToken = Tok; + TPA.Revert(); + + if (!rBraceToken.is(tok::r_brace)) { + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); + } else { + std::string NamespaceFix; + for (std::vector::iterator I = ExtraIdent.begin(), + E = ExtraIdent.end(); I != E; ++I) { + NamespaceFix += " { namespace "; + NamespaceFix += (*I)->getName(); + } + + std::string RBraces; + for (unsigned i = 0, e = ExtraIdent.size(); i != e; ++i) + RBraces += "} "; + + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(), + ExtraIdentLoc.back()), + NamespaceFix) + << FixItHint::CreateInsertion(rBraceToken.getLocation(), RBraces); + } + } + + // If we're still good, complain about inline namespaces in non-C++0x now. + if (InlineLoc.isValid()) + Diag(InlineLoc, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_inline_namespace : diag::ext_inline_namespace); + + // Enter a scope for the namespace. + ParseScope NamespaceScope(this, Scope::DeclScope); + + Decl *NamespcDecl = + Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, NamespaceLoc, + IdentLoc, Ident, T.getOpenLocation(), + attrs.getList()); + + PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc, + "parsing namespace"); + + // Parse the contents of the namespace. This includes parsing recovery on + // any improperly nested namespaces. + ParseInnerNamespace(ExtraIdentLoc, ExtraIdent, ExtraNamespaceLoc, 0, + InlineLoc, attrs, T); + + // Leave the namespace scope. + NamespaceScope.Exit(); + + DeclEnd = T.getCloseLocation(); + Actions.ActOnFinishNamespaceDef(NamespcDecl, DeclEnd); + + return NamespcDecl; +} + +/// ParseInnerNamespace - Parse the contents of a namespace. +void Parser::ParseInnerNamespace(std::vector& IdentLoc, + std::vector& Ident, + std::vector& NamespaceLoc, + unsigned int index, SourceLocation& InlineLoc, + ParsedAttributes& attrs, + BalancedDelimiterTracker &Tracker) { + if (index == Ident.size()) { + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + ParseExternalDeclaration(attrs); + } + + // The caller is what called check -- we are simply calling + // the close for it. + Tracker.consumeClose(); + + return; + } + + // Parse improperly nested namespaces. + ParseScope NamespaceScope(this, Scope::DeclScope); + Decl *NamespcDecl = + Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(), + NamespaceLoc[index], IdentLoc[index], + Ident[index], Tracker.getOpenLocation(), + attrs.getList()); + + ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc, + attrs, Tracker); + + NamespaceScope.Exit(); + + Actions.ActOnFinishNamespaceDef(NamespcDecl, Tracker.getCloseLocation()); +} + +/// ParseNamespaceAlias - Parse the part after the '=' in a namespace +/// alias definition. +/// +Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, + SourceLocation AliasLoc, + IdentifierInfo *Alias, + SourceLocation &DeclEnd) { + assert(Tok.is(tok::equal) && "Not equal token"); + + ConsumeToken(); // eat the '='. + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteNamespaceAliasDecl(getCurScope()); + cutOffParsing(); + return 0; + } + + CXXScopeSpec SS; + // Parse (optional) nested-name-specifier. + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + + if (SS.isInvalid() || Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_namespace_name); + // Skip to end of the definition and eat the ';'. + SkipUntil(tok::semi); + return 0; + } + + // Parse identifier. + IdentifierInfo *Ident = Tok.getIdentifierInfo(); + SourceLocation IdentLoc = ConsumeToken(); + + // Eat the ';'. + DeclEnd = Tok.getLocation(); + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_namespace_name, + "", tok::semi); + + return Actions.ActOnNamespaceAliasDef(getCurScope(), NamespaceLoc, AliasLoc, Alias, + SS, IdentLoc, Ident); +} + +/// ParseLinkage - We know that the current token is a string_literal +/// and just before that, that extern was seen. +/// +/// linkage-specification: [C++ 7.5p2: dcl.link] +/// 'extern' string-literal '{' declaration-seq[opt] '}' +/// 'extern' string-literal declaration +/// +Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { + assert(Tok.is(tok::string_literal) && "Not a string literal!"); + SmallString<8> LangBuffer; + bool Invalid = false; + StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid); + if (Invalid) + return 0; + + // FIXME: This is incorrect: linkage-specifiers are parsed in translation + // phase 7, so string-literal concatenation is supposed to occur. + // extern "" "C" "" "+" "+" { } is legal. + if (Tok.hasUDSuffix()) + Diag(Tok, diag::err_invalid_string_udl); + SourceLocation Loc = ConsumeStringToken(); + + ParseScope LinkageScope(this, Scope::DeclScope); + Decl *LinkageSpec + = Actions.ActOnStartLinkageSpecification(getCurScope(), + DS.getSourceRange().getBegin(), + Loc, Lang, + Tok.is(tok::l_brace) ? Tok.getLocation() + : SourceLocation()); + + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + + if (Tok.isNot(tok::l_brace)) { + // Reset the source range in DS, as the leading "extern" + // does not really belong to the inner declaration ... + DS.SetRangeStart(SourceLocation()); + DS.SetRangeEnd(SourceLocation()); + // ... but anyway remember that such an "extern" was seen. + DS.setExternInLinkageSpec(true); + ParseExternalDeclaration(attrs, &DS); + return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec, + SourceLocation()); + } + + DS.abort(); + + ProhibitAttributes(attrs); + + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + ParseExternalDeclaration(attrs); + } + + T.consumeClose(); + return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec, + T.getCloseLocation()); +} + +/// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or +/// using-directive. Assumes that current token is 'using'. +Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs, + Decl **OwnedType) { + assert(Tok.is(tok::kw_using) && "Not using token"); + ObjCDeclContextSwitch ObjCDC(*this); + + // Eat 'using'. + SourceLocation UsingLoc = ConsumeToken(); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteUsing(getCurScope()); + cutOffParsing(); + return 0; + } + + // 'using namespace' means this is a using-directive. + if (Tok.is(tok::kw_namespace)) { + // Template parameters are always an error here. + if (TemplateInfo.Kind) { + SourceRange R = TemplateInfo.getSourceRange(); + Diag(UsingLoc, diag::err_templated_using_directive) + << R << FixItHint::CreateRemoval(R); + } + + return ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs); + } + + // Otherwise, it must be a using-declaration or an alias-declaration. + + // Using declarations can't have attributes. + ProhibitAttributes(attrs); + + return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd, + AS_none, OwnedType); +} + +/// ParseUsingDirective - Parse C++ using-directive, assumes +/// that current token is 'namespace' and 'using' was already parsed. +/// +/// using-directive: [C++ 7.3.p4: namespace.udir] +/// 'using' 'namespace' ::[opt] nested-name-specifier[opt] +/// namespace-name ; +/// [GNU] using-directive: +/// 'using' 'namespace' ::[opt] nested-name-specifier[opt] +/// namespace-name attributes[opt] ; +/// +Decl *Parser::ParseUsingDirective(unsigned Context, + SourceLocation UsingLoc, + SourceLocation &DeclEnd, + ParsedAttributes &attrs) { + assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token"); + + // Eat 'namespace'. + SourceLocation NamespcLoc = ConsumeToken(); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteUsingDirective(getCurScope()); + cutOffParsing(); + return 0; + } + + CXXScopeSpec SS; + // Parse (optional) nested-name-specifier. + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + + IdentifierInfo *NamespcName = 0; + SourceLocation IdentLoc = SourceLocation(); + + // Parse namespace-name. + if (SS.isInvalid() || Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_namespace_name); + // If there was invalid namespace name, skip to end of decl, and eat ';'. + SkipUntil(tok::semi); + // FIXME: Are there cases, when we would like to call ActOnUsingDirective? + return 0; + } + + // Parse identifier. + NamespcName = Tok.getIdentifierInfo(); + IdentLoc = ConsumeToken(); + + // Parse (optional) attributes (most likely GNU strong-using extension). + bool GNUAttr = false; + if (Tok.is(tok::kw___attribute)) { + GNUAttr = true; + ParseGNUAttributes(attrs); + } + + // Eat ';'. + DeclEnd = Tok.getLocation(); + ExpectAndConsume(tok::semi, + GNUAttr ? diag::err_expected_semi_after_attribute_list + : diag::err_expected_semi_after_namespace_name, + "", tok::semi); + + return Actions.ActOnUsingDirective(getCurScope(), UsingLoc, NamespcLoc, SS, + IdentLoc, NamespcName, attrs.getList()); +} + +/// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration. +/// Assumes that 'using' was already seen. +/// +/// using-declaration: [C++ 7.3.p3: namespace.udecl] +/// 'using' 'typename'[opt] ::[opt] nested-name-specifier +/// unqualified-id +/// 'using' :: unqualified-id +/// +/// alias-declaration: C++0x [decl.typedef]p2 +/// 'using' identifier = type-id ; +/// +Decl *Parser::ParseUsingDeclaration(unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + SourceLocation UsingLoc, + SourceLocation &DeclEnd, + AccessSpecifier AS, + Decl **OwnedType) { + CXXScopeSpec SS; + SourceLocation TypenameLoc; + bool IsTypeName; + + // Ignore optional 'typename'. + // FIXME: This is wrong; we should parse this as a typename-specifier. + if (Tok.is(tok::kw_typename)) { + TypenameLoc = Tok.getLocation(); + ConsumeToken(); + IsTypeName = true; + } + else + IsTypeName = false; + + // Parse nested-name-specifier. + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + + // Check nested-name specifier. + if (SS.isInvalid()) { + SkipUntil(tok::semi); + return 0; + } + + // Parse the unqualified-id. We allow parsing of both constructor and + // destructor names and allow the action module to diagnose any semantic + // errors. + SourceLocation TemplateKWLoc; + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/true, + ParsedType(), + TemplateKWLoc, + Name)) { + SkipUntil(tok::semi); + return 0; + } + + ParsedAttributes attrs(AttrFactory); + + // Maybe this is an alias-declaration. + bool IsAliasDecl = Tok.is(tok::equal); + TypeResult TypeAlias; + if (IsAliasDecl) { + // TODO: Attribute support. C++0x attributes may appear before the equals. + // Where can GNU attributes appear? + ConsumeToken(); + + Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_alias_declaration : + diag::ext_alias_declaration); + + // Type alias templates cannot be specialized. + int SpecKind = -1; + if (TemplateInfo.Kind == ParsedTemplateInfo::Template && + Name.getKind() == UnqualifiedId::IK_TemplateId) + SpecKind = 0; + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization) + SpecKind = 1; + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + SpecKind = 2; + if (SpecKind != -1) { + SourceRange Range; + if (SpecKind == 0) + Range = SourceRange(Name.TemplateId->LAngleLoc, + Name.TemplateId->RAngleLoc); + else + Range = TemplateInfo.getSourceRange(); + Diag(Range.getBegin(), diag::err_alias_declaration_specialization) + << SpecKind << Range; + SkipUntil(tok::semi); + return 0; + } + + // Name must be an identifier. + if (Name.getKind() != UnqualifiedId::IK_Identifier) { + Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier); + // No removal fixit: can't recover from this. + SkipUntil(tok::semi); + return 0; + } else if (IsTypeName) + Diag(TypenameLoc, diag::err_alias_declaration_not_identifier) + << FixItHint::CreateRemoval(SourceRange(TypenameLoc, + SS.isNotEmpty() ? SS.getEndLoc() : TypenameLoc)); + else if (SS.isNotEmpty()) + Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier) + << FixItHint::CreateRemoval(SS.getRange()); + + TypeAlias = ParseTypeName(0, TemplateInfo.Kind ? + Declarator::AliasTemplateContext : + Declarator::AliasDeclContext, AS, OwnedType); + } else + // Parse (optional) attributes (most likely GNU strong-using extension). + MaybeParseGNUAttributes(attrs); + + // Eat ';'. + DeclEnd = Tok.getLocation(); + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, + !attrs.empty() ? "attributes list" : + IsAliasDecl ? "alias declaration" : "using declaration", + tok::semi); + + // Diagnose an attempt to declare a templated using-declaration. + // In C++0x, alias-declarations can be templates: + // template <...> using id = type; + if (TemplateInfo.Kind && !IsAliasDecl) { + SourceRange R = TemplateInfo.getSourceRange(); + Diag(UsingLoc, diag::err_templated_using_declaration) + << R << FixItHint::CreateRemoval(R); + + // Unfortunately, we have to bail out instead of recovering by + // ignoring the parameters, just in case the nested name specifier + // depends on the parameters. + return 0; + } + + // "typename" keyword is allowed for identifiers only, + // because it may be a type definition. + if (IsTypeName && Name.getKind() != UnqualifiedId::IK_Identifier) { + Diag(Name.getSourceRange().getBegin(), diag::err_typename_identifiers_only) + << FixItHint::CreateRemoval(SourceRange(TypenameLoc)); + // Proceed parsing, but reset the IsTypeName flag. + IsTypeName = false; + } + + if (IsAliasDecl) { + TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; + MultiTemplateParamsArg TemplateParamsArg(Actions, + TemplateParams ? TemplateParams->data() : 0, + TemplateParams ? TemplateParams->size() : 0); + return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg, + UsingLoc, Name, TypeAlias); + } + + return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, + Name, attrs.getList(), + IsTypeName, TypenameLoc); +} + +/// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration. +/// +/// [C++0x] static_assert-declaration: +/// static_assert ( constant-expression , string-literal ) ; +/// +/// [C11] static_assert-declaration: +/// _Static_assert ( constant-expression , string-literal ) ; +/// +Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ + assert((Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) && + "Not a static_assert declaration"); + + if (Tok.is(tok::kw__Static_assert) && !getLangOpts().C11) + Diag(Tok, diag::ext_c11_static_assert); + if (Tok.is(tok::kw_static_assert)) + Diag(Tok, diag::warn_cxx98_compat_static_assert); + + SourceLocation StaticAssertLoc = ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { + Diag(Tok, diag::err_expected_lparen); + return 0; + } + + ExprResult AssertExpr(ParseConstantExpression()); + if (AssertExpr.isInvalid()) { + SkipUntil(tok::semi); + return 0; + } + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::semi)) + return 0; + + if (!isTokenStringLiteral()) { + Diag(Tok, diag::err_expected_string_literal); + SkipUntil(tok::semi); + return 0; + } + + ExprResult AssertMessage(ParseStringLiteralExpression()); + if (AssertMessage.isInvalid()) { + SkipUntil(tok::semi); + return 0; + } + + T.consumeClose(); + + DeclEnd = Tok.getLocation(); + ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert); + + return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, + AssertExpr.take(), + AssertMessage.take(), + T.getCloseLocation()); +} + +/// ParseDecltypeSpecifier - Parse a C++0x decltype specifier. +/// +/// 'decltype' ( expression ) +/// +SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { + assert((Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) + && "Not a decltype specifier"); + + + ExprResult Result; + SourceLocation StartLoc = Tok.getLocation(); + SourceLocation EndLoc; + + if (Tok.is(tok::annot_decltype)) { + Result = getExprAnnotation(Tok); + EndLoc = Tok.getAnnotationEndLoc(); + ConsumeToken(); + if (Result.isInvalid()) { + DS.SetTypeSpecError(); + return EndLoc; + } + } else { + if (Tok.getIdentifierInfo()->isStr("decltype")) + Diag(Tok, diag::warn_cxx98_compat_decltype); + + ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, + "decltype", tok::r_paren)) { + DS.SetTypeSpecError(); + return T.getOpenLocation() == Tok.getLocation() ? + StartLoc : T.getOpenLocation(); + } + + // Parse the expression + + // C++0x [dcl.type.simple]p4: + // The operand of the decltype specifier is an unevaluated operand. + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, + 0, /*IsDecltype=*/true); + Result = ParseExpression(); + if (Result.isInvalid()) { + SkipUntil(tok::r_paren); + DS.SetTypeSpecError(); + return StartLoc; + } + + // Match the ')' + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) { + DS.SetTypeSpecError(); + // FIXME: this should return the location of the last token + // that was consumed (by "consumeClose()") + return T.getCloseLocation(); + } + + Result = Actions.ActOnDecltypeExpression(Result.take()); + if (Result.isInvalid()) { + DS.SetTypeSpecError(); + return T.getCloseLocation(); + } + + EndLoc = T.getCloseLocation(); + } + + const char *PrevSpec = 0; + unsigned DiagID; + // Check for duplicate type specifiers (e.g. "int decltype(a)"). + if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec, + DiagID, Result.release())) { + Diag(StartLoc, DiagID) << PrevSpec; + DS.SetTypeSpecError(); + } + return EndLoc; +} + +void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec& DS, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // make sure we have a token we can turn into an annotation token + if (PP.isBacktrackEnabled()) + PP.RevertCachedTokens(1); + else + PP.EnterToken(Tok); + + Tok.setKind(tok::annot_decltype); + setExprAnnotation(Tok, DS.getTypeSpecType() == TST_decltype ? + DS.getRepAsExpr() : ExprResult()); + Tok.setAnnotationEndLoc(EndLoc); + Tok.setLocation(StartLoc); + PP.AnnotateCachedTokens(Tok); +} + +void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { + assert(Tok.is(tok::kw___underlying_type) && + "Not an underlying type specifier"); + + SourceLocation StartLoc = ConsumeToken(); + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, + "__underlying_type", tok::r_paren)) { + return; + } + + TypeResult Result = ParseTypeName(); + if (Result.isInvalid()) { + SkipUntil(tok::r_paren); + return; + } + + // Match the ')' + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) + return; + + const char *PrevSpec = 0; + unsigned DiagID; + if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec, + DiagID, Result.release())) + Diag(StartLoc, DiagID) << PrevSpec; +} + +/// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a +/// class name or decltype-specifier. Note that we only check that the result +/// names a type; semantic analysis will need to verify that the type names a +/// class. The result is either a type or null, depending on whether a type +/// name was found. +/// +/// base-type-specifier: [C++ 10.1] +/// class-or-decltype +/// class-or-decltype: [C++ 10.1] +/// nested-name-specifier[opt] class-name +/// decltype-specifier +/// class-name: [C++ 9.1] +/// identifier +/// simple-template-id +/// +Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, + SourceLocation &EndLocation) { + // Ignore attempts to use typename + if (Tok.is(tok::kw_typename)) { + Diag(Tok, diag::err_expected_class_name_not_template) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeToken(); + } + + // Parse optional nested-name-specifier + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + + BaseLoc = Tok.getLocation(); + + // Parse decltype-specifier + // tok == kw_decltype is just error recovery, it can only happen when SS + // isn't empty + if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) { + if (SS.isNotEmpty()) + Diag(SS.getBeginLoc(), diag::err_unexpected_scope_on_base_decltype) + << FixItHint::CreateRemoval(SS.getRange()); + // Fake up a Declarator to use with ActOnTypeName. + DeclSpec DS(AttrFactory); + + EndLocation = ParseDecltypeSpecifier(DS); + + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); + } + + // Check whether we have a template-id that names a type. + if (Tok.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (TemplateId->Kind == TNK_Type_template || + TemplateId->Kind == TNK_Dependent_template_name) { + AnnotateTemplateIdTokenAsType(); + + assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); + ParsedType Type = getTypeAnnotation(Tok); + EndLocation = Tok.getAnnotationEndLoc(); + ConsumeToken(); + + if (Type) + return Type; + return true; + } + + // Fall through to produce an error below. + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_class_name); + return true; + } + + IdentifierInfo *Id = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + + if (Tok.is(tok::less)) { + // It looks the user intended to write a template-id here, but the + // template-name was wrong. Try to fix that. + TemplateNameKind TNK = TNK_Type_template; + TemplateTy Template; + if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, getCurScope(), + &SS, Template, TNK)) { + Diag(IdLoc, diag::err_unknown_template_name) + << Id; + } + + if (!Template) + return true; + + // Form the template name + UnqualifiedId TemplateName; + TemplateName.setIdentifier(Id, IdLoc); + + // Parse the full template-id, then turn it into a type. + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName, true)) + return true; + if (TNK == TNK_Dependent_template_name) + AnnotateTemplateIdTokenAsType(); + + // If we didn't end up with a typename token, there's nothing more we + // can do. + if (Tok.isNot(tok::annot_typename)) + return true; + + // Retrieve the type from the annotation token, consume that token, and + // return. + EndLocation = Tok.getAnnotationEndLoc(); + ParsedType Type = getTypeAnnotation(Tok); + ConsumeToken(); + return Type; + } + + // We have an identifier; check whether it is actually a type. + ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true, + false, ParsedType(), + /*IsCtorOrDtorName=*/false, + /*NonTrivialTypeSourceInfo=*/true); + if (!Type) { + Diag(IdLoc, diag::err_expected_class_name); + return true; + } + + // Consume the identifier. + EndLocation = IdLoc; + + // Fake up a Declarator to use with ActOnTypeName. + DeclSpec DS(AttrFactory); + DS.SetRangeStart(IdLoc); + DS.SetRangeEnd(EndLocation); + DS.getTypeSpecScope() = SS; + + const char *PrevSpec = 0; + unsigned DiagID; + DS.SetTypeSpecType(TST_typename, IdLoc, PrevSpec, DiagID, Type); + + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); +} + +/// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or +/// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which +/// until we reach the start of a definition or see a token that +/// cannot start a definition. +/// +/// class-specifier: [C++ class] +/// class-head '{' member-specification[opt] '}' +/// class-head '{' member-specification[opt] '}' attributes[opt] +/// class-head: +/// class-key identifier[opt] base-clause[opt] +/// class-key nested-name-specifier identifier base-clause[opt] +/// class-key nested-name-specifier[opt] simple-template-id +/// base-clause[opt] +/// [GNU] class-key attributes[opt] identifier[opt] base-clause[opt] +/// [GNU] class-key attributes[opt] nested-name-specifier +/// identifier base-clause[opt] +/// [GNU] class-key attributes[opt] nested-name-specifier[opt] +/// simple-template-id base-clause[opt] +/// class-key: +/// 'class' +/// 'struct' +/// 'union' +/// +/// elaborated-type-specifier: [C++ dcl.type.elab] +/// class-key ::[opt] nested-name-specifier[opt] identifier +/// class-key ::[opt] nested-name-specifier[opt] 'template'[opt] +/// simple-template-id +/// +/// Note that the C++ class-specifier and elaborated-type-specifier, +/// together, subsume the C99 struct-or-union-specifier: +/// +/// struct-or-union-specifier: [C99 6.7.2.1] +/// struct-or-union identifier[opt] '{' struct-contents '}' +/// struct-or-union identifier +/// [GNU] struct-or-union attributes[opt] identifier[opt] '{' struct-contents +/// '}' attributes[opt] +/// [GNU] struct-or-union attributes[opt] identifier +/// struct-or-union: +/// 'struct' +/// 'union' +void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, + SourceLocation StartLoc, DeclSpec &DS, + const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS, + bool EnteringContext, DeclSpecContext DSC) { + DeclSpec::TST TagType; + if (TagTokKind == tok::kw_struct) + TagType = DeclSpec::TST_struct; + else if (TagTokKind == tok::kw_class) + TagType = DeclSpec::TST_class; + else { + assert(TagTokKind == tok::kw_union && "Not a class specifier"); + TagType = DeclSpec::TST_union; + } + + if (Tok.is(tok::code_completion)) { + // Code completion for a struct, class, or union name. + Actions.CodeCompleteTag(getCurScope(), TagType); + return cutOffParsing(); + } + + // C++03 [temp.explicit] 14.7.2/8: + // The usual access checking rules do not apply to names used to specify + // explicit instantiations. + // + // As an extension we do not perform access checking on the names used to + // specify explicit specializations either. This is important to allow + // specializing traits classes for private types. + Sema::SuppressAccessChecksRAII SuppressAccess(Actions, + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + + ParsedAttributes attrs(AttrFactory); + // If attributes exist after tag, parse them. + if (Tok.is(tok::kw___attribute)) + ParseGNUAttributes(attrs); + + // If declspecs exist after tag, parse them. + while (Tok.is(tok::kw___declspec)) + ParseMicrosoftDeclSpec(attrs); + + // If C++0x attributes exist here, parse them. + // FIXME: Are we consistent with the ordering of parsing of different + // styles of attributes? + MaybeParseCXX0XAttributes(attrs); + + if (TagType == DeclSpec::TST_struct && + !Tok.is(tok::identifier) && + Tok.getIdentifierInfo() && + (Tok.is(tok::kw___is_arithmetic) || + Tok.is(tok::kw___is_convertible) || + Tok.is(tok::kw___is_empty) || + Tok.is(tok::kw___is_floating_point) || + Tok.is(tok::kw___is_function) || + Tok.is(tok::kw___is_fundamental) || + Tok.is(tok::kw___is_integral) || + Tok.is(tok::kw___is_member_function_pointer) || + Tok.is(tok::kw___is_member_pointer) || + Tok.is(tok::kw___is_pod) || + Tok.is(tok::kw___is_pointer) || + Tok.is(tok::kw___is_same) || + Tok.is(tok::kw___is_scalar) || + Tok.is(tok::kw___is_signed) || + Tok.is(tok::kw___is_unsigned) || + Tok.is(tok::kw___is_void))) { + // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the + // name of struct templates, but some are keywords in GCC >= 4.3 + // and Clang. Therefore, when we see the token sequence "struct + // X", make X into a normal identifier rather than a keyword, to + // allow libstdc++ 4.2 and libc++ to work properly. + Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); + Tok.setKind(tok::identifier); + } + + // Parse the (optional) nested-name-specifier. + CXXScopeSpec &SS = DS.getTypeSpecScope(); + if (getLangOpts().CPlusPlus) { + // "FOO : BAR" is not a potential typo for "FOO::BAR". + ColonProtectionRAIIObject X(*this); + + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) + DS.SetTypeSpecError(); + if (SS.isSet()) + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) + Diag(Tok, diag::err_expected_ident); + } + + TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; + + // Parse the (optional) class name or simple-template-id. + IdentifierInfo *Name = 0; + SourceLocation NameLoc; + TemplateIdAnnotation *TemplateId = 0; + if (Tok.is(tok::identifier)) { + Name = Tok.getIdentifierInfo(); + NameLoc = ConsumeToken(); + + if (Tok.is(tok::less) && getLangOpts().CPlusPlus) { + // The name was supposed to refer to a template, but didn't. + // Eat the template argument list and try to continue parsing this as + // a class (or template thereof). + TemplateArgList TemplateArgs; + SourceLocation LAngleLoc, RAngleLoc; + if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, SS, + true, LAngleLoc, + TemplateArgs, RAngleLoc)) { + // We couldn't parse the template argument list at all, so don't + // try to give any location information for the list. + LAngleLoc = RAngleLoc = SourceLocation(); + } + + Diag(NameLoc, diag::err_explicit_spec_non_template) + << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + << (TagType == DeclSpec::TST_class? 0 + : TagType == DeclSpec::TST_struct? 1 + : 2) + << Name + << SourceRange(LAngleLoc, RAngleLoc); + + // Strip off the last template parameter list if it was empty, since + // we've removed its template argument list. + if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) { + if (TemplateParams && TemplateParams->size() > 1) { + TemplateParams->pop_back(); + } else { + TemplateParams = 0; + const_cast(TemplateInfo).Kind + = ParsedTemplateInfo::NonTemplate; + } + } else if (TemplateInfo.Kind + == ParsedTemplateInfo::ExplicitInstantiation) { + // Pretend this is just a forward declaration. + TemplateParams = 0; + const_cast(TemplateInfo).Kind + = ParsedTemplateInfo::NonTemplate; + const_cast(TemplateInfo).TemplateLoc + = SourceLocation(); + const_cast(TemplateInfo).ExternLoc + = SourceLocation(); + } + } + } else if (Tok.is(tok::annot_template_id)) { + TemplateId = takeTemplateIdAnnotation(Tok); + NameLoc = ConsumeToken(); + + if (TemplateId->Kind != TNK_Type_template && + TemplateId->Kind != TNK_Dependent_template_name) { + // The template-name in the simple-template-id refers to + // something other than a class template. Give an appropriate + // error message and skip to the ';'. + SourceRange Range(NameLoc); + if (SS.isNotEmpty()) + Range.setBegin(SS.getBeginLoc()); + + Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template) + << Name << static_cast(TemplateId->Kind) << Range; + + DS.SetTypeSpecError(); + SkipUntil(tok::semi, false, true); + return; + } + } + + // As soon as we're finished parsing the class's template-id, turn access + // checking back on. + SuppressAccess.done(); + + // There are four options here. + // - If we are in a trailing return type, this is always just a reference, + // and we must not try to parse a definition. For instance, + // [] () -> struct S { }; + // does not define a type. + // - If we have 'struct foo {...', 'struct foo :...', + // 'struct foo final :' or 'struct foo final {', then this is a definition. + // - If we have 'struct foo;', then this is either a forward declaration + // or a friend declaration, which have to be treated differently. + // - Otherwise we have something like 'struct foo xyz', a reference. + // However, in type-specifier-seq's, things look like declarations but are + // just references, e.g. + // new struct s; + // or + // &T::operator struct s; + // For these, DSC is DSC_type_specifier. + Sema::TagUseKind TUK; + if (DSC == DSC_trailing) + TUK = Sema::TUK_Reference; + else if (Tok.is(tok::l_brace) || + (getLangOpts().CPlusPlus && Tok.is(tok::colon)) || + (isCXX0XFinalKeyword() && + (NextToken().is(tok::l_brace) || NextToken().is(tok::colon)))) { + if (DS.isFriendSpecified()) { + // C++ [class.friend]p2: + // A class shall not be defined in a friend declaration. + Diag(Tok.getLocation(), diag::err_friend_decl_defines_type) + << SourceRange(DS.getFriendSpecLoc()); + + // Skip everything up to the semicolon, so that this looks like a proper + // friend class (or template thereof) declaration. + SkipUntil(tok::semi, true, true); + TUK = Sema::TUK_Friend; + } else { + // Okay, this is a class definition. + TUK = Sema::TUK_Definition; + } + } else if (Tok.is(tok::semi) && DSC != DSC_type_specifier) + TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; + else + TUK = Sema::TUK_Reference; + + if (!Name && !TemplateId && (DS.getTypeSpecType() == DeclSpec::TST_error || + TUK != Sema::TUK_Definition)) { + if (DS.getTypeSpecType() != DeclSpec::TST_error) { + // We have a declaration or reference to an anonymous class. + Diag(StartLoc, diag::err_anon_type_definition) + << DeclSpec::getSpecifierName(TagType); + } + + SkipUntil(tok::comma, true); + return; + } + + // Create the tag portion of the class or class template. + DeclResult TagOrTempResult = true; // invalid + TypeResult TypeResult = true; // invalid + + bool Owned = false; + if (TemplateId) { + // Explicit specialization, class template partial specialization, + // or explicit instantiation. + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && + TUK == Sema::TUK_Declaration) { + // This is an explicit instantiation of a class template. + TagOrTempResult + = Actions.ActOnExplicitInstantiation(getCurScope(), + TemplateInfo.ExternLoc, + TemplateInfo.TemplateLoc, + TagType, + StartLoc, + SS, + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc, + attrs.getList()); + + // Friend template-ids are treated as references unless + // they have template headers, in which case they're ill-formed + // (FIXME: "template friend class A::B;"). + // We diagnose this error in ActOnClassTemplateSpecialization. + } else if (TUK == Sema::TUK_Reference || + (TUK == Sema::TUK_Friend && + TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { + TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc, + TemplateId->SS, + TemplateId->TemplateKWLoc, + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); + } else { + // This is an explicit specialization or a class template + // partial specialization. + TemplateParameterLists FakedParamLists; + + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { + // This looks like an explicit instantiation, because we have + // something like + // + // template class Foo + // + // but it actually has a definition. Most likely, this was + // meant to be an explicit specialization, but the user forgot + // the '<>' after 'template'. + assert(TUK == Sema::TUK_Definition && "Expected a definition here"); + + SourceLocation LAngleLoc + = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); + Diag(TemplateId->TemplateNameLoc, + diag::err_explicit_instantiation_with_definition) + << SourceRange(TemplateInfo.TemplateLoc) + << FixItHint::CreateInsertion(LAngleLoc, "<>"); + + // Create a fake template parameter list that contains only + // "template<>", so that we treat this construct as a class + // template specialization. + FakedParamLists.push_back( + Actions.ActOnTemplateParameterList(0, SourceLocation(), + TemplateInfo.TemplateLoc, + LAngleLoc, + 0, 0, + LAngleLoc)); + TemplateParams = &FakedParamLists; + } + + // Build the class template specialization. + TagOrTempResult + = Actions.ActOnClassTemplateSpecialization(getCurScope(), TagType, TUK, + StartLoc, DS.getModulePrivateSpecLoc(), SS, + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc, + attrs.getList(), + MultiTemplateParamsArg(Actions, + TemplateParams? &(*TemplateParams)[0] : 0, + TemplateParams? TemplateParams->size() : 0)); + } + } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && + TUK == Sema::TUK_Declaration) { + // Explicit instantiation of a member of a class template + // specialization, e.g., + // + // template struct Outer::Inner; + // + TagOrTempResult + = Actions.ActOnExplicitInstantiation(getCurScope(), + TemplateInfo.ExternLoc, + TemplateInfo.TemplateLoc, + TagType, StartLoc, SS, Name, + NameLoc, attrs.getList()); + } else if (TUK == Sema::TUK_Friend && + TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) { + TagOrTempResult = + Actions.ActOnTemplatedFriendTag(getCurScope(), DS.getFriendSpecLoc(), + TagType, StartLoc, SS, + Name, NameLoc, attrs.getList(), + MultiTemplateParamsArg(Actions, + TemplateParams? &(*TemplateParams)[0] : 0, + TemplateParams? TemplateParams->size() : 0)); + } else { + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && + TUK == Sema::TUK_Definition) { + // FIXME: Diagnose this particular error. + } + + bool IsDependent = false; + + // Don't pass down template parameter lists if this is just a tag + // reference. For example, we don't need the template parameters here: + // template class A *makeA(T t); + MultiTemplateParamsArg TParams; + if (TUK != Sema::TUK_Reference && TemplateParams) + TParams = + MultiTemplateParamsArg(&(*TemplateParams)[0], TemplateParams->size()); + + // Declaration or definition of a class type + TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc, + SS, Name, NameLoc, attrs.getList(), AS, + DS.getModulePrivateSpecLoc(), + TParams, Owned, IsDependent, + SourceLocation(), false, + clang::TypeResult()); + + // If ActOnTag said the type was dependent, try again with the + // less common call. + if (IsDependent) { + assert(TUK == Sema::TUK_Reference || TUK == Sema::TUK_Friend); + TypeResult = Actions.ActOnDependentTag(getCurScope(), TagType, TUK, + SS, Name, StartLoc, NameLoc); + } + } + + // If there is a body, parse it and inform the actions module. + if (TUK == Sema::TUK_Definition) { + assert(Tok.is(tok::l_brace) || + (getLangOpts().CPlusPlus && Tok.is(tok::colon)) || + isCXX0XFinalKeyword()); + if (getLangOpts().CPlusPlus) + ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get()); + else + ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get()); + } + + const char *PrevSpec = 0; + unsigned DiagID; + bool Result; + if (!TypeResult.isInvalid()) { + Result = DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, + PrevSpec, DiagID, TypeResult.get()); + } else if (!TagOrTempResult.isInvalid()) { + Result = DS.SetTypeSpecType(TagType, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, + PrevSpec, DiagID, TagOrTempResult.get(), Owned); + } else { + DS.SetTypeSpecError(); + return; + } + + if (Result) + 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 == Sema::TUK_Definition) { + bool ExpectedSemi = true; + switch (Tok.getKind()) { + default: break; + 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 ::b; + case tok::l_paren: // struct foo {...} ( x); + case tok::comma: // __builtin_offsetof(struct foo{...} , + ExpectedSemi = false; + break; + // Type qualifiers + case tok::kw_const: // struct foo {...} const x; + case tok::kw_volatile: // struct foo {...} volatile x; + case tok::kw_restrict: // struct foo {...} restrict x; + case tok::kw_inline: // struct foo {...} inline foo() {}; + // Storage-class specifiers + case tok::kw_static: // struct foo {...} static x; + case tok::kw_extern: // struct foo {...} extern x; + case tok::kw_typedef: // struct foo {...} typedef x; + case tok::kw_register: // struct foo {...} register x; + case tok::kw_auto: // struct foo {...} auto x; + case tok::kw_mutable: // struct foo {...} mutable x; + case tok::kw_constexpr: // struct foo {...} constexpr x; + // As shown above, type qualifiers and storage class specifiers absolutely + // can occur after class specifiers according to the grammar. However, + // almost no one actually writes code like this. If we see one of these, + // it is much more likely that someone missed a semi colon and the + // type/storage class specifier we're seeing is part of the *next* + // intended declaration, as in: + // + // struct foo { ... } + // typedef int X; + // + // We'd really like to emit a missing semicolon error instead of emitting + // an error on the 'int' saying that you can't have two type specifiers in + // the same declaration of X. Because of this, we look ahead past this + // token to see if it's a type specifier. If so, we know the code is + // otherwise invalid, so we can produce the expected semi error. + if (!isKnownToBeTypeSpecifier(NextToken())) + ExpectedSemi = false; + break; + + case tok::r_brace: // struct bar { struct foo {...} } + // Missing ';' at end of struct is accepted as an extension in C mode. + if (!getLangOpts().CPlusPlus) + ExpectedSemi = false; + break; + } + + // C++ [temp]p3 In a template-declaration which defines a class, no + // declarator is permitted. + if (TemplateInfo.Kind) + ExpectedSemi = true; + + if (ExpectedSemi) { + 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); + } + } +} + +/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived]. +/// +/// base-clause : [C++ class.derived] +/// ':' base-specifier-list +/// base-specifier-list: +/// base-specifier '...'[opt] +/// base-specifier-list ',' base-specifier '...'[opt] +void Parser::ParseBaseClause(Decl *ClassDecl) { + assert(Tok.is(tok::colon) && "Not a base clause"); + ConsumeToken(); + + // Build up an array of parsed base specifiers. + SmallVector BaseInfo; + + while (true) { + // Parse a base-specifier. + BaseResult Result = ParseBaseSpecifier(ClassDecl); + if (Result.isInvalid()) { + // Skip the rest of this base specifier, up until the comma or + // opening brace. + SkipUntil(tok::comma, tok::l_brace, true, true); + } else { + // Add this to our array of base specifiers. + BaseInfo.push_back(Result.get()); + } + + // If the next token is a comma, consume it and keep reading + // base-specifiers. + if (Tok.isNot(tok::comma)) break; + + // Consume the comma. + ConsumeToken(); + } + + // Attach the base specifiers + Actions.ActOnBaseSpecifiers(ClassDecl, BaseInfo.data(), BaseInfo.size()); +} + +/// ParseBaseSpecifier - Parse a C++ base-specifier. A base-specifier is +/// one entry in the base class list of a class specifier, for example: +/// class foo : public bar, virtual private baz { +/// 'public bar' and 'virtual private baz' are each base-specifiers. +/// +/// base-specifier: [C++ class.derived] +/// ::[opt] nested-name-specifier[opt] class-name +/// 'virtual' access-specifier[opt] ::[opt] nested-name-specifier[opt] +/// base-type-specifier +/// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt] +/// base-type-specifier +Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { + bool IsVirtual = false; + SourceLocation StartLoc = Tok.getLocation(); + + // Parse the 'virtual' keyword. + if (Tok.is(tok::kw_virtual)) { + ConsumeToken(); + IsVirtual = true; + } + + // Parse an (optional) access specifier. + AccessSpecifier Access = getAccessSpecifierIfPresent(); + if (Access != AS_none) + ConsumeToken(); + + // Parse the 'virtual' keyword (again!), in case it came after the + // access specifier. + if (Tok.is(tok::kw_virtual)) { + SourceLocation VirtualLoc = ConsumeToken(); + if (IsVirtual) { + // Complain about duplicate 'virtual' + Diag(VirtualLoc, diag::err_dup_virtual) + << FixItHint::CreateRemoval(VirtualLoc); + } + + IsVirtual = true; + } + + // Parse the class-name. + SourceLocation EndLocation; + SourceLocation BaseLoc; + TypeResult BaseType = ParseBaseTypeSpecifier(BaseLoc, EndLocation); + if (BaseType.isInvalid()) + return true; + + // Parse the optional ellipsis (for a pack expansion). The ellipsis is + // actually part of the base-specifier-list grammar productions, but we + // parse it here for convenience. + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + + // Find the complete source range for the base-specifier. + SourceRange Range(StartLoc, EndLocation); + + // Notify semantic analysis that we have parsed a complete + // base-specifier. + return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access, + BaseType.get(), BaseLoc, EllipsisLoc); +} + +/// getAccessSpecifierIfPresent - Determine whether the next token is +/// a C++ access-specifier. +/// +/// access-specifier: [C++ class.derived] +/// 'private' +/// 'protected' +/// 'public' +AccessSpecifier Parser::getAccessSpecifierIfPresent() const { + switch (Tok.getKind()) { + default: return AS_none; + case tok::kw_private: return AS_private; + case tok::kw_protected: return AS_protected; + case tok::kw_public: return AS_public; + } +} + +/// \brief If the given declarator has any parts for which parsing has to be +/// delayed, e.g., default arguments, create a late-parsed method declaration +/// record to handle the parsing at the end of the class definition. +void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, + Decl *ThisDecl) { + // We just declared a member function. If this member function + // has any default arguments, we'll need to parse them later. + LateParsedMethodDeclaration *LateMethod = 0; + DeclaratorChunk::FunctionTypeInfo &FTI + = DeclaratorInfo.getFunctionTypeInfo(); + + for (unsigned ParamIdx = 0; ParamIdx < FTI.NumArgs; ++ParamIdx) { + if (LateMethod || FTI.ArgInfo[ParamIdx].DefaultArgTokens) { + if (!LateMethod) { + // Push this method onto the stack of late-parsed method + // declarations. + LateMethod = new LateParsedMethodDeclaration(this, ThisDecl); + getCurrentClass().LateParsedDeclarations.push_back(LateMethod); + LateMethod->TemplateScope = getCurScope()->isTemplateParamScope(); + + // Add all of the parameters prior to this one (they don't + // have default arguments). + LateMethod->DefaultArgs.reserve(FTI.NumArgs); + for (unsigned I = 0; I < ParamIdx; ++I) + LateMethod->DefaultArgs.push_back( + LateParsedDefaultArgument(FTI.ArgInfo[I].Param)); + } + + // Add this parameter to the list of parameters (it may or may + // not have a default argument). + LateMethod->DefaultArgs.push_back( + LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param, + FTI.ArgInfo[ParamIdx].DefaultArgTokens)); + } + } +} + +/// isCXX0XVirtSpecifier - Determine whether the given token is a C++0x +/// virt-specifier. +/// +/// virt-specifier: +/// override +/// final +VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const { + if (!getLangOpts().CPlusPlus) + return VirtSpecifiers::VS_None; + + if (Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + + // Initialize the contextual keywords. + if (!Ident_final) { + Ident_final = &PP.getIdentifierTable().get("final"); + Ident_override = &PP.getIdentifierTable().get("override"); + } + + if (II == Ident_override) + return VirtSpecifiers::VS_Override; + + if (II == Ident_final) + return VirtSpecifiers::VS_Final; + } + + return VirtSpecifiers::VS_None; +} + +/// ParseOptionalCXX0XVirtSpecifierSeq - Parse a virt-specifier-seq. +/// +/// virt-specifier-seq: +/// virt-specifier +/// virt-specifier-seq virt-specifier +void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) { + while (true) { + VirtSpecifiers::Specifier Specifier = isCXX0XVirtSpecifier(); + if (Specifier == VirtSpecifiers::VS_None) + return; + + // C++ [class.mem]p8: + // A virt-specifier-seq shall contain at most one of each virt-specifier. + const char *PrevSpec = 0; + if (VS.SetSpecifier(Specifier, Tok.getLocation(), PrevSpec)) + Diag(Tok.getLocation(), diag::err_duplicate_virt_specifier) + << PrevSpec + << FixItHint::CreateRemoval(Tok.getLocation()); + + Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_override_control_keyword : + diag::ext_override_control_keyword) + << VirtSpecifiers::getSpecifierName(Specifier); + ConsumeToken(); + } +} + +/// isCXX0XFinalKeyword - Determine whether the next token is a C++0x +/// contextual 'final' keyword. +bool Parser::isCXX0XFinalKeyword() const { + if (!getLangOpts().CPlusPlus) + return false; + + if (!Tok.is(tok::identifier)) + return false; + + // Initialize the contextual keywords. + if (!Ident_final) { + Ident_final = &PP.getIdentifierTable().get("final"); + Ident_override = &PP.getIdentifierTable().get("override"); + } + + return Tok.getIdentifierInfo() == Ident_final; +} + +/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. +/// +/// member-declaration: +/// decl-specifier-seq[opt] member-declarator-list[opt] ';' +/// function-definition ';'[opt] +/// ::[opt] nested-name-specifier template[opt] unqualified-id ';'[TODO] +/// using-declaration [TODO] +/// [C++0x] static_assert-declaration +/// template-declaration +/// [GNU] '__extension__' member-declaration +/// +/// member-declarator-list: +/// member-declarator +/// member-declarator-list ',' member-declarator +/// +/// member-declarator: +/// declarator virt-specifier-seq[opt] pure-specifier[opt] +/// declarator constant-initializer[opt] +/// [C++11] declarator brace-or-equal-initializer[opt] +/// identifier[opt] ':' constant-expression +/// +/// virt-specifier-seq: +/// virt-specifier +/// virt-specifier-seq virt-specifier +/// +/// virt-specifier: +/// override +/// final +/// +/// pure-specifier: +/// '= 0' +/// +/// constant-initializer: +/// '=' constant-expression +/// +void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, + AttributeList *AccessAttrs, + const ParsedTemplateInfo &TemplateInfo, + ParsingDeclRAIIObject *TemplateDiags) { + if (Tok.is(tok::at)) { + if (getLangOpts().ObjC1 && NextToken().isObjCAtKeyword(tok::objc_defs)) + Diag(Tok, diag::err_at_defs_cxx); + else + Diag(Tok, diag::err_at_in_class); + + ConsumeToken(); + SkipUntil(tok::r_brace); + return; + } + + // Access declarations. + if (!TemplateInfo.Kind && + (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) && + !TryAnnotateCXXScopeToken() && + Tok.is(tok::annot_cxxscope)) { + bool isAccessDecl = false; + if (NextToken().is(tok::identifier)) + isAccessDecl = GetLookAheadToken(2).is(tok::semi); + else + isAccessDecl = NextToken().is(tok::kw_operator); + + if (isAccessDecl) { + // Collect the scope specifier token we annotated earlier. + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*EnteringContext=*/false); + + // Try to parse an unqualified-id. + SourceLocation TemplateKWLoc; + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), + TemplateKWLoc, Name)) { + SkipUntil(tok::semi); + return; + } + + // TODO: recover from mistakenly-qualified operator declarations. + if (ExpectAndConsume(tok::semi, + diag::err_expected_semi_after, + "access declaration", + tok::semi)) + return; + + Actions.ActOnUsingDeclaration(getCurScope(), AS, + false, SourceLocation(), + SS, Name, + /* AttrList */ 0, + /* IsTypeName */ false, + SourceLocation()); + return; + } + } + + // static_assert-declaration + if (Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) { + // FIXME: Check for templates + SourceLocation DeclEnd; + ParseStaticAssertDeclaration(DeclEnd); + return; + } + + if (Tok.is(tok::kw_template)) { + assert(!TemplateInfo.TemplateParams && + "Nested template improperly parsed?"); + SourceLocation DeclEnd; + ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd, + AS, AccessAttrs); + return; + } + + // Handle: member-declaration ::= '__extension__' member-declaration + if (Tok.is(tok::kw___extension__)) { + // __extension__ silences extension warnings in the subexpression. + ExtensionRAIIObject O(Diags); // Use RAII to do this. + ConsumeToken(); + return ParseCXXClassMemberDeclaration(AS, AccessAttrs, + TemplateInfo, TemplateDiags); + } + + // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it + // is a bitfield. + ColonProtectionRAIIObject X(*this); + + ParsedAttributesWithRange attrs(AttrFactory); + // Optional C++0x attribute-specifier + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + + if (Tok.is(tok::kw_using)) { + ProhibitAttributes(attrs); + + // Eat 'using'. + SourceLocation UsingLoc = ConsumeToken(); + + if (Tok.is(tok::kw_namespace)) { + Diag(UsingLoc, diag::err_using_namespace_in_class); + SkipUntil(tok::semi, true, true); + } else { + SourceLocation DeclEnd; + // Otherwise, it must be a using-declaration or an alias-declaration. + ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo, + UsingLoc, DeclEnd, AS); + } + return; + } + + // Hold late-parsed attributes so we can attach a Decl to them later. + LateParsedAttrList CommonLateParsedAttrs; + + // decl-specifier-seq: + // Parse the common declaration-specifiers piece. + ParsingDeclSpec DS(*this, TemplateDiags); + DS.takeAttributesFrom(attrs); + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, + &CommonLateParsedAttrs); + + MultiTemplateParamsArg TemplateParams(Actions, + TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, + TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); + + if (Tok.is(tok::semi)) { + ConsumeToken(); + Decl *TheDecl = + Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams); + DS.complete(TheDecl); + return; + } + + ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); + VirtSpecifiers VS; + + // Hold late-parsed attributes so we can attach a Decl to them later. + LateParsedAttrList LateParsedAttrs; + + SourceLocation EqualLoc; + bool HasInitializer = false; + ExprResult Init; + if (Tok.isNot(tok::colon)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); + + // Parse the first declarator. + ParseDeclarator(DeclaratorInfo); + // Error parsing the declarator? + if (!DeclaratorInfo.hasName()) { + // If so, skip until the semi-colon or a }. + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return; + } + + ParseOptionalCXX0XVirtSpecifierSeq(VS); + + // If attributes exist after the declarator, but before an '{', parse them. + MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); + + // MSVC permits pure specifier on inline functions declared at class scope. + // Hence check for =0 before checking for function definition. + if (getLangOpts().MicrosoftExt && Tok.is(tok::equal) && + DeclaratorInfo.isFunctionDeclarator() && + NextToken().is(tok::numeric_constant)) { + EqualLoc = ConsumeToken(); + Init = ParseInitializer(); + if (Init.isInvalid()) + SkipUntil(tok::comma, true, true); + else + HasInitializer = true; + } + + FunctionDefinitionKind DefinitionKind = FDK_Declaration; + // function-definition: + // + // In C++11, a non-function declarator followed by an open brace is a + // braced-init-list for an in-class member initialization, not an + // erroneous function definition. + if (Tok.is(tok::l_brace) && !getLangOpts().CPlusPlus0x) { + DefinitionKind = FDK_Definition; + } else if (DeclaratorInfo.isFunctionDeclarator()) { + if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) { + DefinitionKind = FDK_Definition; + } else if (Tok.is(tok::equal)) { + const Token &KW = NextToken(); + if (KW.is(tok::kw_default)) + DefinitionKind = FDK_Defaulted; + else if (KW.is(tok::kw_delete)) + DefinitionKind = FDK_Deleted; + } + } + + if (DefinitionKind) { + if (!DeclaratorInfo.isFunctionDeclarator()) { + Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params); + ConsumeBrace(); + SkipUntil(tok::r_brace, /*StopAtSemi*/false); + + // Consume the optional ';' + if (Tok.is(tok::semi)) + ConsumeToken(); + return; + } + + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { + Diag(DeclaratorInfo.getIdentifierLoc(), + diag::err_function_declared_typedef); + // This recovery skips the entire function body. It would be nice + // to simply call ParseCXXInlineMethodDef() below, however Sema + // assumes the declarator represents a function, not a typedef. + ConsumeBrace(); + SkipUntil(tok::r_brace, /*StopAtSemi*/false); + + // Consume the optional ';' + if (Tok.is(tok::semi)) + ConsumeToken(); + return; + } + + Decl *FunDecl = + ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo, + VS, DefinitionKind, Init); + + for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) { + CommonLateParsedAttrs[i]->addDecl(FunDecl); + } + for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) { + LateParsedAttrs[i]->addDecl(FunDecl); + } + LateParsedAttrs.clear(); + + // Consume the ';' - it's optional unless we have a delete or default + if (Tok.is(tok::semi)) { + ConsumeToken(); + } + + return; + } + } + + // member-declarator-list: + // member-declarator + // member-declarator-list ',' member-declarator + + SmallVector DeclsInGroup; + ExprResult BitfieldSize; + bool ExpectSemi = true; + + while (1) { + // member-declarator: + // declarator pure-specifier[opt] + // declarator brace-or-equal-initializer[opt] + // identifier[opt] ':' constant-expression + if (Tok.is(tok::colon)) { + ConsumeToken(); + BitfieldSize = ParseConstantExpression(); + if (BitfieldSize.isInvalid()) + SkipUntil(tok::comma, true, true); + } + + // If a simple-asm-expr is present, parse it. + if (Tok.is(tok::kw_asm)) { + SourceLocation Loc; + ExprResult AsmLabel(ParseSimpleAsm(&Loc)); + if (AsmLabel.isInvalid()) + SkipUntil(tok::comma, true, true); + + DeclaratorInfo.setAsmLabel(AsmLabel.release()); + DeclaratorInfo.SetRangeEnd(Loc); + } + + // If attributes exist after the declarator, parse them. + MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); + + // FIXME: When g++ adds support for this, we'll need to check whether it + // goes before or after the GNU attributes and __asm__. + ParseOptionalCXX0XVirtSpecifierSeq(VS); + + bool HasDeferredInitializer = false; + if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) { + if (BitfieldSize.get()) { + Diag(Tok, diag::err_bitfield_member_init); + SkipUntil(tok::comma, true, true); + } else { + HasInitializer = true; + HasDeferredInitializer = !DeclaratorInfo.isDeclarationOfFunction() && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_static && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_typedef; + } + } + + // NOTE: If Sema is the Action module and declarator is an instance field, + // this call will *not* return the created decl; It will return null. + // See Sema::ActOnCXXMemberDeclarator for details. + + Decl *ThisDecl = 0; + if (DS.isFriendSpecified()) { + // TODO: handle initializers, bitfields, 'delete' + ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, + move(TemplateParams)); + } else { + ThisDecl = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, + DeclaratorInfo, + move(TemplateParams), + BitfieldSize.release(), + VS, HasDeferredInitializer); + if (AccessAttrs) + Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs, + false, true); + } + + // Set the Decl for any late parsed attributes + for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) { + CommonLateParsedAttrs[i]->addDecl(ThisDecl); + } + for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) { + LateParsedAttrs[i]->addDecl(ThisDecl); + } + LateParsedAttrs.clear(); + + // Handle the initializer. + if (HasDeferredInitializer) { + // The initializer was deferred; parse it and cache the tokens. + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_nonstatic_member_init : + diag::ext_nonstatic_member_init); + + if (DeclaratorInfo.isArrayOfUnknownBound()) { + // C++0x [dcl.array]p3: An array bound may also be omitted when the + // declarator is followed by an initializer. + // + // A brace-or-equal-initializer for a member-declarator is not an + // initializer in the grammar, so this is ill-formed. + Diag(Tok, diag::err_incomplete_array_member_init); + SkipUntil(tok::comma, true, true); + if (ThisDecl) + // Avoid later warnings about a class member of incomplete type. + ThisDecl->setInvalidDecl(); + } else + ParseCXXNonStaticMemberInitializer(ThisDecl); + } else if (HasInitializer) { + // Normal initializer. + if (!Init.isUsable()) + Init = ParseCXXMemberInitializer(ThisDecl, + DeclaratorInfo.isDeclarationOfFunction(), EqualLoc); + + if (Init.isInvalid()) + SkipUntil(tok::comma, true, true); + else if (ThisDecl) + Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid(), + DS.getTypeSpecType() == DeclSpec::TST_auto); + } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) { + // No initializer. + Actions.ActOnUninitializedDecl(ThisDecl, + DS.getTypeSpecType() == DeclSpec::TST_auto); + } + + if (ThisDecl) { + Actions.FinalizeDeclaration(ThisDecl); + DeclsInGroup.push_back(ThisDecl); + } + + if (ThisDecl && DeclaratorInfo.isFunctionDeclarator() && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_typedef) { + HandleMemberFunctionDeclDelays(DeclaratorInfo, ThisDecl); + } + + DeclaratorInfo.complete(ThisDecl); + + // If we don't have a comma, it is either the end of the list (a ';') + // or an error, bail out. + if (Tok.isNot(tok::comma)) + break; + + // Consume the comma. + SourceLocation CommaLoc = ConsumeToken(); + + if (Tok.isAtStartOfLine() && + !MightBeDeclarator(Declarator::MemberContext)) { + // This comma was followed by a line-break and something which can't be + // the start of a declarator. The comma was probably a typo for a + // semicolon. + Diag(CommaLoc, diag::err_expected_semi_declaration) + << FixItHint::CreateReplacement(CommaLoc, ";"); + ExpectSemi = false; + break; + } + + // Parse the next declarator. + DeclaratorInfo.clear(); + VS.clear(); + BitfieldSize = true; + Init = true; + HasInitializer = false; + DeclaratorInfo.setCommaLoc(CommaLoc); + + // Attributes are only allowed on the second declarator. + MaybeParseGNUAttributes(DeclaratorInfo); + + if (Tok.isNot(tok::colon)) + ParseDeclarator(DeclaratorInfo); + } + + if (ExpectSemi && + ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) { + // Skip to end of block or statement. + SkipUntil(tok::r_brace, true, true); + // If we stopped at a ';', eat it. + if (Tok.is(tok::semi)) ConsumeToken(); + return; + } + + Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup.data(), + DeclsInGroup.size()); +} + +/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or +/// pure-specifier. Also detect and reject any attempted defaulted/deleted +/// function definition. The location of the '=', if any, will be placed in +/// EqualLoc. +/// +/// pure-specifier: +/// '= 0' +/// +/// brace-or-equal-initializer: +/// '=' initializer-expression +/// braced-init-list +/// +/// initializer-clause: +/// assignment-expression +/// braced-init-list +/// +/// defaulted/deleted function-definition: +/// '=' 'default' +/// '=' 'delete' +/// +/// Prior to C++0x, the assignment-expression in an initializer-clause must +/// be a constant-expression. +ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, + SourceLocation &EqualLoc) { + assert((Tok.is(tok::equal) || Tok.is(tok::l_brace)) + && "Data member initializer not starting with '=' or '{'"); + + EnterExpressionEvaluationContext Context(Actions, + Sema::PotentiallyEvaluated, + D); + if (Tok.is(tok::equal)) { + EqualLoc = ConsumeToken(); + if (Tok.is(tok::kw_delete)) { + // In principle, an initializer of '= delete p;' is legal, but it will + // never type-check. It's better to diagnose it as an ill-formed expression + // than as an ill-formed deleted non-function member. + // An initializer of '= delete p, foo' will never be parsed, because + // a top-level comma always ends the initializer expression. + const Token &Next = NextToken(); + if (IsFunction || Next.is(tok::semi) || Next.is(tok::comma) || + Next.is(tok::eof)) { + if (IsFunction) + Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) + << 1 /* delete */; + else + Diag(ConsumeToken(), diag::err_deleted_non_function); + return ExprResult(); + } + } else if (Tok.is(tok::kw_default)) { + if (IsFunction) + Diag(Tok, diag::err_default_delete_in_multiple_declaration) + << 0 /* default */; + else + Diag(ConsumeToken(), diag::err_default_special_members); + return ExprResult(); + } + + } + return ParseInitializer(); +} + +/// ParseCXXMemberSpecification - Parse the class definition. +/// +/// member-specification: +/// member-declaration member-specification[opt] +/// access-specifier ':' member-specification[opt] +/// +void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, + unsigned TagType, Decl *TagDecl) { + assert((TagType == DeclSpec::TST_struct || + TagType == DeclSpec::TST_union || + TagType == DeclSpec::TST_class) && "Invalid TagType!"); + + PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc, + "parsing struct/union/class body"); + + // Determine whether this is a non-nested class. Note that local + // classes are *not* considered to be nested classes. + bool NonNestedClass = true; + if (!ClassStack.empty()) { + for (const Scope *S = getCurScope(); S; S = S->getParent()) { + if (S->isClassScope()) { + // We're inside a class scope, so this is a nested class. + NonNestedClass = false; + break; + } + + if ((S->getFlags() & Scope::FnScope)) { + // If we're in a function or function template declared in the + // body of a class, then this is a local class rather than a + // nested class. + const Scope *Parent = S->getParent(); + if (Parent->isTemplateParamScope()) + Parent = Parent->getParent(); + if (Parent->isClassScope()) + break; + } + } + } + + // Enter a scope for the class. + ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope); + + // Note that we are parsing a new (potentially-nested) class definition. + ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass); + + if (TagDecl) + Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); + + SourceLocation FinalLoc; + + // Parse the optional 'final' keyword. + if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) { + assert(isCXX0XFinalKeyword() && "not a class definition"); + FinalLoc = ConsumeToken(); + + Diag(FinalLoc, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_override_control_keyword : + diag::ext_override_control_keyword) << "final"; + } + + if (Tok.is(tok::colon)) { + ParseBaseClause(TagDecl); + + if (!Tok.is(tok::l_brace)) { + Diag(Tok, diag::err_expected_lbrace_after_base_specifiers); + + if (TagDecl) + Actions.ActOnTagDefinitionError(getCurScope(), TagDecl); + return; + } + } + + assert(Tok.is(tok::l_brace)); + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); + + if (TagDecl) + Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc, + T.getOpenLocation()); + + // C++ 11p3: Members of a class defined with the keyword class are private + // by default. Members of a class defined with the keywords struct or union + // are public by default. + AccessSpecifier CurAS; + if (TagType == DeclSpec::TST_class) + CurAS = AS_private; + else + CurAS = AS_public; + ParsedAttributes AccessAttrs(AttrFactory); + + if (TagDecl) { + // While we still have something to read, read the member-declarations. + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + // Each iteration of this loop reads one member-declaration. + + if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) || + Tok.is(tok::kw___if_not_exists))) { + ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); + continue; + } + + // Check for extraneous top-level semicolon. + if (Tok.is(tok::semi)) { + Diag(Tok, diag::ext_extra_struct_semi) + << DeclSpec::getSpecifierName((DeclSpec::TST)TagType) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeToken(); + continue; + } + + if (Tok.is(tok::annot_pragma_vis)) { + HandlePragmaVisibility(); + continue; + } + + if (Tok.is(tok::annot_pragma_pack)) { + HandlePragmaPack(); + continue; + } + + AccessSpecifier AS = getAccessSpecifierIfPresent(); + if (AS != AS_none) { + // Current token is a C++ access specifier. + CurAS = AS; + SourceLocation ASLoc = Tok.getLocation(); + unsigned TokLength = Tok.getLength(); + ConsumeToken(); + AccessAttrs.clear(); + MaybeParseGNUAttributes(AccessAttrs); + + SourceLocation EndLoc; + if (Tok.is(tok::colon)) { + EndLoc = Tok.getLocation(); + ConsumeToken(); + } else if (Tok.is(tok::semi)) { + EndLoc = Tok.getLocation(); + ConsumeToken(); + Diag(EndLoc, diag::err_expected_colon) + << FixItHint::CreateReplacement(EndLoc, ":"); + } else { + EndLoc = ASLoc.getLocWithOffset(TokLength); + Diag(EndLoc, diag::err_expected_colon) + << FixItHint::CreateInsertion(EndLoc, ":"); + } + + if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc, + AccessAttrs.getList())) { + // found another attribute than only annotations + AccessAttrs.clear(); + } + + continue; + } + + // FIXME: Make sure we don't have a template here. + + // Parse all the comma separated declarators. + ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList()); + } + + T.consumeClose(); + } else { + SkipUntil(tok::r_brace, false, false); + } + + // If attributes exist after class contents, parse them. + ParsedAttributes attrs(AttrFactory); + MaybeParseGNUAttributes(attrs); + + if (TagDecl) + Actions.ActOnFinishCXXMemberSpecification(getCurScope(), RecordLoc, TagDecl, + T.getOpenLocation(), + T.getCloseLocation(), + attrs.getList()); + + // C++11 [class.mem]p2: + // Within the class member-specification, the class is regarded as complete + // within function bodies, default arguments, and + // brace-or-equal-initializers for non-static data members (including such + // things in nested classes). + if (TagDecl && NonNestedClass) { + // We are not inside a nested class. This class and its nested classes + // are complete and we can parse the delayed portions of method + // declarations and the lexed inline method definitions, along with any + // delayed attributes. + SourceLocation SavedPrevTokLocation = PrevTokLocation; + ParseLexedAttributes(getCurrentClass()); + ParseLexedMethodDeclarations(getCurrentClass()); + + // We've finished with all pending member declarations. + Actions.ActOnFinishCXXMemberDecls(); + + ParseLexedMemberInitializers(getCurrentClass()); + ParseLexedMethodDefs(getCurrentClass()); + PrevTokLocation = SavedPrevTokLocation; + } + + if (TagDecl) + Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, + T.getCloseLocation()); + + // Leave the class scope. + ParsingDef.Pop(); + ClassScope.Exit(); +} + +/// ParseConstructorInitializer - Parse a C++ constructor initializer, +/// which explicitly initializes the members or base classes of a +/// class (C++ [class.base.init]). For example, the three initializers +/// after the ':' in the Derived constructor below: +/// +/// @code +/// class Base { }; +/// class Derived : Base { +/// int x; +/// float f; +/// public: +/// Derived(float f) : Base(), x(17), f(f) { } +/// }; +/// @endcode +/// +/// [C++] ctor-initializer: +/// ':' mem-initializer-list +/// +/// [C++] mem-initializer-list: +/// mem-initializer ...[opt] +/// mem-initializer ...[opt] , mem-initializer-list +void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { + assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'"); + + // Poison the SEH identifiers so they are flagged as illegal in constructor initializers + PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true); + SourceLocation ColonLoc = ConsumeToken(); + + SmallVector MemInitializers; + bool AnyErrors = false; + + do { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteConstructorInitializer(ConstructorDecl, + MemInitializers.data(), + MemInitializers.size()); + return cutOffParsing(); + } else { + MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); + if (!MemInit.isInvalid()) + MemInitializers.push_back(MemInit.get()); + else + AnyErrors = true; + } + + if (Tok.is(tok::comma)) + ConsumeToken(); + else if (Tok.is(tok::l_brace)) + break; + // If the next token looks like a base or member initializer, assume that + // we're just missing a comma. + else if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) { + SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation); + Diag(Loc, diag::err_ctor_init_missing_comma) + << FixItHint::CreateInsertion(Loc, ", "); + } else { + // Skip over garbage, until we get to '{'. Don't eat the '{'. + Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma); + SkipUntil(tok::l_brace, true, true); + break; + } + } while (true); + + Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, + MemInitializers.data(), MemInitializers.size(), + AnyErrors); +} + +/// ParseMemInitializer - Parse a C++ member initializer, which is +/// part of a constructor initializer that explicitly initializes one +/// member or base class (C++ [class.base.init]). See +/// ParseConstructorInitializer for an example. +/// +/// [C++] mem-initializer: +/// mem-initializer-id '(' expression-list[opt] ')' +/// [C++0x] mem-initializer-id braced-init-list +/// +/// [C++] mem-initializer-id: +/// '::'[opt] nested-name-specifier[opt] class-name +/// identifier +Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { + // parse '::'[opt] nested-name-specifier[opt] + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + ParsedType TemplateTypeTy; + if (Tok.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (TemplateId->Kind == TNK_Type_template || + TemplateId->Kind == TNK_Dependent_template_name) { + AnnotateTemplateIdTokenAsType(); + assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); + TemplateTypeTy = getTypeAnnotation(Tok); + } + } + // Uses of decltype will already have been converted to annot_decltype by + // ParseOptionalCXXScopeSpecifier at this point. + if (!TemplateTypeTy && Tok.isNot(tok::identifier) + && Tok.isNot(tok::annot_decltype)) { + Diag(Tok, diag::err_expected_member_or_base_name); + return true; + } + + IdentifierInfo *II = 0; + DeclSpec DS(AttrFactory); + SourceLocation IdLoc = Tok.getLocation(); + if (Tok.is(tok::annot_decltype)) { + // Get the decltype expression, if there is one. + ParseDecltypeSpecifier(DS); + } else { + if (Tok.is(tok::identifier)) + // Get the identifier. This may be a member name or a class name, + // but we'll let the semantic analysis determine which it is. + II = Tok.getIdentifierInfo(); + ConsumeToken(); + } + + + // Parse the '('. + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + + ExprResult InitList = ParseBraceInitializer(); + if (InitList.isInvalid()) + return true; + + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + + return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, + TemplateTypeTy, DS, IdLoc, + InitList.take(), EllipsisLoc); + } else if(Tok.is(tok::l_paren)) { + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + // Parse the optional expression-list. + ExprVector ArgExprs(Actions); + CommaLocsTy CommaLocs; + if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) { + SkipUntil(tok::r_paren); + return true; + } + + T.consumeClose(); + + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + + return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, + TemplateTypeTy, DS, IdLoc, + T.getOpenLocation(), ArgExprs.take(), + ArgExprs.size(), T.getCloseLocation(), + EllipsisLoc); + } + + Diag(Tok, getLangOpts().CPlusPlus0x ? diag::err_expected_lparen_or_lbrace + : diag::err_expected_lparen); + return true; +} + +/// \brief Parse a C++ exception-specification if present (C++0x [except.spec]). +/// +/// exception-specification: +/// dynamic-exception-specification +/// noexcept-specification +/// +/// noexcept-specification: +/// 'noexcept' +/// 'noexcept' '(' constant-expression ')' +ExceptionSpecificationType +Parser::tryParseExceptionSpecification( + SourceRange &SpecificationRange, + SmallVectorImpl &DynamicExceptions, + SmallVectorImpl &DynamicExceptionRanges, + ExprResult &NoexceptExpr) { + ExceptionSpecificationType Result = EST_None; + + // See if there's a dynamic specification. + if (Tok.is(tok::kw_throw)) { + Result = ParseDynamicExceptionSpecification(SpecificationRange, + DynamicExceptions, + DynamicExceptionRanges); + assert(DynamicExceptions.size() == DynamicExceptionRanges.size() && + "Produced different number of exception types and ranges."); + } + + // If there's no noexcept specification, we're done. + if (Tok.isNot(tok::kw_noexcept)) + return Result; + + Diag(Tok, diag::warn_cxx98_compat_noexcept_decl); + + // If we already had a dynamic specification, parse the noexcept for, + // recovery, but emit a diagnostic and don't store the results. + SourceRange NoexceptRange; + ExceptionSpecificationType NoexceptType = EST_None; + + SourceLocation KeywordLoc = ConsumeToken(); + if (Tok.is(tok::l_paren)) { + // There is an argument. + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + NoexceptType = EST_ComputedNoexcept; + NoexceptExpr = ParseConstantExpression(); + // The argument must be contextually convertible to bool. We use + // ActOnBooleanCondition for this purpose. + if (!NoexceptExpr.isInvalid()) + NoexceptExpr = Actions.ActOnBooleanCondition(getCurScope(), KeywordLoc, + NoexceptExpr.get()); + T.consumeClose(); + NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation()); + } else { + // There is no argument. + NoexceptType = EST_BasicNoexcept; + NoexceptRange = SourceRange(KeywordLoc, KeywordLoc); + } + + if (Result == EST_None) { + SpecificationRange = NoexceptRange; + Result = NoexceptType; + + // If there's a dynamic specification after a noexcept specification, + // parse that and ignore the results. + if (Tok.is(tok::kw_throw)) { + Diag(Tok.getLocation(), diag::err_dynamic_and_noexcept_specification); + ParseDynamicExceptionSpecification(NoexceptRange, DynamicExceptions, + DynamicExceptionRanges); + } + } else { + Diag(Tok.getLocation(), diag::err_dynamic_and_noexcept_specification); + } + + return Result; +} + +/// ParseDynamicExceptionSpecification - Parse a C++ +/// dynamic-exception-specification (C++ [except.spec]). +/// +/// dynamic-exception-specification: +/// 'throw' '(' type-id-list [opt] ')' +/// [MS] 'throw' '(' '...' ')' +/// +/// type-id-list: +/// type-id ... [opt] +/// type-id-list ',' type-id ... [opt] +/// +ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( + SourceRange &SpecificationRange, + SmallVectorImpl &Exceptions, + SmallVectorImpl &Ranges) { + assert(Tok.is(tok::kw_throw) && "expected throw"); + + SpecificationRange.setBegin(ConsumeToken()); + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { + Diag(Tok, diag::err_expected_lparen_after) << "throw"; + SpecificationRange.setEnd(SpecificationRange.getBegin()); + return EST_DynamicNone; + } + + // Parse throw(...), a Microsoft extension that means "this function + // can throw anything". + if (Tok.is(tok::ellipsis)) { + SourceLocation EllipsisLoc = ConsumeToken(); + if (!getLangOpts().MicrosoftExt) + Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec); + T.consumeClose(); + SpecificationRange.setEnd(T.getCloseLocation()); + return EST_MSAny; + } + + // Parse the sequence of type-ids. + SourceRange Range; + while (Tok.isNot(tok::r_paren)) { + TypeResult Res(ParseTypeName(&Range)); + + if (Tok.is(tok::ellipsis)) { + // C++0x [temp.variadic]p5: + // - In a dynamic-exception-specification (15.4); the pattern is a + // type-id. + SourceLocation Ellipsis = ConsumeToken(); + Range.setEnd(Ellipsis); + if (!Res.isInvalid()) + Res = Actions.ActOnPackExpansion(Res.get(), Ellipsis); + } + + if (!Res.isInvalid()) { + Exceptions.push_back(Res.get()); + Ranges.push_back(Range); + } + + if (Tok.is(tok::comma)) + ConsumeToken(); + else + break; + } + + T.consumeClose(); + SpecificationRange.setEnd(T.getCloseLocation()); + return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic; +} + +/// ParseTrailingReturnType - Parse a trailing return type on a new-style +/// function declaration. +TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) { + assert(Tok.is(tok::arrow) && "expected arrow"); + + ConsumeToken(); + + return ParseTypeName(&Range, Declarator::TrailingReturnContext); +} + +/// \brief We have just started parsing the definition of a new class, +/// so push that class onto our stack of classes that is currently +/// being parsed. +Sema::ParsingClassState +Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass) { + assert((NonNestedClass || !ClassStack.empty()) && + "Nested class without outer class"); + ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass)); + return Actions.PushParsingClass(); +} + +/// \brief Deallocate the given parsed class and all of its nested +/// classes. +void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) { + for (unsigned I = 0, N = Class->LateParsedDeclarations.size(); I != N; ++I) + delete Class->LateParsedDeclarations[I]; + delete Class; +} + +/// \brief Pop the top class of the stack of classes that are +/// currently being parsed. +/// +/// This routine should be called when we have finished parsing the +/// definition of a class, but have not yet popped the Scope +/// associated with the class's definition. +/// +/// \returns true if the class we've popped is a top-level class, +/// false otherwise. +void Parser::PopParsingClass(Sema::ParsingClassState state) { + assert(!ClassStack.empty() && "Mismatched push/pop for class parsing"); + + Actions.PopParsingClass(state); + + ParsingClass *Victim = ClassStack.top(); + ClassStack.pop(); + if (Victim->TopLevelClass) { + // Deallocate all of the nested classes of this class, + // recursively: we don't need to keep any of this information. + DeallocateParsedClasses(Victim); + return; + } + assert(!ClassStack.empty() && "Missing top-level class?"); + + if (Victim->LateParsedDeclarations.empty()) { + // The victim is a nested class, but we will not need to perform + // any processing after the definition of this class since it has + // no members whose handling was delayed. Therefore, we can just + // remove this nested class. + DeallocateParsedClasses(Victim); + return; + } + + // This nested class has some members that will need to be processed + // after the top-level class is completely defined. Therefore, add + // it to the list of nested classes within its parent. + assert(getCurScope()->isClassScope() && "Nested class outside of class scope?"); + ClassStack.top()->LateParsedDeclarations.push_back(new LateParsedClass(this, Victim)); + Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope(); +} + +/// \brief Try to parse an 'identifier' which appears within an attribute-token. +/// +/// \return the parsed identifier on success, and 0 if the next token is not an +/// attribute-token. +/// +/// C++11 [dcl.attr.grammar]p3: +/// If a keyword or an alternative token that satisfies the syntactic +/// requirements of an identifier is contained in an attribute-token, +/// it is considered an identifier. +IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { + switch (Tok.getKind()) { + default: + // Identifiers and keywords have identifier info attached. + if (IdentifierInfo *II = Tok.getIdentifierInfo()) { + Loc = ConsumeToken(); + return II; + } + return 0; + + case tok::ampamp: // 'and' + case tok::pipe: // 'bitor' + case tok::pipepipe: // 'or' + case tok::caret: // 'xor' + case tok::tilde: // 'compl' + case tok::amp: // 'bitand' + case tok::ampequal: // 'and_eq' + case tok::pipeequal: // 'or_eq' + case tok::caretequal: // 'xor_eq' + case tok::exclaim: // 'not' + case tok::exclaimequal: // 'not_eq' + // Alternative tokens do not have identifier info, but their spelling + // starts with an alphabetical character. + llvm::SmallString<8> SpellingBuf; + StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf); + if (std::isalpha(Spelling[0])) { + Loc = ConsumeToken(); + return &PP.getIdentifierTable().get(Spelling.data()); + } + return 0; + } +} + +/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier. Currently +/// only parses standard attributes. +/// +/// [C++11] attribute-specifier: +/// '[' '[' attribute-list ']' ']' +/// alignment-specifier +/// +/// [C++11] attribute-list: +/// attribute[opt] +/// attribute-list ',' attribute[opt] +/// attribute '...' +/// attribute-list ',' attribute '...' +/// +/// [C++11] attribute: +/// attribute-token attribute-argument-clause[opt] +/// +/// [C++11] attribute-token: +/// identifier +/// attribute-scoped-token +/// +/// [C++11] attribute-scoped-token: +/// attribute-namespace '::' identifier +/// +/// [C++11] attribute-namespace: +/// identifier +/// +/// [C++11] attribute-argument-clause: +/// '(' balanced-token-seq ')' +/// +/// [C++11] balanced-token-seq: +/// balanced-token +/// balanced-token-seq balanced-token +/// +/// [C++11] balanced-token: +/// '(' balanced-token-seq ')' +/// '[' balanced-token-seq ']' +/// '{' balanced-token-seq '}' +/// any token but '(', ')', '[', ']', '{', or '}' +void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, + SourceLocation *endLoc) { + if (Tok.is(tok::kw_alignas)) { + Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas); + ParseAlignmentSpecifier(attrs, endLoc); + return; + } + + assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) + && "Not a C++11 attribute list"); + + Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute); + + ConsumeBracket(); + ConsumeBracket(); + + while (Tok.isNot(tok::r_square)) { + // attribute not present + if (Tok.is(tok::comma)) { + ConsumeToken(); + continue; + } + + SourceLocation ScopeLoc, AttrLoc; + IdentifierInfo *ScopeName = 0, *AttrName = 0; + + AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); + if (!AttrName) + // Break out to the "expected ']'" diagnostic. + break; + + // scoped attribute + if (Tok.is(tok::coloncolon)) { + ConsumeToken(); + + ScopeName = AttrName; + ScopeLoc = AttrLoc; + + AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); + if (!AttrName) { + Diag(Tok.getLocation(), diag::err_expected_ident); + SkipUntil(tok::r_square, tok::comma, true, true); + continue; + } + } + + bool AttrParsed = false; + // No scoped names are supported; ideally we could put all non-standard + // attributes into namespaces. + if (!ScopeName) { + switch (AttributeList::getKind(AttrName)) { + // No arguments + case AttributeList::AT_carries_dependency: + case AttributeList::AT_noreturn: { + if (Tok.is(tok::l_paren)) { + Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments) + << AttrName->getName(); + break; + } + + attrs.addNew(AttrName, AttrLoc, 0, AttrLoc, 0, + SourceLocation(), 0, 0, false, true); + AttrParsed = true; + break; + } + + // Silence warnings + default: break; + } + } + + // Skip the entire parameter clause, if any + if (!AttrParsed && Tok.is(tok::l_paren)) { + ConsumeParen(); + // SkipUntil maintains the balancedness of tokens. + SkipUntil(tok::r_paren, false); + } + + if (Tok.is(tok::ellipsis)) { + if (AttrParsed) + Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis) + << AttrName->getName(); + ConsumeToken(); + } + } + + if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) + SkipUntil(tok::r_square, false); + if (endLoc) + *endLoc = Tok.getLocation(); + if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) + SkipUntil(tok::r_square, false); +} + +/// ParseCXX11Attributes - Parse a C++0x attribute-specifier-seq. +/// +/// attribute-specifier-seq: +/// attribute-specifier-seq[opt] attribute-specifier +void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs, + SourceLocation *endLoc) { + SourceLocation StartLoc = Tok.getLocation(), Loc; + if (!endLoc) + endLoc = &Loc; + + do { + ParseCXX11AttributeSpecifier(attrs, endLoc); + } while (isCXX11AttributeSpecifier()); + + attrs.Range = SourceRange(StartLoc, *endLoc); +} + +/// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr] +/// +/// [MS] ms-attribute: +/// '[' token-seq ']' +/// +/// [MS] ms-attribute-seq: +/// ms-attribute[opt] +/// ms-attribute ms-attribute-seq +void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc) { + assert(Tok.is(tok::l_square) && "Not a Microsoft attribute list"); + + while (Tok.is(tok::l_square)) { + // FIXME: If this is actually a C++11 attribute, parse it as one. + ConsumeBracket(); + SkipUntil(tok::r_square, true, true); + if (endLoc) *endLoc = Tok.getLocation(); + ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); + } +} + +void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, + AccessSpecifier& CurAS) { + IfExistsCondition Result; + if (ParseMicrosoftIfExistsCondition(Result)) + return; + + BalancedDelimiterTracker Braces(*this, tok::l_brace); + if (Braces.consumeOpen()) { + Diag(Tok, diag::err_expected_lbrace); + return; + } + + switch (Result.Behavior) { + case IEB_Parse: + // Parse the declarations below. + break; + + case IEB_Dependent: + Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists) + << Result.IsIfExists; + // Fall through to skip. + + case IEB_Skip: + Braces.skipToEnd(); + return; + } + + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + // __if_exists, __if_not_exists can nest. + if ((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { + ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); + continue; + } + + // Check for extraneous top-level semicolon. + if (Tok.is(tok::semi)) { + Diag(Tok, diag::ext_extra_struct_semi) + << DeclSpec::getSpecifierName((DeclSpec::TST)TagType) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeToken(); + continue; + } + + AccessSpecifier AS = getAccessSpecifierIfPresent(); + if (AS != AS_none) { + // Current token is a C++ access specifier. + CurAS = AS; + SourceLocation ASLoc = Tok.getLocation(); + ConsumeToken(); + if (Tok.is(tok::colon)) + Actions.ActOnAccessSpecifier(AS, ASLoc, Tok.getLocation()); + else + Diag(Tok, diag::err_expected_colon); + ConsumeToken(); + continue; + } + + // Parse all the comma separated declarators. + ParseCXXClassMemberDeclaration(CurAS, 0); + } + + Braces.consumeClose(); +} diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp new file mode 100644 index 0000000..6d31396 --- /dev/null +++ b/clang/lib/Parse/ParseExpr.cpp @@ -0,0 +1,2431 @@ +//===--- ParseExpr.cpp - Expression Parsing -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Expression parsing implementation. Expressions in +// C99 basically consist of a bunch of binary operators with unary operators and +// other random stuff at the leaves. +// +// In the C99 grammar, these unary operators bind tightest and are represented +// as the 'cast-expression' production. Everything else is either a binary +// operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are +// handled by ParseCastExpression, the higher level pieces are handled by +// ParseBinaryExpression. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/TypoCorrection.h" +#include "clang/Basic/PrettyStackTrace.h" +#include "RAIIObjectsForParser.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SmallString.h" +using namespace clang; + +/// getBinOpPrecedence - Return the precedence of the specified binary operator +/// token. +static prec::Level getBinOpPrecedence(tok::TokenKind Kind, + bool GreaterThanIsOperator, + bool CPlusPlus0x) { + switch (Kind) { + case tok::greater: + // C++ [temp.names]p3: + // [...] When parsing a template-argument-list, the first + // non-nested > is taken as the ending delimiter rather than a + // greater-than operator. [...] + if (GreaterThanIsOperator) + return prec::Relational; + return prec::Unknown; + + case tok::greatergreater: + // C++0x [temp.names]p3: + // + // [...] Similarly, the first non-nested >> is treated as two + // consecutive but distinct > tokens, the first of which is + // taken as the end of the template-argument-list and completes + // the template-id. [...] + if (GreaterThanIsOperator || !CPlusPlus0x) + return prec::Shift; + return prec::Unknown; + + default: return prec::Unknown; + case tok::comma: return prec::Comma; + case tok::equal: + case tok::starequal: + case tok::slashequal: + case tok::percentequal: + case tok::plusequal: + case tok::minusequal: + case tok::lesslessequal: + case tok::greatergreaterequal: + case tok::ampequal: + case tok::caretequal: + case tok::pipeequal: return prec::Assignment; + case tok::question: return prec::Conditional; + case tok::pipepipe: return prec::LogicalOr; + case tok::ampamp: return prec::LogicalAnd; + case tok::pipe: return prec::InclusiveOr; + case tok::caret: return prec::ExclusiveOr; + case tok::amp: return prec::And; + case tok::exclaimequal: + case tok::equalequal: return prec::Equality; + case tok::lessequal: + case tok::less: + case tok::greaterequal: return prec::Relational; + case tok::lessless: return prec::Shift; + case tok::plus: + case tok::minus: return prec::Additive; + case tok::percent: + case tok::slash: + case tok::star: return prec::Multiplicative; + case tok::periodstar: + case tok::arrowstar: return prec::PointerToMember; + } +} + + +/// ParseExpression - Simple precedence-based parser for binary/ternary +/// operators. +/// +/// Note: we diverge from the C99 grammar when parsing the assignment-expression +/// production. C99 specifies that the LHS of an assignment operator should be +/// parsed as a unary-expression, but consistency dictates that it be a +/// conditional-expession. In practice, the important thing here is that the +/// LHS of an assignment has to be an l-value, which productions between +/// unary-expression and conditional-expression don't produce. Because we want +/// consistency, we parse the LHS as a conditional-expression, then check for +/// l-value-ness in semantic analysis stages. +/// +/// pm-expression: [C++ 5.5] +/// cast-expression +/// pm-expression '.*' cast-expression +/// pm-expression '->*' cast-expression +/// +/// multiplicative-expression: [C99 6.5.5] +/// Note: in C++, apply pm-expression instead of cast-expression +/// cast-expression +/// multiplicative-expression '*' cast-expression +/// multiplicative-expression '/' cast-expression +/// multiplicative-expression '%' cast-expression +/// +/// additive-expression: [C99 6.5.6] +/// multiplicative-expression +/// additive-expression '+' multiplicative-expression +/// additive-expression '-' multiplicative-expression +/// +/// shift-expression: [C99 6.5.7] +/// additive-expression +/// shift-expression '<<' additive-expression +/// shift-expression '>>' additive-expression +/// +/// relational-expression: [C99 6.5.8] +/// shift-expression +/// relational-expression '<' shift-expression +/// relational-expression '>' shift-expression +/// relational-expression '<=' shift-expression +/// relational-expression '>=' shift-expression +/// +/// equality-expression: [C99 6.5.9] +/// relational-expression +/// equality-expression '==' relational-expression +/// equality-expression '!=' relational-expression +/// +/// AND-expression: [C99 6.5.10] +/// equality-expression +/// AND-expression '&' equality-expression +/// +/// exclusive-OR-expression: [C99 6.5.11] +/// AND-expression +/// exclusive-OR-expression '^' AND-expression +/// +/// inclusive-OR-expression: [C99 6.5.12] +/// exclusive-OR-expression +/// inclusive-OR-expression '|' exclusive-OR-expression +/// +/// logical-AND-expression: [C99 6.5.13] +/// inclusive-OR-expression +/// logical-AND-expression '&&' inclusive-OR-expression +/// +/// logical-OR-expression: [C99 6.5.14] +/// logical-AND-expression +/// logical-OR-expression '||' logical-AND-expression +/// +/// conditional-expression: [C99 6.5.15] +/// logical-OR-expression +/// logical-OR-expression '?' expression ':' conditional-expression +/// [GNU] logical-OR-expression '?' ':' conditional-expression +/// [C++] the third operand is an assignment-expression +/// +/// assignment-expression: [C99 6.5.16] +/// conditional-expression +/// unary-expression assignment-operator assignment-expression +/// [C++] throw-expression [C++ 15] +/// +/// assignment-operator: one of +/// = *= /= %= += -= <<= >>= &= ^= |= +/// +/// expression: [C99 6.5.17] +/// assignment-expression ...[opt] +/// expression ',' assignment-expression ...[opt] +ExprResult Parser::ParseExpression(TypeCastState isTypeCast) { + ExprResult LHS(ParseAssignmentExpression(isTypeCast)); + return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); +} + +/// This routine is called when the '@' is seen and consumed. +/// Current token is an Identifier and is not a 'try'. This +/// routine is necessary to disambiguate @try-statement from, +/// for example, @encode-expression. +/// +ExprResult +Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { + ExprResult LHS(ParseObjCAtExpression(AtLoc)); + return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); +} + +/// This routine is called when a leading '__extension__' is seen and +/// consumed. This is necessary because the token gets consumed in the +/// process of disambiguating between an expression and a declaration. +ExprResult +Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { + ExprResult LHS(true); + { + // Silence extension warnings in the sub-expression + ExtensionRAIIObject O(Diags); + + LHS = ParseCastExpression(false); + } + + if (!LHS.isInvalid()) + LHS = Actions.ActOnUnaryOp(getCurScope(), ExtLoc, tok::kw___extension__, + LHS.take()); + + return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); +} + +/// ParseAssignmentExpression - Parse an expr that doesn't include commas. +ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); + cutOffParsing(); + return ExprError(); + } + + if (Tok.is(tok::kw_throw)) + return ParseThrowExpression(); + + ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false, + /*isAddressOfOperand=*/false, + isTypeCast); + return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment); +} + +/// ParseAssignmentExprWithObjCMessageExprStart - Parse an assignment expression +/// where part of an objc message send has already been parsed. In this case +/// LBracLoc indicates the location of the '[' of the message send, and either +/// ReceiverName or ReceiverExpr is non-null indicating the receiver of the +/// message. +/// +/// Since this handles full assignment-expression's, it handles postfix +/// expressions and other binary operators for these expressions as well. +ExprResult +Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, + SourceLocation SuperLoc, + ParsedType ReceiverType, + Expr *ReceiverExpr) { + ExprResult R + = ParseObjCMessageExpressionBody(LBracLoc, SuperLoc, + ReceiverType, ReceiverExpr); + R = ParsePostfixExpressionSuffix(R); + return ParseRHSOfBinaryExpression(R, prec::Assignment); +} + + +ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { + // C++03 [basic.def.odr]p2: + // An expression is potentially evaluated unless it appears where an + // integral constant expression is required (see 5.19) [...]. + // C++98 and C++11 have no such rule, but this is only a defect in C++98. + EnterExpressionEvaluationContext Unevaluated(Actions, + Sema::ConstantEvaluated); + + ExprResult LHS(ParseCastExpression(false, false, isTypeCast)); + ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + return Actions.ActOnConstantExpression(Res); +} + +/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with +/// LHS and has a precedence of at least MinPrec. +ExprResult +Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { + prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(), + GreaterThanIsOperator, + getLangOpts().CPlusPlus0x); + SourceLocation ColonLoc; + + while (1) { + // If this token has a lower precedence than we are allowed to parse (e.g. + // because we are called recursively, or because the token is not a binop), + // then we are done! + if (NextTokPrec < MinPrec) + return move(LHS); + + // Consume the operator, saving the operator token for error reporting. + Token OpToken = Tok; + ConsumeToken(); + + // Special case handling for the ternary operator. + ExprResult TernaryMiddle(true); + if (NextTokPrec == prec::Conditional) { + if (Tok.isNot(tok::colon)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); + + // Handle this production specially: + // logical-OR-expression '?' expression ':' conditional-expression + // In particular, the RHS of the '?' is 'expression', not + // 'logical-OR-expression' as we might expect. + TernaryMiddle = ParseExpression(); + if (TernaryMiddle.isInvalid()) { + LHS = ExprError(); + TernaryMiddle = 0; + } + } else { + // Special case handling of "X ? Y : Z" where Y is empty: + // logical-OR-expression '?' ':' conditional-expression [GNU] + TernaryMiddle = 0; + Diag(Tok, diag::ext_gnu_conditional_expr); + } + + if (Tok.is(tok::colon)) { + // Eat the colon. + ColonLoc = ConsumeToken(); + } else { + // Otherwise, we're missing a ':'. Assume that this was a typo that + // the user forgot. If we're not in a macro expansion, we can suggest + // a fixit hint. If there were two spaces before the current token, + // suggest inserting the colon in between them, otherwise insert ": ". + SourceLocation FILoc = Tok.getLocation(); + const char *FIText = ": "; + const SourceManager &SM = PP.getSourceManager(); + if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc, &FILoc)) { + assert(FILoc.isFileID()); + bool IsInvalid = false; + const char *SourcePtr = + SM.getCharacterData(FILoc.getLocWithOffset(-1), &IsInvalid); + if (!IsInvalid && *SourcePtr == ' ') { + SourcePtr = + SM.getCharacterData(FILoc.getLocWithOffset(-2), &IsInvalid); + if (!IsInvalid && *SourcePtr == ' ') { + FILoc = FILoc.getLocWithOffset(-1); + FIText = ":"; + } + } + } + + Diag(Tok, diag::err_expected_colon) + << FixItHint::CreateInsertion(FILoc, FIText); + Diag(OpToken, diag::note_matching) << "?"; + ColonLoc = Tok.getLocation(); + } + } + + // Code completion for the right-hand side of an assignment expression + // goes through a special hook that takes the left-hand side into account. + if (Tok.is(tok::code_completion) && NextTokPrec == prec::Assignment) { + Actions.CodeCompleteAssignmentRHS(getCurScope(), LHS.get()); + cutOffParsing(); + return ExprError(); + } + + // Parse another leaf here for the RHS of the operator. + // ParseCastExpression works here because all RHS expressions in C have it + // as a prefix, at least. However, in C++, an assignment-expression could + // be a throw-expression, which is not a valid cast-expression. + // Therefore we need some special-casing here. + // Also note that the third operand of the conditional operator is + // an assignment-expression in C++, and in C++11, we can have a + // braced-init-list on the RHS of an assignment. For better diagnostics, + // parse as if we were allowed braced-init-lists everywhere, and check that + // they only appear on the RHS of assignments later. + ExprResult RHS; + bool RHSIsInitList = false; + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + RHS = ParseBraceInitializer(); + RHSIsInitList = true; + } else if (getLangOpts().CPlusPlus && NextTokPrec <= prec::Conditional) + RHS = ParseAssignmentExpression(); + else + RHS = ParseCastExpression(false); + + if (RHS.isInvalid()) + LHS = ExprError(); + + // Remember the precedence of this operator and get the precedence of the + // operator immediately to the right of the RHS. + prec::Level ThisPrec = NextTokPrec; + NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, + getLangOpts().CPlusPlus0x); + + // Assignment and conditional expressions are right-associative. + bool isRightAssoc = ThisPrec == prec::Conditional || + ThisPrec == prec::Assignment; + + // Get the precedence of the operator to the right of the RHS. If it binds + // more tightly with RHS than we do, evaluate it completely first. + if (ThisPrec < NextTokPrec || + (ThisPrec == NextTokPrec && isRightAssoc)) { + if (!RHS.isInvalid() && RHSIsInitList) { + Diag(Tok, diag::err_init_list_bin_op) + << /*LHS*/0 << PP.getSpelling(Tok) << Actions.getExprRange(RHS.get()); + RHS = ExprError(); + } + // If this is left-associative, only parse things on the RHS that bind + // more tightly than the current operator. If it is left-associative, it + // is okay, to bind exactly as tightly. For example, compile A=B=C=D as + // A=(B=(C=D)), where each paren is a level of recursion here. + // The function takes ownership of the RHS. + RHS = ParseRHSOfBinaryExpression(RHS, + static_cast(ThisPrec + !isRightAssoc)); + RHSIsInitList = false; + + if (RHS.isInvalid()) + LHS = ExprError(); + + NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, + getLangOpts().CPlusPlus0x); + } + assert(NextTokPrec <= ThisPrec && "Recursion didn't work!"); + + if (!RHS.isInvalid() && RHSIsInitList) { + if (ThisPrec == prec::Assignment) { + Diag(OpToken, diag::warn_cxx98_compat_generalized_initializer_lists) + << Actions.getExprRange(RHS.get()); + } else { + Diag(OpToken, diag::err_init_list_bin_op) + << /*RHS*/1 << PP.getSpelling(OpToken) + << Actions.getExprRange(RHS.get()); + LHS = ExprError(); + } + } + + if (!LHS.isInvalid()) { + // Combine the LHS and RHS into the LHS (e.g. build AST). + if (TernaryMiddle.isInvalid()) { + // If we're using '>>' as an operator within a template + // argument list (in C++98), suggest the addition of + // parentheses so that the code remains well-formed in C++0x. + if (!GreaterThanIsOperator && OpToken.is(tok::greatergreater)) + SuggestParentheses(OpToken.getLocation(), + diag::warn_cxx0x_right_shift_in_template_arg, + SourceRange(Actions.getExprRange(LHS.get()).getBegin(), + Actions.getExprRange(RHS.get()).getEnd())); + + LHS = Actions.ActOnBinOp(getCurScope(), OpToken.getLocation(), + OpToken.getKind(), LHS.take(), RHS.take()); + } else + LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc, + LHS.take(), TernaryMiddle.take(), + RHS.take()); + } + } +} + +/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is +/// true, parse a unary-expression. isAddressOfOperand exists because an +/// id-expression that is the operand of address-of gets special treatment +/// due to member pointers. +/// +ExprResult Parser::ParseCastExpression(bool isUnaryExpression, + bool isAddressOfOperand, + TypeCastState isTypeCast) { + bool NotCastExpr; + ExprResult Res = ParseCastExpression(isUnaryExpression, + isAddressOfOperand, + NotCastExpr, + isTypeCast); + if (NotCastExpr) + Diag(Tok, diag::err_expected_expression); + return move(Res); +} + +namespace { +class CastExpressionIdValidator : public CorrectionCandidateCallback { + public: + CastExpressionIdValidator(bool AllowTypes, bool AllowNonTypes) + : AllowNonTypes(AllowNonTypes) { + WantTypeSpecifiers = AllowTypes; + } + + virtual bool ValidateCandidate(const TypoCorrection &candidate) { + NamedDecl *ND = candidate.getCorrectionDecl(); + if (!ND) + return candidate.isKeyword(); + + if (isa(ND)) + return WantTypeSpecifiers; + return AllowNonTypes; + } + + private: + bool AllowNonTypes; +}; +} + +/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is +/// true, parse a unary-expression. isAddressOfOperand exists because an +/// id-expression that is the operand of address-of gets special treatment +/// due to member pointers. NotCastExpr is set to true if the token is not the +/// start of a cast-expression, and no diagnostic is emitted in this case. +/// +/// cast-expression: [C99 6.5.4] +/// unary-expression +/// '(' type-name ')' cast-expression +/// +/// unary-expression: [C99 6.5.3] +/// postfix-expression +/// '++' unary-expression +/// '--' unary-expression +/// unary-operator cast-expression +/// 'sizeof' unary-expression +/// 'sizeof' '(' type-name ')' +/// [C++11] 'sizeof' '...' '(' identifier ')' +/// [GNU] '__alignof' unary-expression +/// [GNU] '__alignof' '(' type-name ')' +/// [C++11] 'alignof' '(' type-id ')' +/// [GNU] '&&' identifier +/// [C++11] 'noexcept' '(' expression ')' [C++11 5.3.7] +/// [C++] new-expression +/// [C++] delete-expression +/// +/// unary-operator: one of +/// '&' '*' '+' '-' '~' '!' +/// [GNU] '__extension__' '__real' '__imag' +/// +/// primary-expression: [C99 6.5.1] +/// [C99] identifier +/// [C++] id-expression +/// constant +/// string-literal +/// [C++] boolean-literal [C++ 2.13.5] +/// [C++11] 'nullptr' [C++11 2.14.7] +/// [C++11] user-defined-literal +/// '(' expression ')' +/// [C11] generic-selection +/// '__func__' [C99 6.4.2.2] +/// [GNU] '__FUNCTION__' +/// [GNU] '__PRETTY_FUNCTION__' +/// [GNU] '(' compound-statement ')' +/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' +/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' +/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' +/// assign-expr ')' +/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' +/// [GNU] '__null' +/// [OBJC] '[' objc-message-expr ']' +/// [OBJC] '@selector' '(' objc-selector-arg ')' +/// [OBJC] '@protocol' '(' identifier ')' +/// [OBJC] '@encode' '(' type-name ')' +/// [OBJC] objc-string-literal +/// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] +/// [C++11] simple-type-specifier braced-init-list [C++11 5.2.3] +/// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3] +/// [C++11] typename-specifier braced-init-list [C++11 5.2.3] +/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] +/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] +/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] +/// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] +/// [C++] 'typeid' '(' expression ')' [C++ 5.2p1] +/// [C++] 'typeid' '(' type-id ')' [C++ 5.2p1] +/// [C++] 'this' [C++ 9.3.2] +/// [G++] unary-type-trait '(' type-id ')' +/// [G++] binary-type-trait '(' type-id ',' type-id ')' [TODO] +/// [EMBT] array-type-trait '(' type-id ',' integer ')' +/// [clang] '^' block-literal +/// +/// constant: [C99 6.4.4] +/// integer-constant +/// floating-constant +/// enumeration-constant -> identifier +/// character-constant +/// +/// id-expression: [C++ 5.1] +/// unqualified-id +/// qualified-id +/// +/// unqualified-id: [C++ 5.1] +/// identifier +/// operator-function-id +/// conversion-function-id +/// '~' class-name +/// template-id +/// +/// new-expression: [C++ 5.3.4] +/// '::'[opt] 'new' new-placement[opt] new-type-id +/// new-initializer[opt] +/// '::'[opt] 'new' new-placement[opt] '(' type-id ')' +/// new-initializer[opt] +/// +/// delete-expression: [C++ 5.3.5] +/// '::'[opt] 'delete' cast-expression +/// '::'[opt] 'delete' '[' ']' cast-expression +/// +/// [GNU/Embarcadero] unary-type-trait: +/// '__is_arithmetic' +/// '__is_floating_point' +/// '__is_integral' +/// '__is_lvalue_expr' +/// '__is_rvalue_expr' +/// '__is_complete_type' +/// '__is_void' +/// '__is_array' +/// '__is_function' +/// '__is_reference' +/// '__is_lvalue_reference' +/// '__is_rvalue_reference' +/// '__is_fundamental' +/// '__is_object' +/// '__is_scalar' +/// '__is_compound' +/// '__is_pointer' +/// '__is_member_object_pointer' +/// '__is_member_function_pointer' +/// '__is_member_pointer' +/// '__is_const' +/// '__is_volatile' +/// '__is_trivial' +/// '__is_standard_layout' +/// '__is_signed' +/// '__is_unsigned' +/// +/// [GNU] unary-type-trait: +/// '__has_nothrow_assign' +/// '__has_nothrow_copy' +/// '__has_nothrow_constructor' +/// '__has_trivial_assign' [TODO] +/// '__has_trivial_copy' [TODO] +/// '__has_trivial_constructor' +/// '__has_trivial_destructor' +/// '__has_virtual_destructor' +/// '__is_abstract' [TODO] +/// '__is_class' +/// '__is_empty' [TODO] +/// '__is_enum' +/// '__is_final' +/// '__is_pod' +/// '__is_polymorphic' +/// '__is_trivial' +/// '__is_union' +/// +/// [Clang] unary-type-trait: +/// '__trivially_copyable' +/// +/// binary-type-trait: +/// [GNU] '__is_base_of' +/// [MS] '__is_convertible_to' +/// '__is_convertible' +/// '__is_same' +/// +/// [Embarcadero] array-type-trait: +/// '__array_rank' +/// '__array_extent' +/// +/// [Embarcadero] expression-trait: +/// '__is_lvalue_expr' +/// '__is_rvalue_expr' +/// +ExprResult Parser::ParseCastExpression(bool isUnaryExpression, + bool isAddressOfOperand, + bool &NotCastExpr, + TypeCastState isTypeCast) { + ExprResult Res; + tok::TokenKind SavedKind = Tok.getKind(); + NotCastExpr = false; + + // This handles all of cast-expression, unary-expression, postfix-expression, + // and primary-expression. We handle them together like this for efficiency + // and to simplify handling of an expression starting with a '(' token: which + // may be one of a parenthesized expression, cast-expression, compound literal + // expression, or statement expression. + // + // If the parsed tokens consist of a primary-expression, the cases below + // break out of the switch; at the end we call ParsePostfixExpressionSuffix + // to handle the postfix expression suffixes. Cases that cannot be followed + // by postfix exprs should return without invoking + // ParsePostfixExpressionSuffix. + switch (SavedKind) { + case tok::l_paren: { + // If this expression is limited to being a unary-expression, the parent can + // not start a cast expression. + ParenParseOption ParenExprType = + (isUnaryExpression && !getLangOpts().CPlusPlus)? CompoundLiteral : CastExpr; + ParsedType CastTy; + SourceLocation RParenLoc; + + { + // The inside of the parens don't need to be a colon protected scope, and + // isn't immediately a message send. + ColonProtectionRAIIObject X(*this, false); + + Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, + isTypeCast == IsTypeCast, CastTy, RParenLoc); + } + + switch (ParenExprType) { + case SimpleExpr: break; // Nothing else to do. + case CompoundStmt: break; // Nothing else to do. + case CompoundLiteral: + // We parsed '(' type-name ')' '{' ... '}'. If any suffixes of + // postfix-expression exist, parse them now. + break; + case CastExpr: + // We have parsed the cast-expression and no postfix-expr pieces are + // following. + return move(Res); + } + + break; + } + + // primary-expression + case tok::numeric_constant: + // constant: integer-constant + // constant: floating-constant + + Res = Actions.ActOnNumericConstant(Tok, /*UDLScope*/getCurScope()); + ConsumeToken(); + break; + + case tok::kw_true: + case tok::kw_false: + return ParseCXXBoolLiteral(); + + case tok::kw___objc_yes: + case tok::kw___objc_no: + return ParseObjCBoolLiteral(); + + case tok::kw_nullptr: + Diag(Tok, diag::warn_cxx98_compat_nullptr); + return Actions.ActOnCXXNullPtrLiteral(ConsumeToken()); + + case tok::annot_primary_expr: + assert(Res.get() == 0 && "Stray primary-expression annotation?"); + Res = getExprAnnotation(Tok); + ConsumeToken(); + break; + + case tok::kw_decltype: + case tok::identifier: { // primary-expression: identifier + // unqualified-id: identifier + // constant: enumeration-constant + // Turn a potentially qualified name into a annot_typename or + // annot_cxxscope if it would be valid. This handles things like x::y, etc. + if (getLangOpts().CPlusPlus) { + // Avoid the unnecessary parse-time lookup in the common case + // where the syntax forbids a type. + const Token &Next = NextToken(); + if (Next.is(tok::coloncolon) || + (!ColonIsSacred && Next.is(tok::colon)) || + Next.is(tok::less) || + Next.is(tok::l_paren) || + Next.is(tok::l_brace)) { + // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. + if (TryAnnotateTypeOrScopeToken()) + return ExprError(); + if (!Tok.is(tok::identifier)) + return ParseCastExpression(isUnaryExpression, isAddressOfOperand); + } + } + + // Consume the identifier so that we can see if it is followed by a '(' or + // '.'. + IdentifierInfo &II = *Tok.getIdentifierInfo(); + SourceLocation ILoc = ConsumeToken(); + + // Support 'Class.property' and 'super.property' notation. + if (getLangOpts().ObjC1 && Tok.is(tok::period) && + (Actions.getTypeName(II, ILoc, getCurScope()) || + // Allow the base to be 'super' if in an objc-method. + (&II == Ident_super && getCurScope()->isInObjcMethodScope()))) { + ConsumeToken(); + + // Allow either an identifier or the keyword 'class' (in C++). + if (Tok.isNot(tok::identifier) && + !(getLangOpts().CPlusPlus && Tok.is(tok::kw_class))) { + Diag(Tok, diag::err_expected_property_name); + return ExprError(); + } + IdentifierInfo &PropertyName = *Tok.getIdentifierInfo(); + SourceLocation PropertyLoc = ConsumeToken(); + + Res = Actions.ActOnClassPropertyRefExpr(II, PropertyName, + ILoc, PropertyLoc); + break; + } + + // In an Objective-C method, if we have "super" followed by an identifier, + // the token sequence is ill-formed. However, if there's a ':' or ']' after + // that identifier, this is probably a message send with a missing open + // bracket. Treat it as such. + if (getLangOpts().ObjC1 && &II == Ident_super && !InMessageExpression && + getCurScope()->isInObjcMethodScope() && + ((Tok.is(tok::identifier) && + (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) || + Tok.is(tok::code_completion))) { + Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, ParsedType(), + 0); + break; + } + + // If we have an Objective-C class name followed by an identifier + // and either ':' or ']', this is an Objective-C class message + // send that's missing the opening '['. Recovery + // appropriately. Also take this path if we're performing code + // completion after an Objective-C class name. + if (getLangOpts().ObjC1 && + ((Tok.is(tok::identifier) && !InMessageExpression) || + Tok.is(tok::code_completion))) { + const Token& Next = NextToken(); + if (Tok.is(tok::code_completion) || + Next.is(tok::colon) || Next.is(tok::r_square)) + if (ParsedType Typ = Actions.getTypeName(II, ILoc, getCurScope())) + if (Typ.get()->isObjCObjectOrInterfaceType()) { + // Fake up a Declarator to use with ActOnTypeName. + DeclSpec DS(AttrFactory); + DS.SetRangeStart(ILoc); + DS.SetRangeEnd(ILoc); + const char *PrevSpec = 0; + unsigned DiagID; + DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Typ); + + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + TypeResult Ty = Actions.ActOnTypeName(getCurScope(), + DeclaratorInfo); + if (Ty.isInvalid()) + break; + + Res = ParseObjCMessageExpressionBody(SourceLocation(), + SourceLocation(), + Ty.get(), 0); + break; + } + } + + // Make sure to pass down the right value for isAddressOfOperand. + if (isAddressOfOperand && isPostfixExpressionSuffixStart()) + isAddressOfOperand = false; + + // Function designators are allowed to be undeclared (C99 6.5.1p2), so we + // need to know whether or not this identifier is a function designator or + // not. + UnqualifiedId Name; + CXXScopeSpec ScopeSpec; + SourceLocation TemplateKWLoc; + CastExpressionIdValidator Validator(isTypeCast != NotTypeCast, + isTypeCast != IsTypeCast); + Name.setIdentifier(&II, ILoc); + Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc, + Name, Tok.is(tok::l_paren), + isAddressOfOperand, &Validator); + break; + } + case tok::char_constant: // constant: character-constant + case tok::wide_char_constant: + case tok::utf16_char_constant: + case tok::utf32_char_constant: + Res = Actions.ActOnCharacterConstant(Tok, /*UDLScope*/getCurScope()); + ConsumeToken(); + break; + case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2] + case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU] + case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] + Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind); + ConsumeToken(); + break; + case tok::string_literal: // primary-expression: string-literal + case tok::wide_string_literal: + case tok::utf8_string_literal: + case tok::utf16_string_literal: + case tok::utf32_string_literal: + Res = ParseStringLiteralExpression(true); + break; + case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1] + Res = ParseGenericSelectionExpression(); + break; + case tok::kw___builtin_va_arg: + case tok::kw___builtin_offsetof: + case tok::kw___builtin_choose_expr: + case tok::kw___builtin_astype: // primary-expression: [OCL] as_type() + return ParseBuiltinPrimaryExpression(); + case tok::kw___null: + return Actions.ActOnGNUNullExpr(ConsumeToken()); + + case tok::plusplus: // unary-expression: '++' unary-expression [C99] + case tok::minusminus: { // unary-expression: '--' unary-expression [C99] + // C++ [expr.unary] has: + // unary-expression: + // ++ cast-expression + // -- cast-expression + SourceLocation SavedLoc = ConsumeToken(); + Res = ParseCastExpression(!getLangOpts().CPlusPlus); + if (!Res.isInvalid()) + Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); + return move(Res); + } + case tok::amp: { // unary-expression: '&' cast-expression + // Special treatment because of member pointers + SourceLocation SavedLoc = ConsumeToken(); + Res = ParseCastExpression(false, true); + if (!Res.isInvalid()) + Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); + return move(Res); + } + + case tok::star: // unary-expression: '*' cast-expression + case tok::plus: // unary-expression: '+' cast-expression + case tok::minus: // unary-expression: '-' cast-expression + case tok::tilde: // unary-expression: '~' cast-expression + case tok::exclaim: // unary-expression: '!' cast-expression + case tok::kw___real: // unary-expression: '__real' cast-expression [GNU] + case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU] + SourceLocation SavedLoc = ConsumeToken(); + Res = ParseCastExpression(false); + if (!Res.isInvalid()) + Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); + return move(Res); + } + + case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU] + // __extension__ silences extension warnings in the subexpression. + ExtensionRAIIObject O(Diags); // Use RAII to do this. + SourceLocation SavedLoc = ConsumeToken(); + Res = ParseCastExpression(false); + if (!Res.isInvalid()) + Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); + return move(Res); + } + case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression + // unary-expression: 'sizeof' '(' type-name ')' + case tok::kw_alignof: + case tok::kw___alignof: // unary-expression: '__alignof' unary-expression + // unary-expression: '__alignof' '(' type-name ')' + // unary-expression: 'alignof' '(' type-id ')' + case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression + return ParseUnaryExprOrTypeTraitExpression(); + case tok::ampamp: { // unary-expression: '&&' identifier + SourceLocation AmpAmpLoc = ConsumeToken(); + if (Tok.isNot(tok::identifier)) + return ExprError(Diag(Tok, diag::err_expected_ident)); + + if (getCurScope()->getFnParent() == 0) + return ExprError(Diag(Tok, diag::err_address_of_label_outside_fn)); + + Diag(AmpAmpLoc, diag::ext_gnu_address_of_label); + LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(), + Tok.getLocation()); + Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), LD); + ConsumeToken(); + return move(Res); + } + case tok::kw_const_cast: + case tok::kw_dynamic_cast: + case tok::kw_reinterpret_cast: + case tok::kw_static_cast: + Res = ParseCXXCasts(); + break; + case tok::kw_typeid: + Res = ParseCXXTypeid(); + break; + case tok::kw___uuidof: + Res = ParseCXXUuidof(); + break; + case tok::kw_this: + Res = ParseCXXThis(); + break; + + case tok::annot_typename: + if (isStartOfObjCClassMessageMissingOpenBracket()) { + ParsedType Type = getTypeAnnotation(Tok); + + // Fake up a Declarator to use with ActOnTypeName. + DeclSpec DS(AttrFactory); + DS.SetRangeStart(Tok.getLocation()); + DS.SetRangeEnd(Tok.getLastLoc()); + + const char *PrevSpec = 0; + unsigned DiagID; + DS.SetTypeSpecType(TST_typename, Tok.getAnnotationEndLoc(), + PrevSpec, DiagID, Type); + + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); + if (Ty.isInvalid()) + break; + + ConsumeToken(); + Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), + Ty.get(), 0); + break; + } + // Fall through + + case tok::annot_decltype: + case tok::kw_char: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_bool: + case tok::kw_short: + case tok::kw_int: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_half: + case tok::kw_float: + case tok::kw_double: + case tok::kw_void: + case tok::kw_typename: + case tok::kw_typeof: + case tok::kw___vector: { + if (!getLangOpts().CPlusPlus) { + Diag(Tok, diag::err_expected_expression); + return ExprError(); + } + + if (SavedKind == tok::kw_typename) { + // postfix-expression: typename-specifier '(' expression-list[opt] ')' + // typename-specifier braced-init-list + if (TryAnnotateTypeOrScopeToken()) + return ExprError(); + } + + // postfix-expression: simple-type-specifier '(' expression-list[opt] ')' + // simple-type-specifier braced-init-list + // + DeclSpec DS(AttrFactory); + ParseCXXSimpleTypeSpecifier(DS); + if (Tok.isNot(tok::l_paren) && + (!getLangOpts().CPlusPlus0x || Tok.isNot(tok::l_brace))) + return ExprError(Diag(Tok, diag::err_expected_lparen_after_type) + << DS.getSourceRange()); + + if (Tok.is(tok::l_brace)) + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + + Res = ParseCXXTypeConstructExpression(DS); + break; + } + + case tok::annot_cxxscope: { // [C++] id-expression: qualified-id + // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. + // (We can end up in this situation after tentative parsing.) + if (TryAnnotateTypeOrScopeToken()) + return ExprError(); + if (!Tok.is(tok::annot_cxxscope)) + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, isTypeCast); + + Token Next = NextToken(); + if (Next.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next); + if (TemplateId->Kind == TNK_Type_template) { + // We have a qualified template-id that we know refers to a + // type, translate it into a type and continue parsing as a + // cast expression. + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*EnteringContext=*/false); + AnnotateTemplateIdTokenAsType(); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, isTypeCast); + } + } + + // Parse as an id-expression. + Res = ParseCXXIdExpression(isAddressOfOperand); + break; + } + + case tok::annot_template_id: { // [C++] template-id + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (TemplateId->Kind == TNK_Type_template) { + // We have a template-id that we know refers to a type, + // translate it into a type and continue parsing as a cast + // expression. + AnnotateTemplateIdTokenAsType(); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, isTypeCast); + } + + // Fall through to treat the template-id as an id-expression. + } + + case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id + Res = ParseCXXIdExpression(isAddressOfOperand); + break; + + case tok::coloncolon: { + // ::foo::bar -> global qualified name etc. If TryAnnotateTypeOrScopeToken + // annotates the token, tail recurse. + if (TryAnnotateTypeOrScopeToken()) + return ExprError(); + if (!Tok.is(tok::coloncolon)) + return ParseCastExpression(isUnaryExpression, isAddressOfOperand); + + // ::new -> [C++] new-expression + // ::delete -> [C++] delete-expression + SourceLocation CCLoc = ConsumeToken(); + if (Tok.is(tok::kw_new)) + return ParseCXXNewExpression(true, CCLoc); + if (Tok.is(tok::kw_delete)) + return ParseCXXDeleteExpression(true, CCLoc); + + // This is not a type name or scope specifier, it is an invalid expression. + Diag(CCLoc, diag::err_expected_expression); + return ExprError(); + } + + case tok::kw_new: // [C++] new-expression + return ParseCXXNewExpression(false, Tok.getLocation()); + + case tok::kw_delete: // [C++] delete-expression + return ParseCXXDeleteExpression(false, Tok.getLocation()); + + case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')' + Diag(Tok, diag::warn_cxx98_compat_noexcept_expr); + SourceLocation KeyLoc = ConsumeToken(); + BalancedDelimiterTracker T(*this, tok::l_paren); + + if (T.expectAndConsume(diag::err_expected_lparen_after, "noexcept")) + return ExprError(); + // C++11 [expr.unary.noexcept]p1: + // The noexcept operator determines whether the evaluation of its operand, + // which is an unevaluated operand, can throw an exception. + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + ExprResult Result = ParseExpression(); + + T.consumeClose(); + + if (!Result.isInvalid()) + Result = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(), + Result.take(), T.getCloseLocation()); + return move(Result); + } + + case tok::kw___is_abstract: // [GNU] unary-type-trait + case tok::kw___is_class: + case tok::kw___is_empty: + case tok::kw___is_enum: + case tok::kw___is_literal: + case tok::kw___is_arithmetic: + case tok::kw___is_integral: + case tok::kw___is_floating_point: + case tok::kw___is_complete_type: + case tok::kw___is_void: + case tok::kw___is_array: + case tok::kw___is_function: + case tok::kw___is_reference: + case tok::kw___is_lvalue_reference: + case tok::kw___is_rvalue_reference: + case tok::kw___is_fundamental: + case tok::kw___is_object: + case tok::kw___is_scalar: + case tok::kw___is_compound: + case tok::kw___is_pointer: + case tok::kw___is_member_object_pointer: + case tok::kw___is_member_function_pointer: + case tok::kw___is_member_pointer: + case tok::kw___is_const: + case tok::kw___is_volatile: + case tok::kw___is_standard_layout: + case tok::kw___is_signed: + case tok::kw___is_unsigned: + case tok::kw___is_literal_type: + case tok::kw___is_pod: + case tok::kw___is_polymorphic: + case tok::kw___is_trivial: + case tok::kw___is_trivially_copyable: + case tok::kw___is_union: + case tok::kw___is_final: + case tok::kw___has_trivial_constructor: + case tok::kw___has_trivial_copy: + case tok::kw___has_trivial_assign: + case tok::kw___has_trivial_destructor: + case tok::kw___has_nothrow_assign: + case tok::kw___has_nothrow_copy: + case tok::kw___has_nothrow_constructor: + case tok::kw___has_virtual_destructor: + return ParseUnaryTypeTrait(); + + case tok::kw___builtin_types_compatible_p: + case tok::kw___is_base_of: + case tok::kw___is_same: + case tok::kw___is_convertible: + case tok::kw___is_convertible_to: + case tok::kw___is_trivially_assignable: + return ParseBinaryTypeTrait(); + + case tok::kw___is_trivially_constructible: + return ParseTypeTrait(); + + case tok::kw___array_rank: + case tok::kw___array_extent: + return ParseArrayTypeTrait(); + + case tok::kw___is_lvalue_expr: + case tok::kw___is_rvalue_expr: + return ParseExpressionTrait(); + + case tok::at: { + SourceLocation AtLoc = ConsumeToken(); + return ParseObjCAtExpression(AtLoc); + } + case tok::caret: + Res = ParseBlockLiteralExpression(); + break; + case tok::code_completion: { + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); + cutOffParsing(); + return ExprError(); + } + case tok::l_square: + if (getLangOpts().CPlusPlus0x) { + if (getLangOpts().ObjC1) { + // C++11 lambda expressions and Objective-C message sends both start with a + // square bracket. There are three possibilities here: + // we have a valid lambda expression, we have an invalid lambda + // expression, or we have something that doesn't appear to be a lambda. + // If we're in the last case, we fall back to ParseObjCMessageExpression. + Res = TryParseLambdaExpression(); + if (!Res.isInvalid() && !Res.get()) + Res = ParseObjCMessageExpression(); + break; + } + Res = ParseLambdaExpression(); + break; + } + if (getLangOpts().ObjC1) { + Res = ParseObjCMessageExpression(); + break; + } + // FALL THROUGH. + default: + NotCastExpr = true; + return ExprError(); + } + + // These can be followed by postfix-expr pieces. + return ParsePostfixExpressionSuffix(Res); +} + +/// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression +/// is parsed, this method parses any suffixes that apply. +/// +/// postfix-expression: [C99 6.5.2] +/// primary-expression +/// postfix-expression '[' expression ']' +/// postfix-expression '[' braced-init-list ']' +/// postfix-expression '(' argument-expression-list[opt] ')' +/// postfix-expression '.' identifier +/// postfix-expression '->' identifier +/// postfix-expression '++' +/// postfix-expression '--' +/// '(' type-name ')' '{' initializer-list '}' +/// '(' type-name ')' '{' initializer-list ',' '}' +/// +/// argument-expression-list: [C99 6.5.2] +/// argument-expression ...[opt] +/// argument-expression-list ',' assignment-expression ...[opt] +/// +ExprResult +Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { + // Now that the primary-expression piece of the postfix-expression has been + // parsed, see if there are any postfix-expression pieces here. + SourceLocation Loc; + while (1) { + switch (Tok.getKind()) { + case tok::code_completion: + if (InMessageExpression) + return move(LHS); + + Actions.CodeCompletePostfixExpression(getCurScope(), LHS); + cutOffParsing(); + return ExprError(); + + case tok::identifier: + // If we see identifier: after an expression, and we're not already in a + // message send, then this is probably a message send with a missing + // opening bracket '['. + if (getLangOpts().ObjC1 && !InMessageExpression && + (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { + LHS = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), + ParsedType(), LHS.get()); + break; + } + + // Fall through; this isn't a message send. + + default: // Not a postfix-expression suffix. + return move(LHS); + case tok::l_square: { // postfix-expression: p-e '[' expression ']' + // If we have a array postfix expression that starts on a new line and + // Objective-C is enabled, it is highly likely that the user forgot a + // semicolon after the base expression and that the array postfix-expr is + // actually another message send. In this case, do some look-ahead to see + // if the contents of the square brackets are obviously not a valid + // expression and recover by pretending there is no suffix. + if (getLangOpts().ObjC1 && Tok.isAtStartOfLine() && + isSimpleObjCMessageExpression()) + return move(LHS); + + // Reject array indices starting with a lambda-expression. '[[' is + // reserved for attributes. + if (CheckProhibitedCXX11Attribute()) + return ExprError(); + + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + Loc = T.getOpenLocation(); + ExprResult Idx; + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + Idx = ParseBraceInitializer(); + } else + Idx = ParseExpression(); + + SourceLocation RLoc = Tok.getLocation(); + + if (!LHS.isInvalid() && !Idx.isInvalid() && Tok.is(tok::r_square)) { + LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.take(), Loc, + Idx.take(), RLoc); + } else + LHS = ExprError(); + + // Match the ']'. + T.consumeClose(); + break; + } + + case tok::l_paren: // p-e: p-e '(' argument-expression-list[opt] ')' + case tok::lesslessless: { // p-e: p-e '<<<' argument-expression-list '>>>' + // '(' argument-expression-list[opt] ')' + tok::TokenKind OpKind = Tok.getKind(); + InMessageExpressionRAIIObject InMessage(*this, false); + + Expr *ExecConfig = 0; + + BalancedDelimiterTracker PT(*this, tok::l_paren); + + if (OpKind == tok::lesslessless) { + ExprVector ExecConfigExprs(Actions); + CommaLocsTy ExecConfigCommaLocs; + SourceLocation OpenLoc = ConsumeToken(); + + if (ParseExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) { + LHS = ExprError(); + } + + SourceLocation CloseLoc = Tok.getLocation(); + if (Tok.is(tok::greatergreatergreater)) { + ConsumeToken(); + } else if (LHS.isInvalid()) { + SkipUntil(tok::greatergreatergreater); + } else { + // There was an error closing the brackets + Diag(Tok, diag::err_expected_ggg); + Diag(OpenLoc, diag::note_matching) << "<<<"; + SkipUntil(tok::greatergreatergreater); + LHS = ExprError(); + } + + if (!LHS.isInvalid()) { + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen, "")) + LHS = ExprError(); + else + Loc = PrevTokLocation; + } + + if (!LHS.isInvalid()) { + ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(), + OpenLoc, + move_arg(ExecConfigExprs), + CloseLoc); + if (ECResult.isInvalid()) + LHS = ExprError(); + else + ExecConfig = ECResult.get(); + } + } else { + PT.consumeOpen(); + Loc = PT.getOpenLocation(); + } + + ExprVector ArgExprs(Actions); + CommaLocsTy CommaLocs; + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteCall(getCurScope(), LHS.get(), + llvm::ArrayRef()); + cutOffParsing(); + return ExprError(); + } + + if (OpKind == tok::l_paren || !LHS.isInvalid()) { + if (Tok.isNot(tok::r_paren)) { + if (ParseExpressionList(ArgExprs, CommaLocs, &Sema::CodeCompleteCall, + LHS.get())) { + LHS = ExprError(); + } + } + } + + // Match the ')'. + if (LHS.isInvalid()) { + SkipUntil(tok::r_paren); + } else if (Tok.isNot(tok::r_paren)) { + PT.consumeClose(); + LHS = ExprError(); + } else { + assert((ArgExprs.size() == 0 || + ArgExprs.size()-1 == CommaLocs.size())&& + "Unexpected number of commas!"); + LHS = Actions.ActOnCallExpr(getCurScope(), LHS.take(), Loc, + move_arg(ArgExprs), Tok.getLocation(), + ExecConfig); + PT.consumeClose(); + } + + break; + } + case tok::arrow: + case tok::period: { + // postfix-expression: p-e '->' template[opt] id-expression + // postfix-expression: p-e '.' template[opt] id-expression + tok::TokenKind OpKind = Tok.getKind(); + SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token. + + CXXScopeSpec SS; + ParsedType ObjectType; + bool MayBePseudoDestructor = false; + if (getLangOpts().CPlusPlus && !LHS.isInvalid()) { + LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), LHS.take(), + OpLoc, OpKind, ObjectType, + MayBePseudoDestructor); + if (LHS.isInvalid()) + break; + + ParseOptionalCXXScopeSpecifier(SS, ObjectType, + /*EnteringContext=*/false, + &MayBePseudoDestructor); + if (SS.isNotEmpty()) + ObjectType = ParsedType(); + } + + if (Tok.is(tok::code_completion)) { + // Code completion for a member access expression. + Actions.CodeCompleteMemberReferenceExpr(getCurScope(), LHS.get(), + OpLoc, OpKind == tok::arrow); + + cutOffParsing(); + return ExprError(); + } + + if (MayBePseudoDestructor && !LHS.isInvalid()) { + LHS = ParseCXXPseudoDestructor(LHS.take(), OpLoc, OpKind, SS, + ObjectType); + break; + } + + // Either the action has told is that this cannot be a + // pseudo-destructor expression (based on the type of base + // expression), or we didn't see a '~' in the right place. We + // can still parse a destructor name here, but in that case it + // names a real destructor. + // Allow explicit constructor calls in Microsoft mode. + // FIXME: Add support for explicit call of template constructor. + SourceLocation TemplateKWLoc; + UnqualifiedId Name; + if (getLangOpts().ObjC2 && OpKind == tok::period && Tok.is(tok::kw_class)) { + // Objective-C++: + // After a '.' in a member access expression, treat the keyword + // 'class' as if it were an identifier. + // + // This hack allows property access to the 'class' method because it is + // such a common method name. For other C++ keywords that are + // Objective-C method names, one must use the message send syntax. + IdentifierInfo *Id = Tok.getIdentifierInfo(); + SourceLocation Loc = ConsumeToken(); + Name.setIdentifier(Id, Loc); + } else if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/ + getLangOpts().MicrosoftExt, + ObjectType, TemplateKWLoc, Name)) + LHS = ExprError(); + + if (!LHS.isInvalid()) + LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.take(), OpLoc, + OpKind, SS, TemplateKWLoc, Name, + CurParsedObjCImpl ? CurParsedObjCImpl->Dcl : 0, + Tok.is(tok::l_paren)); + break; + } + case tok::plusplus: // postfix-expression: postfix-expression '++' + case tok::minusminus: // postfix-expression: postfix-expression '--' + if (!LHS.isInvalid()) { + LHS = Actions.ActOnPostfixUnaryOp(getCurScope(), Tok.getLocation(), + Tok.getKind(), LHS.take()); + } + ConsumeToken(); + break; + } + } +} + +/// ParseExprAfterUnaryExprOrTypeTrait - We parsed a typeof/sizeof/alignof/ +/// vec_step and we are at the start of an expression or a parenthesized +/// type-id. OpTok is the operand token (typeof/sizeof/alignof). Returns the +/// expression (isCastExpr == false) or the type (isCastExpr == true). +/// +/// unary-expression: [C99 6.5.3] +/// 'sizeof' unary-expression +/// 'sizeof' '(' type-name ')' +/// [GNU] '__alignof' unary-expression +/// [GNU] '__alignof' '(' type-name ')' +/// [C++0x] 'alignof' '(' type-id ')' +/// +/// [GNU] typeof-specifier: +/// typeof ( expressions ) +/// typeof ( type-name ) +/// [GNU/C++] typeof unary-expression +/// +/// [OpenCL 1.1 6.11.12] vec_step built-in function: +/// vec_step ( expressions ) +/// vec_step ( type-name ) +/// +ExprResult +Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, + bool &isCastExpr, + ParsedType &CastTy, + SourceRange &CastRange) { + + assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) || + OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof) || + OpTok.is(tok::kw_vec_step)) && + "Not a typeof/sizeof/alignof/vec_step expression!"); + + ExprResult Operand; + + // If the operand doesn't start with an '(', it must be an expression. + if (Tok.isNot(tok::l_paren)) { + isCastExpr = false; + if (OpTok.is(tok::kw_typeof) && !getLangOpts().CPlusPlus) { + Diag(Tok,diag::err_expected_lparen_after_id) << OpTok.getIdentifierInfo(); + return ExprError(); + } + + Operand = ParseCastExpression(true/*isUnaryExpression*/); + } else { + // If it starts with a '(', we know that it is either a parenthesized + // type-name, or it is a unary-expression that starts with a compound + // literal, or starts with a primary-expression that is a parenthesized + // expression. + ParenParseOption ExprType = CastExpr; + SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; + + Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, + false, CastTy, RParenLoc); + CastRange = SourceRange(LParenLoc, RParenLoc); + + // If ParseParenExpression parsed a '(typename)' sequence only, then this is + // a type. + if (ExprType == CastExpr) { + isCastExpr = true; + return ExprEmpty(); + } + + if (getLangOpts().CPlusPlus || OpTok.isNot(tok::kw_typeof)) { + // GNU typeof in C requires the expression to be parenthesized. Not so for + // sizeof/alignof or in C++. Therefore, the parenthesized expression is + // the start of a unary-expression, but doesn't include any postfix + // pieces. Parse these now if present. + if (!Operand.isInvalid()) + Operand = ParsePostfixExpressionSuffix(Operand.get()); + } + } + + // If we get here, the operand to the typeof/sizeof/alignof was an expresion. + isCastExpr = false; + return move(Operand); +} + + +/// ParseUnaryExprOrTypeTraitExpression - Parse a sizeof or alignof expression. +/// unary-expression: [C99 6.5.3] +/// 'sizeof' unary-expression +/// 'sizeof' '(' type-name ')' +/// [C++0x] 'sizeof' '...' '(' identifier ')' +/// [GNU] '__alignof' unary-expression +/// [GNU] '__alignof' '(' type-name ')' +/// [C++0x] 'alignof' '(' type-id ')' +ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { + assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof) + || Tok.is(tok::kw_alignof) || Tok.is(tok::kw_vec_step)) && + "Not a sizeof/alignof/vec_step expression!"); + Token OpTok = Tok; + ConsumeToken(); + + // [C++0x] 'sizeof' '...' '(' identifier ')' + if (Tok.is(tok::ellipsis) && OpTok.is(tok::kw_sizeof)) { + SourceLocation EllipsisLoc = ConsumeToken(); + SourceLocation LParenLoc, RParenLoc; + IdentifierInfo *Name = 0; + SourceLocation NameLoc; + if (Tok.is(tok::l_paren)) { + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + LParenLoc = T.getOpenLocation(); + if (Tok.is(tok::identifier)) { + Name = Tok.getIdentifierInfo(); + NameLoc = ConsumeToken(); + T.consumeClose(); + RParenLoc = T.getCloseLocation(); + if (RParenLoc.isInvalid()) + RParenLoc = PP.getLocForEndOfToken(NameLoc); + } else { + Diag(Tok, diag::err_expected_parameter_pack); + SkipUntil(tok::r_paren); + } + } else if (Tok.is(tok::identifier)) { + Name = Tok.getIdentifierInfo(); + NameLoc = ConsumeToken(); + LParenLoc = PP.getLocForEndOfToken(EllipsisLoc); + RParenLoc = PP.getLocForEndOfToken(NameLoc); + Diag(LParenLoc, diag::err_paren_sizeof_parameter_pack) + << Name + << FixItHint::CreateInsertion(LParenLoc, "(") + << FixItHint::CreateInsertion(RParenLoc, ")"); + } else { + Diag(Tok, diag::err_sizeof_parameter_pack); + } + + if (!Name) + return ExprError(); + + return Actions.ActOnSizeofParameterPackExpr(getCurScope(), + OpTok.getLocation(), + *Name, NameLoc, + RParenLoc); + } + + if (OpTok.is(tok::kw_alignof)) + Diag(OpTok, diag::warn_cxx98_compat_alignof); + + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + + bool isCastExpr; + ParsedType CastTy; + SourceRange CastRange; + ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, + isCastExpr, + CastTy, + CastRange); + + UnaryExprOrTypeTrait ExprKind = UETT_SizeOf; + if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw___alignof)) + ExprKind = UETT_AlignOf; + else if (OpTok.is(tok::kw_vec_step)) + ExprKind = UETT_VecStep; + + if (isCastExpr) + return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), + ExprKind, + /*isType=*/true, + CastTy.getAsOpaquePtr(), + CastRange); + + // If we get here, the operand to the sizeof/alignof was an expresion. + if (!Operand.isInvalid()) + Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), + ExprKind, + /*isType=*/false, + Operand.release(), + CastRange); + return move(Operand); +} + +/// ParseBuiltinPrimaryExpression +/// +/// primary-expression: [C99 6.5.1] +/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' +/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' +/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' +/// assign-expr ')' +/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' +/// [OCL] '__builtin_astype' '(' assignment-expression ',' type-name ')' +/// +/// [GNU] offsetof-member-designator: +/// [GNU] identifier +/// [GNU] offsetof-member-designator '.' identifier +/// [GNU] offsetof-member-designator '[' expression ']' +/// +ExprResult Parser::ParseBuiltinPrimaryExpression() { + ExprResult Res; + const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo(); + + tok::TokenKind T = Tok.getKind(); + SourceLocation StartLoc = ConsumeToken(); // Eat the builtin identifier. + + // All of these start with an open paren. + if (Tok.isNot(tok::l_paren)) + return ExprError(Diag(Tok, diag::err_expected_lparen_after_id) + << BuiltinII); + + BalancedDelimiterTracker PT(*this, tok::l_paren); + PT.consumeOpen(); + + // TODO: Build AST. + + switch (T) { + default: llvm_unreachable("Not a builtin primary expression!"); + case tok::kw___builtin_va_arg: { + ExprResult Expr(ParseAssignmentExpression()); + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) + Expr = ExprError(); + + TypeResult Ty = ParseTypeName(); + + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + Expr = ExprError(); + } + + if (Expr.isInvalid() || Ty.isInvalid()) + Res = ExprError(); + else + Res = Actions.ActOnVAArg(StartLoc, Expr.take(), Ty.get(), ConsumeParen()); + break; + } + case tok::kw___builtin_offsetof: { + SourceLocation TypeLoc = Tok.getLocation(); + TypeResult Ty = ParseTypeName(); + if (Ty.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) + return ExprError(); + + // We must have at least one identifier here. + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::r_paren); + return ExprError(); + } + + // Keep track of the various subcomponents we see. + SmallVector Comps; + + Comps.push_back(Sema::OffsetOfComponent()); + Comps.back().isBrackets = false; + Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); + Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken(); + + // FIXME: This loop leaks the index expressions on error. + while (1) { + if (Tok.is(tok::period)) { + // offsetof-member-designator: offsetof-member-designator '.' identifier + Comps.push_back(Sema::OffsetOfComponent()); + Comps.back().isBrackets = false; + Comps.back().LocStart = ConsumeToken(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::r_paren); + return ExprError(); + } + Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); + Comps.back().LocEnd = ConsumeToken(); + + } else if (Tok.is(tok::l_square)) { + if (CheckProhibitedCXX11Attribute()) + return ExprError(); + + // offsetof-member-designator: offsetof-member-design '[' expression ']' + Comps.push_back(Sema::OffsetOfComponent()); + Comps.back().isBrackets = true; + BalancedDelimiterTracker ST(*this, tok::l_square); + ST.consumeOpen(); + Comps.back().LocStart = ST.getOpenLocation(); + Res = ParseExpression(); + if (Res.isInvalid()) { + SkipUntil(tok::r_paren); + return move(Res); + } + Comps.back().U.E = Res.release(); + + ST.consumeClose(); + Comps.back().LocEnd = ST.getCloseLocation(); + } else { + if (Tok.isNot(tok::r_paren)) { + PT.consumeClose(); + Res = ExprError(); + } else if (Ty.isInvalid()) { + Res = ExprError(); + } else { + PT.consumeClose(); + Res = Actions.ActOnBuiltinOffsetOf(getCurScope(), StartLoc, TypeLoc, + Ty.get(), &Comps[0], Comps.size(), + PT.getCloseLocation()); + } + break; + } + } + break; + } + case tok::kw___builtin_choose_expr: { + ExprResult Cond(ParseAssignmentExpression()); + if (Cond.isInvalid()) { + SkipUntil(tok::r_paren); + return move(Cond); + } + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) + return ExprError(); + + ExprResult Expr1(ParseAssignmentExpression()); + if (Expr1.isInvalid()) { + SkipUntil(tok::r_paren); + return move(Expr1); + } + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) + return ExprError(); + + ExprResult Expr2(ParseAssignmentExpression()); + if (Expr2.isInvalid()) { + SkipUntil(tok::r_paren); + return move(Expr2); + } + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + return ExprError(); + } + Res = Actions.ActOnChooseExpr(StartLoc, Cond.take(), Expr1.take(), + Expr2.take(), ConsumeParen()); + break; + } + case tok::kw___builtin_astype: { + // The first argument is an expression to be converted, followed by a comma. + ExprResult Expr(ParseAssignmentExpression()); + if (Expr.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", + tok::r_paren)) + return ExprError(); + + // Second argument is the type to bitcast to. + TypeResult DestTy = ParseTypeName(); + if (DestTy.isInvalid()) + return ExprError(); + + // Attempt to consume the r-paren. + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + SkipUntil(tok::r_paren); + return ExprError(); + } + + Res = Actions.ActOnAsTypeExpr(Expr.take(), DestTy.get(), StartLoc, + ConsumeParen()); + break; + } + } + + if (Res.isInvalid()) + return ExprError(); + + // These can be followed by postfix-expr pieces because they are + // primary-expressions. + return ParsePostfixExpressionSuffix(Res.take()); +} + +/// ParseParenExpression - This parses the unit that starts with a '(' token, +/// based on what is allowed by ExprType. The actual thing parsed is returned +/// in ExprType. If stopIfCastExpr is true, it will only return the parsed type, +/// not the parsed cast-expression. +/// +/// primary-expression: [C99 6.5.1] +/// '(' expression ')' +/// [GNU] '(' compound-statement ')' (if !ParenExprOnly) +/// postfix-expression: [C99 6.5.2] +/// '(' type-name ')' '{' initializer-list '}' +/// '(' type-name ')' '{' initializer-list ',' '}' +/// cast-expression: [C99 6.5.4] +/// '(' type-name ')' cast-expression +/// [ARC] bridged-cast-expression +/// +/// [ARC] bridged-cast-expression: +/// (__bridge type-name) cast-expression +/// (__bridge_transfer type-name) cast-expression +/// (__bridge_retained type-name) cast-expression +ExprResult +Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, + bool isTypeCast, ParsedType &CastTy, + SourceLocation &RParenLoc) { + assert(Tok.is(tok::l_paren) && "Not a paren expr!"); + GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) + return ExprError(); + SourceLocation OpenLoc = T.getOpenLocation(); + + ExprResult Result(true); + bool isAmbiguousTypeId; + CastTy = ParsedType(); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(getCurScope(), + ExprType >= CompoundLiteral? Sema::PCC_ParenthesizedExpression + : Sema::PCC_Expression); + cutOffParsing(); + return ExprError(); + } + + // Diagnose use of bridge casts in non-arc mode. + bool BridgeCast = (getLangOpts().ObjC2 && + (Tok.is(tok::kw___bridge) || + Tok.is(tok::kw___bridge_transfer) || + Tok.is(tok::kw___bridge_retained) || + Tok.is(tok::kw___bridge_retain))); + if (BridgeCast && !getLangOpts().ObjCAutoRefCount) { + StringRef BridgeCastName = Tok.getName(); + SourceLocation BridgeKeywordLoc = ConsumeToken(); + if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) + Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc) + << BridgeCastName + << FixItHint::CreateReplacement(BridgeKeywordLoc, ""); + BridgeCast = false; + } + + // None of these cases should fall through with an invalid Result + // unless they've already reported an error. + if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { + Diag(Tok, diag::ext_gnu_statement_expr); + Actions.ActOnStartStmtExpr(); + + StmtResult Stmt(ParseCompoundStatement(true)); + ExprType = CompoundStmt; + + // If the substmt parsed correctly, build the AST node. + if (!Stmt.isInvalid()) { + Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.take(), Tok.getLocation()); + } else { + Actions.ActOnStmtExprError(); + } + } else if (ExprType >= CompoundLiteral && BridgeCast) { + tok::TokenKind tokenKind = Tok.getKind(); + SourceLocation BridgeKeywordLoc = ConsumeToken(); + + // Parse an Objective-C ARC ownership cast expression. + ObjCBridgeCastKind Kind; + if (tokenKind == tok::kw___bridge) + Kind = OBC_Bridge; + else if (tokenKind == tok::kw___bridge_transfer) + Kind = OBC_BridgeTransfer; + else if (tokenKind == tok::kw___bridge_retained) + Kind = OBC_BridgeRetained; + else { + // As a hopefully temporary workaround, allow __bridge_retain as + // a synonym for __bridge_retained, but only in system headers. + assert(tokenKind == tok::kw___bridge_retain); + Kind = OBC_BridgeRetained; + if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) + Diag(BridgeKeywordLoc, diag::err_arc_bridge_retain) + << FixItHint::CreateReplacement(BridgeKeywordLoc, + "__bridge_retained"); + } + + TypeResult Ty = ParseTypeName(); + T.consumeClose(); + RParenLoc = T.getCloseLocation(); + ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false); + + if (Ty.isInvalid() || SubExpr.isInvalid()) + return ExprError(); + + return Actions.ActOnObjCBridgedCast(getCurScope(), OpenLoc, Kind, + BridgeKeywordLoc, Ty.get(), + RParenLoc, SubExpr.get()); + } else if (ExprType >= CompoundLiteral && + isTypeIdInParens(isAmbiguousTypeId)) { + + // Otherwise, this is a compound literal expression or cast expression. + + // In C++, if the type-id is ambiguous we disambiguate based on context. + // If stopIfCastExpr is true the context is a typeof/sizeof/alignof + // in which case we should treat it as type-id. + // if stopIfCastExpr is false, we need to determine the context past the + // parens, so we defer to ParseCXXAmbiguousParenExpression for that. + if (isAmbiguousTypeId && !stopIfCastExpr) { + ExprResult res = ParseCXXAmbiguousParenExpression(ExprType, CastTy, T); + RParenLoc = T.getCloseLocation(); + return res; + } + + // Parse the type declarator. + DeclSpec DS(AttrFactory); + ParseSpecifierQualifierList(DS); + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + ParseDeclarator(DeclaratorInfo); + + // If our type is followed by an identifier and either ':' or ']', then + // this is probably an Objective-C message send where the leading '[' is + // missing. Recover as if that were the case. + if (!DeclaratorInfo.isInvalidType() && Tok.is(tok::identifier) && + !InMessageExpression && getLangOpts().ObjC1 && + (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { + TypeResult Ty; + { + InMessageExpressionRAIIObject InMessage(*this, false); + Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); + } + Result = ParseObjCMessageExpressionBody(SourceLocation(), + SourceLocation(), + Ty.get(), 0); + } else { + // Match the ')'. + T.consumeClose(); + RParenLoc = T.getCloseLocation(); + if (Tok.is(tok::l_brace)) { + ExprType = CompoundLiteral; + TypeResult Ty; + { + InMessageExpressionRAIIObject InMessage(*this, false); + Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); + } + return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc); + } + + if (ExprType == CastExpr) { + // We parsed '(' type-name ')' and the thing after it wasn't a '{'. + + if (DeclaratorInfo.isInvalidType()) + return ExprError(); + + // Note that this doesn't parse the subsequent cast-expression, it just + // returns the parsed type to the callee. + if (stopIfCastExpr) { + TypeResult Ty; + { + InMessageExpressionRAIIObject InMessage(*this, false); + Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); + } + CastTy = Ty.get(); + return ExprResult(); + } + + // Reject the cast of super idiom in ObjC. + if (Tok.is(tok::identifier) && getLangOpts().ObjC1 && + Tok.getIdentifierInfo() == Ident_super && + getCurScope()->isInObjcMethodScope() && + GetLookAheadToken(1).isNot(tok::period)) { + Diag(Tok.getLocation(), diag::err_illegal_super_cast) + << SourceRange(OpenLoc, RParenLoc); + return ExprError(); + } + + // Parse the cast-expression that follows it next. + // TODO: For cast expression with CastTy. + Result = ParseCastExpression(/*isUnaryExpression=*/false, + /*isAddressOfOperand=*/false, + /*isTypeCast=*/IsTypeCast); + if (!Result.isInvalid()) { + Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, + DeclaratorInfo, CastTy, + RParenLoc, Result.take()); + } + return move(Result); + } + + Diag(Tok, diag::err_expected_lbrace_in_compound_literal); + return ExprError(); + } + } else if (isTypeCast) { + // Parse the expression-list. + InMessageExpressionRAIIObject InMessage(*this, false); + + ExprVector ArgExprs(Actions); + CommaLocsTy CommaLocs; + + if (!ParseExpressionList(ArgExprs, CommaLocs)) { + ExprType = SimpleExpr; + Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), + move_arg(ArgExprs)); + } + } else { + InMessageExpressionRAIIObject InMessage(*this, false); + + Result = ParseExpression(MaybeTypeCast); + ExprType = SimpleExpr; + + // Don't build a paren expression unless we actually match a ')'. + if (!Result.isInvalid() && Tok.is(tok::r_paren)) + Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.take()); + } + + // Match the ')'. + if (Result.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + T.consumeClose(); + RParenLoc = T.getCloseLocation(); + return move(Result); +} + +/// ParseCompoundLiteralExpression - We have parsed the parenthesized type-name +/// and we are at the left brace. +/// +/// postfix-expression: [C99 6.5.2] +/// '(' type-name ')' '{' initializer-list '}' +/// '(' type-name ')' '{' initializer-list ',' '}' +/// +ExprResult +Parser::ParseCompoundLiteralExpression(ParsedType Ty, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + assert(Tok.is(tok::l_brace) && "Not a compound literal!"); + if (!getLangOpts().C99) // Compound literals don't exist in C90. + Diag(LParenLoc, diag::ext_c99_compound_literal); + ExprResult Result = ParseInitializer(); + if (!Result.isInvalid() && Ty) + return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, Result.take()); + return move(Result); +} + +/// ParseStringLiteralExpression - This handles the various token types that +/// form string literals, and also handles string concatenation [C99 5.1.1.2, +/// translation phase #6]. +/// +/// primary-expression: [C99 6.5.1] +/// string-literal +ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) { + assert(isTokenStringLiteral() && "Not a string literal!"); + + // String concat. Note that keywords like __func__ and __FUNCTION__ are not + // considered to be strings for concatenation purposes. + SmallVector StringToks; + + do { + StringToks.push_back(Tok); + ConsumeStringToken(); + } while (isTokenStringLiteral()); + + // Pass the set of string tokens, ready for concatenation, to the actions. + return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size(), + AllowUserDefinedLiteral ? getCurScope() : 0); +} + +/// ParseGenericSelectionExpression - Parse a C11 generic-selection +/// [C11 6.5.1.1]. +/// +/// generic-selection: +/// _Generic ( assignment-expression , generic-assoc-list ) +/// generic-assoc-list: +/// generic-association +/// generic-assoc-list , generic-association +/// generic-association: +/// type-name : assignment-expression +/// default : assignment-expression +ExprResult Parser::ParseGenericSelectionExpression() { + assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected"); + SourceLocation KeyLoc = ConsumeToken(); + + if (!getLangOpts().C11) + Diag(KeyLoc, diag::ext_c11_generic_selection); + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) + return ExprError(); + + ExprResult ControllingExpr; + { + // C11 6.5.1.1p3 "The controlling expression of a generic selection is + // not evaluated." + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + ControllingExpr = ParseAssignmentExpression(); + if (ControllingExpr.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + } + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "")) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + SourceLocation DefaultLoc; + TypeVector Types(Actions); + ExprVector Exprs(Actions); + while (1) { + ParsedType Ty; + if (Tok.is(tok::kw_default)) { + // C11 6.5.1.1p2 "A generic selection shall have no more than one default + // generic association." + if (!DefaultLoc.isInvalid()) { + Diag(Tok, diag::err_duplicate_default_assoc); + Diag(DefaultLoc, diag::note_previous_default_assoc); + SkipUntil(tok::r_paren); + return ExprError(); + } + DefaultLoc = ConsumeToken(); + Ty = ParsedType(); + } else { + ColonProtectionRAIIObject X(*this); + TypeResult TR = ParseTypeName(); + if (TR.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + Ty = TR.release(); + } + Types.push_back(Ty); + + if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "")) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + // FIXME: These expressions should be parsed in a potentially potentially + // evaluated context. + ExprResult ER(ParseAssignmentExpression()); + if (ER.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + Exprs.push_back(ER.release()); + + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); + } + + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) + return ExprError(); + + return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, + T.getCloseLocation(), + ControllingExpr.release(), + move_arg(Types), move_arg(Exprs)); +} + +/// ParseExpressionList - Used for C/C++ (argument-)expression-list. +/// +/// argument-expression-list: +/// assignment-expression +/// argument-expression-list , assignment-expression +/// +/// [C++] expression-list: +/// [C++] assignment-expression +/// [C++] expression-list , assignment-expression +/// +/// [C++0x] expression-list: +/// [C++0x] initializer-list +/// +/// [C++0x] initializer-list +/// [C++0x] initializer-clause ...[opt] +/// [C++0x] initializer-list , initializer-clause ...[opt] +/// +/// [C++0x] initializer-clause: +/// [C++0x] assignment-expression +/// [C++0x] braced-init-list +/// +bool Parser::ParseExpressionList(SmallVectorImpl &Exprs, + SmallVectorImpl &CommaLocs, + void (Sema::*Completer)(Scope *S, + Expr *Data, + llvm::ArrayRef Args), + Expr *Data) { + while (1) { + if (Tok.is(tok::code_completion)) { + if (Completer) + (Actions.*Completer)(getCurScope(), Data, Exprs); + else + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); + cutOffParsing(); + return true; + } + + ExprResult Expr; + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + Expr = ParseBraceInitializer(); + } else + Expr = ParseAssignmentExpression(); + + if (Tok.is(tok::ellipsis)) + Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); + if (Expr.isInvalid()) + return true; + + Exprs.push_back(Expr.release()); + + if (Tok.isNot(tok::comma)) + return false; + // Move to the next argument, remember where the comma was. + CommaLocs.push_back(ConsumeToken()); + } +} + +/// ParseBlockId - Parse a block-id, which roughly looks like int (int x). +/// +/// [clang] block-id: +/// [clang] specifier-qualifier-list block-declarator +/// +void Parser::ParseBlockId() { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); + return cutOffParsing(); + } + + // Parse the specifier-qualifier-list piece. + DeclSpec DS(AttrFactory); + ParseSpecifierQualifierList(DS); + + // Parse the block-declarator. + Declarator DeclaratorInfo(DS, Declarator::BlockLiteralContext); + ParseDeclarator(DeclaratorInfo); + + // We do this for: ^ __attribute__((noreturn)) {, as DS has the attributes. + DeclaratorInfo.takeAttributes(DS.getAttributes(), SourceLocation()); + + MaybeParseGNUAttributes(DeclaratorInfo); + + // Inform sema that we are starting a block. + Actions.ActOnBlockArguments(DeclaratorInfo, getCurScope()); +} + +/// ParseBlockLiteralExpression - Parse a block literal, which roughly looks +/// like ^(int x){ return x+1; } +/// +/// block-literal: +/// [clang] '^' block-args[opt] compound-statement +/// [clang] '^' block-id compound-statement +/// [clang] block-args: +/// [clang] '(' parameter-list ')' +/// +ExprResult Parser::ParseBlockLiteralExpression() { + assert(Tok.is(tok::caret) && "block literal starts with ^"); + SourceLocation CaretLoc = ConsumeToken(); + + PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), CaretLoc, + "block literal parsing"); + + // Enter a scope to hold everything within the block. This includes the + // argument decls, decls within the compound expression, etc. This also + // allows determining whether a variable reference inside the block is + // within or outside of the block. + ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope | + Scope::DeclScope); + + // Inform sema that we are starting a block. + Actions.ActOnBlockStart(CaretLoc, getCurScope()); + + // Parse the return type if present. + DeclSpec DS(AttrFactory); + Declarator ParamInfo(DS, Declarator::BlockLiteralContext); + // FIXME: Since the return type isn't actually parsed, it can't be used to + // fill ParamInfo with an initial valid range, so do it manually. + ParamInfo.SetSourceRange(SourceRange(Tok.getLocation(), Tok.getLocation())); + + // If this block has arguments, parse them. There is no ambiguity here with + // the expression case, because the expression case requires a parameter list. + if (Tok.is(tok::l_paren)) { + ParseParenDeclarator(ParamInfo); + // Parse the pieces after the identifier as if we had "int(...)". + // SetIdentifier sets the source range end, but in this case we're past + // that location. + SourceLocation Tmp = ParamInfo.getSourceRange().getEnd(); + ParamInfo.SetIdentifier(0, CaretLoc); + ParamInfo.SetRangeEnd(Tmp); + if (ParamInfo.isInvalidType()) { + // If there was an error parsing the arguments, they may have + // tried to use ^(x+y) which requires an argument list. Just + // skip the whole block literal. + Actions.ActOnBlockError(CaretLoc, getCurScope()); + return ExprError(); + } + + MaybeParseGNUAttributes(ParamInfo); + + // Inform sema that we are starting a block. + Actions.ActOnBlockArguments(ParamInfo, getCurScope()); + } else if (!Tok.is(tok::l_brace)) { + ParseBlockId(); + } else { + // Otherwise, pretend we saw (void). + ParsedAttributes attrs(AttrFactory); + ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, + SourceLocation(), + 0, 0, 0, + true, SourceLocation(), + SourceLocation(), + SourceLocation(), + SourceLocation(), + EST_None, + SourceLocation(), + 0, 0, 0, 0, + CaretLoc, CaretLoc, + ParamInfo), + attrs, CaretLoc); + + MaybeParseGNUAttributes(ParamInfo); + + // Inform sema that we are starting a block. + Actions.ActOnBlockArguments(ParamInfo, getCurScope()); + } + + + ExprResult Result(true); + if (!Tok.is(tok::l_brace)) { + // Saw something like: ^expr + Diag(Tok, diag::err_expected_expression); + Actions.ActOnBlockError(CaretLoc, getCurScope()); + return ExprError(); + } + + StmtResult Stmt(ParseCompoundStatementBody()); + BlockScope.Exit(); + if (!Stmt.isInvalid()) + Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.take(), getCurScope()); + else + Actions.ActOnBlockError(CaretLoc, getCurScope()); + return move(Result); +} + +/// ParseObjCBoolLiteral - This handles the objective-c Boolean literals. +/// +/// '__objc_yes' +/// '__objc_no' +ExprResult Parser::ParseObjCBoolLiteral() { + tok::TokenKind Kind = Tok.getKind(); + return Actions.ActOnObjCBoolLiteral(ConsumeToken(), Kind); +} diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp new file mode 100644 index 0000000..7152184 --- /dev/null +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -0,0 +1,2846 @@ +//===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Expression parsing implementation for C++. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "RAIIObjectsForParser.h" +#include "clang/Basic/PrettyStackTrace.h" +#include "clang/Lex/LiteralSupport.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ParsedTemplate.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; + +static int SelectDigraphErrorMessage(tok::TokenKind Kind) { + switch (Kind) { + case tok::kw_template: return 0; + case tok::kw_const_cast: return 1; + case tok::kw_dynamic_cast: return 2; + case tok::kw_reinterpret_cast: return 3; + case tok::kw_static_cast: return 4; + default: + llvm_unreachable("Unknown type for digraph error message."); + } +} + +// Are the two tokens adjacent in the same source file? +static bool AreTokensAdjacent(Preprocessor &PP, Token &First, Token &Second) { + SourceManager &SM = PP.getSourceManager(); + SourceLocation FirstLoc = SM.getSpellingLoc(First.getLocation()); + SourceLocation FirstEnd = FirstLoc.getLocWithOffset(First.getLength()); + return FirstEnd == SM.getSpellingLoc(Second.getLocation()); +} + +// Suggest fixit for "<::" after a cast. +static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken, + Token &ColonToken, tok::TokenKind Kind, bool AtDigraph) { + // Pull '<:' and ':' off token stream. + if (!AtDigraph) + PP.Lex(DigraphToken); + PP.Lex(ColonToken); + + SourceRange Range; + Range.setBegin(DigraphToken.getLocation()); + Range.setEnd(ColonToken.getLocation()); + P.Diag(DigraphToken.getLocation(), diag::err_missing_whitespace_digraph) + << SelectDigraphErrorMessage(Kind) + << FixItHint::CreateReplacement(Range, "< ::"); + + // Update token information to reflect their change in token type. + ColonToken.setKind(tok::coloncolon); + ColonToken.setLocation(ColonToken.getLocation().getLocWithOffset(-1)); + ColonToken.setLength(2); + DigraphToken.setKind(tok::less); + DigraphToken.setLength(1); + + // Push new tokens back to token stream. + PP.EnterToken(ColonToken); + if (!AtDigraph) + PP.EnterToken(DigraphToken); +} + +// Check for '<::' which should be '< ::' instead of '[:' when following +// a template name. +void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, + bool EnteringContext, + IdentifierInfo &II, CXXScopeSpec &SS) { + if (!Next.is(tok::l_square) || Next.getLength() != 2) + return; + + Token SecondToken = GetLookAheadToken(2); + if (!SecondToken.is(tok::colon) || !AreTokensAdjacent(PP, Next, SecondToken)) + return; + + TemplateTy Template; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(&II, Tok.getLocation()); + bool MemberOfUnknownSpecialization; + if (!Actions.isTemplateName(getCurScope(), SS, /*hasTemplateKeyword=*/false, + TemplateName, ObjectType, EnteringContext, + Template, MemberOfUnknownSpecialization)) + return; + + FixDigraph(*this, PP, Next, SecondToken, tok::kw_template, + /*AtDigraph*/false); +} + +/// \brief Parse global scope or nested-name-specifier if present. +/// +/// Parses a C++ global scope specifier ('::') or nested-name-specifier (which +/// may be preceded by '::'). Note that this routine will not parse ::new or +/// ::delete; it will just leave them in the token stream. +/// +/// '::'[opt] nested-name-specifier +/// '::' +/// +/// nested-name-specifier: +/// type-name '::' +/// namespace-name '::' +/// nested-name-specifier identifier '::' +/// nested-name-specifier 'template'[opt] simple-template-id '::' +/// +/// +/// \param SS the scope specifier that will be set to the parsed +/// nested-name-specifier (or empty) +/// +/// \param ObjectType if this nested-name-specifier is being parsed following +/// the "." or "->" of a member access expression, this parameter provides the +/// type of the object whose members are being accessed. +/// +/// \param EnteringContext whether we will be entering into the context of +/// the nested-name-specifier after parsing it. +/// +/// \param MayBePseudoDestructor When non-NULL, points to a flag that +/// indicates whether this nested-name-specifier may be part of a +/// pseudo-destructor name. In this case, the flag will be set false +/// if we don't actually end up parsing a destructor name. Moreorover, +/// if we do end up determining that we are parsing a destructor name, +/// the last component of the nested-name-specifier is not parsed as +/// part of the scope specifier. + +/// member access expression, e.g., the \p T:: in \p p->T::m. +/// +/// \returns true if there was an error parsing a scope specifier +bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, + ParsedType ObjectType, + bool EnteringContext, + bool *MayBePseudoDestructor, + bool IsTypename) { + assert(getLangOpts().CPlusPlus && + "Call sites of this function should be guarded by checking for C++"); + + if (Tok.is(tok::annot_cxxscope)) { + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); + ConsumeToken(); + return false; + } + + bool HasScopeSpecifier = false; + + if (Tok.is(tok::coloncolon)) { + // ::new and ::delete aren't nested-name-specifiers. + tok::TokenKind NextKind = NextToken().getKind(); + if (NextKind == tok::kw_new || NextKind == tok::kw_delete) + return false; + + // '::' - Global scope qualifier. + if (Actions.ActOnCXXGlobalScopeSpecifier(getCurScope(), ConsumeToken(), SS)) + return true; + + HasScopeSpecifier = true; + } + + bool CheckForDestructor = false; + if (MayBePseudoDestructor && *MayBePseudoDestructor) { + CheckForDestructor = true; + *MayBePseudoDestructor = false; + } + + if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) { + DeclSpec DS(AttrFactory); + SourceLocation DeclLoc = Tok.getLocation(); + SourceLocation EndLoc = ParseDecltypeSpecifier(DS); + if (Tok.isNot(tok::coloncolon)) { + AnnotateExistingDecltypeSpecifier(DS, DeclLoc, EndLoc); + return false; + } + + SourceLocation CCLoc = ConsumeToken(); + if (Actions.ActOnCXXNestedNameSpecifierDecltype(SS, DS, CCLoc)) + SS.SetInvalid(SourceRange(DeclLoc, CCLoc)); + + HasScopeSpecifier = true; + } + + while (true) { + if (HasScopeSpecifier) { + // C++ [basic.lookup.classref]p5: + // If the qualified-id has the form + // + // ::class-name-or-namespace-name::... + // + // the class-name-or-namespace-name is looked up in global scope as a + // class-name or namespace-name. + // + // To implement this, we clear out the object type as soon as we've + // seen a leading '::' or part of a nested-name-specifier. + ObjectType = ParsedType(); + + if (Tok.is(tok::code_completion)) { + // Code completion for a nested-name-specifier, where the code + // code completion token follows the '::'. + Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext); + // Include code completion token into the range of the scope otherwise + // when we try to annotate the scope tokens the dangling code completion + // token will cause assertion in + // Preprocessor::AnnotatePreviousCachedTokens. + SS.setEndLoc(Tok.getLocation()); + cutOffParsing(); + return true; + } + } + + // nested-name-specifier: + // nested-name-specifier 'template'[opt] simple-template-id '::' + + // Parse the optional 'template' keyword, then make sure we have + // 'identifier <' after it. + if (Tok.is(tok::kw_template)) { + // If we don't have a scope specifier or an object type, this isn't a + // nested-name-specifier, since they aren't allowed to start with + // 'template'. + if (!HasScopeSpecifier && !ObjectType) + break; + + TentativeParsingAction TPA(*this); + SourceLocation TemplateKWLoc = ConsumeToken(); + + UnqualifiedId TemplateName; + if (Tok.is(tok::identifier)) { + // Consume the identifier. + TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); + } else if (Tok.is(tok::kw_operator)) { + if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, + TemplateName)) { + TPA.Commit(); + break; + } + + if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId && + TemplateName.getKind() != UnqualifiedId::IK_LiteralOperatorId) { + Diag(TemplateName.getSourceRange().getBegin(), + diag::err_id_after_template_in_nested_name_spec) + << TemplateName.getSourceRange(); + TPA.Commit(); + break; + } + } else { + TPA.Revert(); + break; + } + + // If the next token is not '<', we have a qualified-id that refers + // to a template name, such as T::template apply, but is not a + // template-id. + if (Tok.isNot(tok::less)) { + TPA.Revert(); + break; + } + + // Commit to parsing the template-id. + TPA.Commit(); + TemplateTy Template; + if (TemplateNameKind TNK + = Actions.ActOnDependentTemplateName(getCurScope(), + SS, TemplateKWLoc, TemplateName, + ObjectType, EnteringContext, + Template)) { + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc, + TemplateName, false)) + return true; + } else + return true; + + continue; + } + + if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) { + // We have + // + // simple-template-id '::' + // + // So we need to check whether the simple-template-id is of the + // right kind (it should name a type or be dependent), and then + // convert it into a type within the nested-name-specifier. + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { + *MayBePseudoDestructor = true; + return false; + } + + // Consume the template-id token. + ConsumeToken(); + + assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); + SourceLocation CCLoc = ConsumeToken(); + + HasScopeSpecifier = true; + + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + + if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), + SS, + TemplateId->TemplateKWLoc, + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc, + CCLoc, + EnteringContext)) { + SourceLocation StartLoc + = SS.getBeginLoc().isValid()? SS.getBeginLoc() + : TemplateId->TemplateNameLoc; + SS.SetInvalid(SourceRange(StartLoc, CCLoc)); + } + + continue; + } + + + // The rest of the nested-name-specifier possibilities start with + // tok::identifier. + if (Tok.isNot(tok::identifier)) + break; + + IdentifierInfo &II = *Tok.getIdentifierInfo(); + + // nested-name-specifier: + // type-name '::' + // namespace-name '::' + // nested-name-specifier identifier '::' + Token Next = NextToken(); + + // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover + // and emit a fixit hint for it. + if (Next.is(tok::colon) && !ColonIsSacred) { + if (Actions.IsInvalidUnlessNestedName(getCurScope(), SS, II, + Tok.getLocation(), + Next.getLocation(), ObjectType, + EnteringContext) && + // If the token after the colon isn't an identifier, it's still an + // error, but they probably meant something else strange so don't + // recover like this. + PP.LookAhead(1).is(tok::identifier)) { + Diag(Next, diag::err_unexected_colon_in_nested_name_spec) + << FixItHint::CreateReplacement(Next.getLocation(), "::"); + + // Recover as if the user wrote '::'. + Next.setKind(tok::coloncolon); + } + } + + if (Next.is(tok::coloncolon)) { + if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) && + !Actions.isNonTypeNestedNameSpecifier(getCurScope(), SS, Tok.getLocation(), + II, ObjectType)) { + *MayBePseudoDestructor = true; + return false; + } + + // We have an identifier followed by a '::'. Lookup this name + // as the name in a nested-name-specifier. + SourceLocation IdLoc = ConsumeToken(); + assert((Tok.is(tok::coloncolon) || Tok.is(tok::colon)) && + "NextToken() not working properly!"); + SourceLocation CCLoc = ConsumeToken(); + + HasScopeSpecifier = true; + if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc, + ObjectType, EnteringContext, SS)) + SS.SetInvalid(SourceRange(IdLoc, CCLoc)); + + continue; + } + + CheckForTemplateAndDigraph(Next, ObjectType, EnteringContext, II, SS); + + // nested-name-specifier: + // type-name '<' + if (Next.is(tok::less)) { + TemplateTy Template; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(&II, Tok.getLocation()); + bool MemberOfUnknownSpecialization; + if (TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, + TemplateName, + ObjectType, + EnteringContext, + Template, + MemberOfUnknownSpecialization)) { + // We have found a template name, so annotate this token + // with a template-id annotation. We do not permit the + // template-id to be translated into a type annotation, + // because some clients (e.g., the parsing of class template + // specializations) still want to see the original template-id + // token. + ConsumeToken(); + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName, false)) + return true; + continue; + } + + if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && + (IsTypename || IsTemplateArgumentList(1))) { + // We have something like t::getAs, where getAs is a + // member of an unknown specialization. However, this will only + // parse correctly as a template, so suggest the keyword 'template' + // before 'getAs' and treat this as a dependent template name. + unsigned DiagID = diag::err_missing_dependent_template_keyword; + if (getLangOpts().MicrosoftExt) + DiagID = diag::warn_missing_dependent_template_keyword; + + Diag(Tok.getLocation(), DiagID) + << II.getName() + << FixItHint::CreateInsertion(Tok.getLocation(), "template "); + + if (TemplateNameKind TNK + = Actions.ActOnDependentTemplateName(getCurScope(), + SS, SourceLocation(), + TemplateName, ObjectType, + EnteringContext, Template)) { + // Consume the identifier. + ConsumeToken(); + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName, false)) + return true; + } + else + return true; + + continue; + } + } + + // We don't have any tokens that form the beginning of a + // nested-name-specifier, so we're done. + break; + } + + // Even if we didn't see any pieces of a nested-name-specifier, we + // still check whether there is a tilde in this position, which + // indicates a potential pseudo-destructor. + if (CheckForDestructor && Tok.is(tok::tilde)) + *MayBePseudoDestructor = true; + + return false; +} + +/// ParseCXXIdExpression - Handle id-expression. +/// +/// id-expression: +/// unqualified-id +/// qualified-id +/// +/// qualified-id: +/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id +/// '::' identifier +/// '::' operator-function-id +/// '::' template-id +/// +/// NOTE: The standard specifies that, for qualified-id, the parser does not +/// expect: +/// +/// '::' conversion-function-id +/// '::' '~' class-name +/// +/// This may cause a slight inconsistency on diagnostics: +/// +/// class C {}; +/// namespace A {} +/// void f() { +/// :: A :: ~ C(); // Some Sema error about using destructor with a +/// // namespace. +/// :: ~ C(); // Some Parser error like 'unexpected ~'. +/// } +/// +/// We simplify the parser a bit and make it work like: +/// +/// qualified-id: +/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id +/// '::' unqualified-id +/// +/// That way Sema can handle and report similar errors for namespaces and the +/// global scope. +/// +/// The isAddressOfOperand parameter indicates that this id-expression is a +/// direct operand of the address-of operator. This is, besides member contexts, +/// the only place where a qualified-id naming a non-static class member may +/// appear. +/// +ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { + // qualified-id: + // '::'[opt] nested-name-specifier 'template'[opt] unqualified-id + // '::' unqualified-id + // + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + + SourceLocation TemplateKWLoc; + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/false, + /*AllowConstructorName=*/false, + /*ObjectType=*/ ParsedType(), + TemplateKWLoc, + Name)) + return ExprError(); + + // This is only the direct operand of an & operator if it is not + // followed by a postfix-expression suffix. + if (isAddressOfOperand && isPostfixExpressionSuffixStart()) + isAddressOfOperand = false; + + return Actions.ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Name, + Tok.is(tok::l_paren), isAddressOfOperand); +} + +/// ParseLambdaExpression - Parse a C++0x lambda expression. +/// +/// lambda-expression: +/// lambda-introducer lambda-declarator[opt] compound-statement +/// +/// lambda-introducer: +/// '[' lambda-capture[opt] ']' +/// +/// lambda-capture: +/// capture-default +/// capture-list +/// capture-default ',' capture-list +/// +/// capture-default: +/// '&' +/// '=' +/// +/// capture-list: +/// capture +/// capture-list ',' capture +/// +/// capture: +/// identifier +/// '&' identifier +/// 'this' +/// +/// lambda-declarator: +/// '(' parameter-declaration-clause ')' attribute-specifier[opt] +/// 'mutable'[opt] exception-specification[opt] +/// trailing-return-type[opt] +/// +ExprResult Parser::ParseLambdaExpression() { + // Parse lambda-introducer. + LambdaIntroducer Intro; + + llvm::Optional DiagID(ParseLambdaIntroducer(Intro)); + if (DiagID) { + Diag(Tok, DiagID.getValue()); + SkipUntil(tok::r_square); + SkipUntil(tok::l_brace); + SkipUntil(tok::r_brace); + return ExprError(); + } + + return ParseLambdaExpressionAfterIntroducer(Intro); +} + +/// TryParseLambdaExpression - Use lookahead and potentially tentative +/// parsing to determine if we are looking at a C++0x lambda expression, and parse +/// it if we are. +/// +/// If we are not looking at a lambda expression, returns ExprError(). +ExprResult Parser::TryParseLambdaExpression() { + assert(getLangOpts().CPlusPlus0x + && Tok.is(tok::l_square) + && "Not at the start of a possible lambda expression."); + + const Token Next = NextToken(), After = GetLookAheadToken(2); + + // If lookahead indicates this is a lambda... + if (Next.is(tok::r_square) || // [] + Next.is(tok::equal) || // [= + (Next.is(tok::amp) && // [&] or [&, + (After.is(tok::r_square) || + After.is(tok::comma))) || + (Next.is(tok::identifier) && // [identifier] + After.is(tok::r_square))) { + return ParseLambdaExpression(); + } + + // If lookahead indicates an ObjC message send... + // [identifier identifier + if (Next.is(tok::identifier) && After.is(tok::identifier)) { + return ExprEmpty(); + } + + // Here, we're stuck: lambda introducers and Objective-C message sends are + // unambiguous, but it requires arbitrary lookhead. [a,b,c,d,e,f,g] is a + // lambda, and [a,b,c,d,e,f,g h] is a Objective-C message send. Instead of + // writing two routines to parse a lambda introducer, just try to parse + // a lambda introducer first, and fall back if that fails. + // (TryParseLambdaIntroducer never produces any diagnostic output.) + LambdaIntroducer Intro; + if (TryParseLambdaIntroducer(Intro)) + return ExprEmpty(); + return ParseLambdaExpressionAfterIntroducer(Intro); +} + +/// ParseLambdaExpression - Parse a lambda introducer. +/// +/// Returns a DiagnosticID if it hit something unexpected. +llvm::Optional Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro){ + typedef llvm::Optional DiagResult; + + assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['."); + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + + Intro.Range.setBegin(T.getOpenLocation()); + + bool first = true; + + // Parse capture-default. + if (Tok.is(tok::amp) && + (NextToken().is(tok::comma) || NextToken().is(tok::r_square))) { + Intro.Default = LCD_ByRef; + Intro.DefaultLoc = ConsumeToken(); + first = false; + } else if (Tok.is(tok::equal)) { + Intro.Default = LCD_ByCopy; + Intro.DefaultLoc = ConsumeToken(); + first = false; + } + + while (Tok.isNot(tok::r_square)) { + if (!first) { + if (Tok.isNot(tok::comma)) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, + /*AfterAmpersand=*/false); + ConsumeCodeCompletionToken(); + break; + } + + return DiagResult(diag::err_expected_comma_or_rsquare); + } + ConsumeToken(); + } + + if (Tok.is(tok::code_completion)) { + // If we're in Objective-C++ and we have a bare '[', then this is more + // likely to be a message receiver. + if (getLangOpts().ObjC1 && first) + Actions.CodeCompleteObjCMessageReceiver(getCurScope()); + else + Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, + /*AfterAmpersand=*/false); + ConsumeCodeCompletionToken(); + break; + } + + first = false; + + // Parse capture. + LambdaCaptureKind Kind = LCK_ByCopy; + SourceLocation Loc; + IdentifierInfo* Id = 0; + SourceLocation EllipsisLoc; + + if (Tok.is(tok::kw_this)) { + Kind = LCK_This; + Loc = ConsumeToken(); + } else { + if (Tok.is(tok::amp)) { + Kind = LCK_ByRef; + ConsumeToken(); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, + /*AfterAmpersand=*/true); + ConsumeCodeCompletionToken(); + break; + } + } + + if (Tok.is(tok::identifier)) { + Id = Tok.getIdentifierInfo(); + Loc = ConsumeToken(); + + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + } else if (Tok.is(tok::kw_this)) { + // FIXME: If we want to suggest a fixit here, will need to return more + // than just DiagnosticID. Perhaps full DiagnosticBuilder that can be + // Clear()ed to prevent emission in case of tentative parsing? + return DiagResult(diag::err_this_captured_by_reference); + } else { + return DiagResult(diag::err_expected_capture); + } + } + + Intro.addCapture(Kind, Loc, Id, EllipsisLoc); + } + + T.consumeClose(); + Intro.Range.setEnd(T.getCloseLocation()); + + return DiagResult(); +} + +/// TryParseLambdaIntroducer - Tentatively parse a lambda introducer. +/// +/// Returns true if it hit something unexpected. +bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) { + TentativeParsingAction PA(*this); + + llvm::Optional DiagID(ParseLambdaIntroducer(Intro)); + + if (DiagID) { + PA.Revert(); + return true; + } + + PA.Commit(); + return false; +} + +/// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda +/// expression. +ExprResult Parser::ParseLambdaExpressionAfterIntroducer( + LambdaIntroducer &Intro) { + SourceLocation LambdaBeginLoc = Intro.Range.getBegin(); + Diag(LambdaBeginLoc, diag::warn_cxx98_compat_lambda); + + PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc, + "lambda expression parsing"); + + // Parse lambda-declarator[opt]. + DeclSpec DS(AttrFactory); + Declarator D(DS, Declarator::LambdaExprContext); + + if (Tok.is(tok::l_paren)) { + ParseScope PrototypeScope(this, + Scope::FunctionPrototypeScope | + Scope::DeclScope); + + SourceLocation DeclLoc, DeclEndLoc; + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + DeclLoc = T.getOpenLocation(); + + // Parse parameter-declaration-clause. + ParsedAttributes Attr(AttrFactory); + llvm::SmallVector ParamInfo; + SourceLocation EllipsisLoc; + + if (Tok.isNot(tok::r_paren)) + ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc); + + T.consumeClose(); + DeclEndLoc = T.getCloseLocation(); + + // Parse 'mutable'[opt]. + SourceLocation MutableLoc; + if (Tok.is(tok::kw_mutable)) { + MutableLoc = ConsumeToken(); + DeclEndLoc = MutableLoc; + } + + // Parse exception-specification[opt]. + ExceptionSpecificationType ESpecType = EST_None; + SourceRange ESpecRange; + llvm::SmallVector DynamicExceptions; + llvm::SmallVector DynamicExceptionRanges; + ExprResult NoexceptExpr; + ESpecType = tryParseExceptionSpecification(ESpecRange, + DynamicExceptions, + DynamicExceptionRanges, + NoexceptExpr); + + if (ESpecType != EST_None) + DeclEndLoc = ESpecRange.getEnd(); + + // Parse attribute-specifier[opt]. + MaybeParseCXX0XAttributes(Attr, &DeclEndLoc); + + // Parse trailing-return-type[opt]. + ParsedType TrailingReturnType; + if (Tok.is(tok::arrow)) { + SourceRange Range; + TrailingReturnType = ParseTrailingReturnType(Range).get(); + if (Range.getEnd().isValid()) + DeclEndLoc = Range.getEnd(); + } + + PrototypeScope.Exit(); + + D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, + /*isVariadic=*/EllipsisLoc.isValid(), + EllipsisLoc, + ParamInfo.data(), ParamInfo.size(), + DS.getTypeQualifiers(), + /*RefQualifierIsLValueRef=*/true, + /*RefQualifierLoc=*/SourceLocation(), + /*ConstQualifierLoc=*/SourceLocation(), + /*VolatileQualifierLoc=*/SourceLocation(), + MutableLoc, + ESpecType, ESpecRange.getBegin(), + DynamicExceptions.data(), + DynamicExceptionRanges.data(), + DynamicExceptions.size(), + NoexceptExpr.isUsable() ? + NoexceptExpr.get() : 0, + DeclLoc, DeclEndLoc, D, + TrailingReturnType), + Attr, DeclEndLoc); + } else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow)) { + // It's common to forget that one needs '()' before 'mutable' or the + // result type. Deal with this. + Diag(Tok, diag::err_lambda_missing_parens) + << Tok.is(tok::arrow) + << FixItHint::CreateInsertion(Tok.getLocation(), "() "); + SourceLocation DeclLoc = Tok.getLocation(); + SourceLocation DeclEndLoc = DeclLoc; + + // Parse 'mutable', if it's there. + SourceLocation MutableLoc; + if (Tok.is(tok::kw_mutable)) { + MutableLoc = ConsumeToken(); + DeclEndLoc = MutableLoc; + } + + // Parse the return type, if there is one. + ParsedType TrailingReturnType; + if (Tok.is(tok::arrow)) { + SourceRange Range; + TrailingReturnType = ParseTrailingReturnType(Range).get(); + if (Range.getEnd().isValid()) + DeclEndLoc = Range.getEnd(); + } + + ParsedAttributes Attr(AttrFactory); + D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, + /*isVariadic=*/false, + /*EllipsisLoc=*/SourceLocation(), + /*Params=*/0, /*NumParams=*/0, + /*TypeQuals=*/0, + /*RefQualifierIsLValueRef=*/true, + /*RefQualifierLoc=*/SourceLocation(), + /*ConstQualifierLoc=*/SourceLocation(), + /*VolatileQualifierLoc=*/SourceLocation(), + MutableLoc, + EST_None, + /*ESpecLoc=*/SourceLocation(), + /*Exceptions=*/0, + /*ExceptionRanges=*/0, + /*NumExceptions=*/0, + /*NoexceptExpr=*/0, + DeclLoc, DeclEndLoc, D, + TrailingReturnType), + Attr, DeclEndLoc); + } + + + // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using + // it. + unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope; + ParseScope BodyScope(this, ScopeFlags); + + Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope()); + + // Parse compound-statement. + if (!Tok.is(tok::l_brace)) { + Diag(Tok, diag::err_expected_lambda_body); + Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); + return ExprError(); + } + + StmtResult Stmt(ParseCompoundStatementBody()); + BodyScope.Exit(); + + if (!Stmt.isInvalid()) + return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.take(), getCurScope()); + + Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); + return ExprError(); +} + +/// ParseCXXCasts - This handles the various ways to cast expressions to another +/// type. +/// +/// postfix-expression: [C++ 5.2p1] +/// 'dynamic_cast' '<' type-name '>' '(' expression ')' +/// 'static_cast' '<' type-name '>' '(' expression ')' +/// 'reinterpret_cast' '<' type-name '>' '(' expression ')' +/// 'const_cast' '<' type-name '>' '(' expression ')' +/// +ExprResult Parser::ParseCXXCasts() { + tok::TokenKind Kind = Tok.getKind(); + const char *CastName = 0; // For error messages + + switch (Kind) { + default: llvm_unreachable("Unknown C++ cast!"); + case tok::kw_const_cast: CastName = "const_cast"; break; + case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break; + case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break; + case tok::kw_static_cast: CastName = "static_cast"; break; + } + + SourceLocation OpLoc = ConsumeToken(); + SourceLocation LAngleBracketLoc = Tok.getLocation(); + + // Check for "<::" which is parsed as "[:". If found, fix token stream, + // diagnose error, suggest fix, and recover parsing. + Token Next = NextToken(); + if (Tok.is(tok::l_square) && Tok.getLength() == 2 && Next.is(tok::colon) && + AreTokensAdjacent(PP, Tok, Next)) + FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true); + + if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName)) + return ExprError(); + + // Parse the common declaration-specifiers piece. + DeclSpec DS(AttrFactory); + ParseSpecifierQualifierList(DS); + + // Parse the abstract-declarator, if present. + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + ParseDeclarator(DeclaratorInfo); + + SourceLocation RAngleBracketLoc = Tok.getLocation(); + + if (ExpectAndConsume(tok::greater, diag::err_expected_greater)) + return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << "<"); + + SourceLocation LParenLoc, RParenLoc; + BalancedDelimiterTracker T(*this, tok::l_paren); + + if (T.expectAndConsume(diag::err_expected_lparen_after, CastName)) + return ExprError(); + + ExprResult Result = ParseExpression(); + + // Match the ')'. + T.consumeClose(); + + if (!Result.isInvalid() && !DeclaratorInfo.isInvalidType()) + Result = Actions.ActOnCXXNamedCast(OpLoc, Kind, + LAngleBracketLoc, DeclaratorInfo, + RAngleBracketLoc, + T.getOpenLocation(), Result.take(), + T.getCloseLocation()); + + return move(Result); +} + +/// ParseCXXTypeid - This handles the C++ typeid expression. +/// +/// postfix-expression: [C++ 5.2p1] +/// 'typeid' '(' expression ')' +/// 'typeid' '(' type-id ')' +/// +ExprResult Parser::ParseCXXTypeid() { + assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!"); + + SourceLocation OpLoc = ConsumeToken(); + SourceLocation LParenLoc, RParenLoc; + BalancedDelimiterTracker T(*this, tok::l_paren); + + // typeid expressions are always parenthesized. + if (T.expectAndConsume(diag::err_expected_lparen_after, "typeid")) + return ExprError(); + LParenLoc = T.getOpenLocation(); + + ExprResult Result; + + if (isTypeIdInParens()) { + TypeResult Ty = ParseTypeName(); + + // Match the ')'. + T.consumeClose(); + RParenLoc = T.getCloseLocation(); + if (Ty.isInvalid() || RParenLoc.isInvalid()) + return ExprError(); + + Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true, + Ty.get().getAsOpaquePtr(), RParenLoc); + } else { + // C++0x [expr.typeid]p3: + // When typeid is applied to an expression other than an lvalue of a + // polymorphic class type [...] The expression is an unevaluated + // operand (Clause 5). + // + // Note that we can't tell whether the expression is an lvalue of a + // polymorphic class type until after we've parsed the expression; we + // speculatively assume the subexpression is unevaluated, and fix it up + // later. + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + Result = ParseExpression(); + + // Match the ')'. + if (Result.isInvalid()) + SkipUntil(tok::r_paren); + else { + T.consumeClose(); + RParenLoc = T.getCloseLocation(); + if (RParenLoc.isInvalid()) + return ExprError(); + + Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false, + Result.release(), RParenLoc); + } + } + + return move(Result); +} + +/// ParseCXXUuidof - This handles the Microsoft C++ __uuidof expression. +/// +/// '__uuidof' '(' expression ')' +/// '__uuidof' '(' type-id ')' +/// +ExprResult Parser::ParseCXXUuidof() { + assert(Tok.is(tok::kw___uuidof) && "Not '__uuidof'!"); + + SourceLocation OpLoc = ConsumeToken(); + BalancedDelimiterTracker T(*this, tok::l_paren); + + // __uuidof expressions are always parenthesized. + if (T.expectAndConsume(diag::err_expected_lparen_after, "__uuidof")) + return ExprError(); + + ExprResult Result; + + if (isTypeIdInParens()) { + TypeResult Ty = ParseTypeName(); + + // Match the ')'. + T.consumeClose(); + + if (Ty.isInvalid()) + return ExprError(); + + Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(), /*isType=*/true, + Ty.get().getAsOpaquePtr(), + T.getCloseLocation()); + } else { + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + Result = ParseExpression(); + + // Match the ')'. + if (Result.isInvalid()) + SkipUntil(tok::r_paren); + else { + T.consumeClose(); + + Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(), + /*isType=*/false, + Result.release(), T.getCloseLocation()); + } + } + + return move(Result); +} + +/// \brief Parse a C++ pseudo-destructor expression after the base, +/// . or -> operator, and nested-name-specifier have already been +/// parsed. +/// +/// postfix-expression: [C++ 5.2] +/// postfix-expression . pseudo-destructor-name +/// postfix-expression -> pseudo-destructor-name +/// +/// pseudo-destructor-name: +/// ::[opt] nested-name-specifier[opt] type-name :: ~type-name +/// ::[opt] nested-name-specifier template simple-template-id :: +/// ~type-name +/// ::[opt] nested-name-specifier[opt] ~type-name +/// +ExprResult +Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + ParsedType ObjectType) { + // We're parsing either a pseudo-destructor-name or a dependent + // member access that has the same form as a + // pseudo-destructor-name. We parse both in the same way and let + // the action model sort them out. + // + // Note that the ::[opt] nested-name-specifier[opt] has already + // been parsed, and if there was a simple-template-id, it has + // been coalesced into a template-id annotation token. + UnqualifiedId FirstTypeName; + SourceLocation CCLoc; + if (Tok.is(tok::identifier)) { + FirstTypeName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); + assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); + CCLoc = ConsumeToken(); + } else if (Tok.is(tok::annot_template_id)) { + // FIXME: retrieve TemplateKWLoc from template-id annotation and + // store it in the pseudo-dtor node (to be used when instantiating it). + FirstTypeName.setTemplateId( + (TemplateIdAnnotation *)Tok.getAnnotationValue()); + ConsumeToken(); + assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); + CCLoc = ConsumeToken(); + } else { + FirstTypeName.setIdentifier(0, SourceLocation()); + } + + // Parse the tilde. + assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail"); + SourceLocation TildeLoc = ConsumeToken(); + + if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid() && SS.isEmpty()) { + DeclSpec DS(AttrFactory); + ParseDecltypeSpecifier(DS); + if (DS.getTypeSpecType() == TST_error) + return ExprError(); + return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, + OpKind, TildeLoc, DS, + Tok.is(tok::l_paren)); + } + + if (!Tok.is(tok::identifier)) { + Diag(Tok, diag::err_destructor_tilde_identifier); + return ExprError(); + } + + // Parse the second type. + UnqualifiedId SecondTypeName; + IdentifierInfo *Name = Tok.getIdentifierInfo(); + SourceLocation NameLoc = ConsumeToken(); + SecondTypeName.setIdentifier(Name, NameLoc); + + // If there is a '<', the second type name is a template-id. Parse + // it as such. + if (Tok.is(tok::less) && + ParseUnqualifiedIdTemplateId(SS, SourceLocation(), + Name, NameLoc, + false, ObjectType, SecondTypeName, + /*AssumeTemplateName=*/true)) + return ExprError(); + + return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, + OpLoc, OpKind, + SS, FirstTypeName, CCLoc, + TildeLoc, SecondTypeName, + Tok.is(tok::l_paren)); +} + +/// ParseCXXBoolLiteral - This handles the C++ Boolean literals. +/// +/// boolean-literal: [C++ 2.13.5] +/// 'true' +/// 'false' +ExprResult Parser::ParseCXXBoolLiteral() { + tok::TokenKind Kind = Tok.getKind(); + return Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind); +} + +/// ParseThrowExpression - This handles the C++ throw expression. +/// +/// throw-expression: [C++ 15] +/// 'throw' assignment-expression[opt] +ExprResult Parser::ParseThrowExpression() { + assert(Tok.is(tok::kw_throw) && "Not throw!"); + SourceLocation ThrowLoc = ConsumeToken(); // Eat the throw token. + + // If the current token isn't the start of an assignment-expression, + // then the expression is not present. This handles things like: + // "C ? throw : (void)42", which is crazy but legal. + switch (Tok.getKind()) { // FIXME: move this predicate somewhere common. + case tok::semi: + case tok::r_paren: + case tok::r_square: + case tok::r_brace: + case tok::colon: + case tok::comma: + return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, 0); + + default: + ExprResult Expr(ParseAssignmentExpression()); + if (Expr.isInvalid()) return move(Expr); + return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, Expr.take()); + } +} + +/// ParseCXXThis - This handles the C++ 'this' pointer. +/// +/// C++ 9.3.2: In the body of a non-static member function, the keyword this is +/// a non-lvalue expression whose value is the address of the object for which +/// the function is called. +ExprResult Parser::ParseCXXThis() { + assert(Tok.is(tok::kw_this) && "Not 'this'!"); + SourceLocation ThisLoc = ConsumeToken(); + return Actions.ActOnCXXThis(ThisLoc); +} + +/// ParseCXXTypeConstructExpression - Parse construction of a specified type. +/// Can be interpreted either as function-style casting ("int(x)") +/// or class type construction ("ClassType(x,y,z)") +/// or creation of a value-initialized type ("int()"). +/// See [C++ 5.2.3]. +/// +/// postfix-expression: [C++ 5.2p1] +/// simple-type-specifier '(' expression-list[opt] ')' +/// [C++0x] simple-type-specifier braced-init-list +/// typename-specifier '(' expression-list[opt] ')' +/// [C++0x] typename-specifier braced-init-list +/// +ExprResult +Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); + + assert((Tok.is(tok::l_paren) || + (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace))) + && "Expected '(' or '{'!"); + + if (Tok.is(tok::l_brace)) { + ExprResult Init = ParseBraceInitializer(); + if (Init.isInvalid()) + return Init; + Expr *InitList = Init.take(); + return Actions.ActOnCXXTypeConstructExpr(TypeRep, SourceLocation(), + MultiExprArg(&InitList, 1), + SourceLocation()); + } else { + GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); + + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + ExprVector Exprs(Actions); + CommaLocsTy CommaLocs; + + if (Tok.isNot(tok::r_paren)) { + if (ParseExpressionList(Exprs, CommaLocs)) { + SkipUntil(tok::r_paren); + return ExprError(); + } + } + + // Match the ')'. + T.consumeClose(); + + // TypeRep could be null, if it references an invalid typedef. + if (!TypeRep) + return ExprError(); + + assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&& + "Unexpected number of commas!"); + return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(), + move_arg(Exprs), + T.getCloseLocation()); + } +} + +/// ParseCXXCondition - if/switch/while condition expression. +/// +/// condition: +/// expression +/// type-specifier-seq declarator '=' assignment-expression +/// [C++11] type-specifier-seq declarator '=' initializer-clause +/// [C++11] type-specifier-seq declarator braced-init-list +/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] +/// '=' assignment-expression +/// +/// \param ExprResult if the condition was parsed as an expression, the +/// parsed expression. +/// +/// \param DeclResult if the condition was parsed as a declaration, the +/// parsed declaration. +/// +/// \param Loc The location of the start of the statement that requires this +/// condition, e.g., the "for" in a for loop. +/// +/// \param ConvertToBoolean Whether the condition expression should be +/// converted to a boolean value. +/// +/// \returns true if there was a parsing, false otherwise. +bool Parser::ParseCXXCondition(ExprResult &ExprOut, + Decl *&DeclOut, + SourceLocation Loc, + bool ConvertToBoolean) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition); + cutOffParsing(); + return true; + } + + if (!isCXXConditionDeclaration()) { + // Parse the expression. + ExprOut = ParseExpression(); // expression + DeclOut = 0; + if (ExprOut.isInvalid()) + return true; + + // If required, convert to a boolean value. + if (ConvertToBoolean) + ExprOut + = Actions.ActOnBooleanCondition(getCurScope(), Loc, ExprOut.get()); + return ExprOut.isInvalid(); + } + + // type-specifier-seq + DeclSpec DS(AttrFactory); + ParseSpecifierQualifierList(DS); + + // declarator + Declarator DeclaratorInfo(DS, Declarator::ConditionContext); + ParseDeclarator(DeclaratorInfo); + + // simple-asm-expr[opt] + if (Tok.is(tok::kw_asm)) { + SourceLocation Loc; + ExprResult AsmLabel(ParseSimpleAsm(&Loc)); + if (AsmLabel.isInvalid()) { + SkipUntil(tok::semi); + return true; + } + DeclaratorInfo.setAsmLabel(AsmLabel.release()); + DeclaratorInfo.SetRangeEnd(Loc); + } + + // If attributes are present, parse them. + MaybeParseGNUAttributes(DeclaratorInfo); + + // Type-check the declaration itself. + DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(getCurScope(), + DeclaratorInfo); + DeclOut = Dcl.get(); + ExprOut = ExprError(); + + // '=' assignment-expression + // If a '==' or '+=' is found, suggest a fixit to '='. + bool CopyInitialization = isTokenEqualOrEqualTypo(); + if (CopyInitialization) + ConsumeToken(); + + ExprResult InitExpr = ExprError(); + if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok.getLocation(), + diag::warn_cxx98_compat_generalized_initializer_lists); + InitExpr = ParseBraceInitializer(); + } else if (CopyInitialization) { + InitExpr = ParseAssignmentExpression(); + } else if (Tok.is(tok::l_paren)) { + // This was probably an attempt to initialize the variable. + SourceLocation LParen = ConsumeParen(), RParen = LParen; + if (SkipUntil(tok::r_paren, true, /*DontConsume=*/true)) + RParen = ConsumeParen(); + Diag(DeclOut ? DeclOut->getLocation() : LParen, + diag::err_expected_init_in_condition_lparen) + << SourceRange(LParen, RParen); + } else { + Diag(DeclOut ? DeclOut->getLocation() : Tok.getLocation(), + diag::err_expected_init_in_condition); + } + + if (!InitExpr.isInvalid()) + Actions.AddInitializerToDecl(DeclOut, InitExpr.take(), !CopyInitialization, + DS.getTypeSpecType() == DeclSpec::TST_auto); + + // FIXME: Build a reference to this declaration? Convert it to bool? + // (This is currently handled by Sema). + + Actions.FinalizeDeclaration(DeclOut); + + return false; +} + +/// \brief Determine whether the current token starts a C++ +/// simple-type-specifier. +bool Parser::isCXXSimpleTypeSpecifier() const { + switch (Tok.getKind()) { + case tok::annot_typename: + case tok::kw_short: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_half: + case tok::kw_float: + case tok::kw_double: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_bool: + case tok::kw_decltype: + case tok::kw_typeof: + case tok::kw___underlying_type: + return true; + + default: + break; + } + + return false; +} + +/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. +/// This should only be called when the current token is known to be part of +/// simple-type-specifier. +/// +/// simple-type-specifier: +/// '::'[opt] nested-name-specifier[opt] type-name +/// '::'[opt] nested-name-specifier 'template' simple-template-id [TODO] +/// char +/// wchar_t +/// bool +/// short +/// int +/// long +/// signed +/// unsigned +/// float +/// double +/// void +/// [GNU] typeof-specifier +/// [C++0x] auto [TODO] +/// +/// type-name: +/// class-name +/// enum-name +/// typedef-name +/// +void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { + DS.SetRangeStart(Tok.getLocation()); + const char *PrevSpec; + unsigned DiagID; + SourceLocation Loc = Tok.getLocation(); + + switch (Tok.getKind()) { + case tok::identifier: // foo::bar + case tok::coloncolon: // ::foo::bar + llvm_unreachable("Annotation token should already be formed!"); + default: + llvm_unreachable("Not a simple-type-specifier token!"); + + // type-name + case tok::annot_typename: { + if (getTypeAnnotation(Tok)) + DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, + getTypeAnnotation(Tok)); + else + DS.SetTypeSpecError(); + + DS.SetRangeEnd(Tok.getAnnotationEndLoc()); + ConsumeToken(); + + // Objective-C supports syntax of the form 'id' where 'id' + // is a specific typedef and 'itf' where 'itf' is an + // Objective-C interface. If we don't have Objective-C or a '<', this is + // just a normal reference to a typedef name. + if (Tok.is(tok::less) && getLangOpts().ObjC1) + ParseObjCProtocolQualifiers(DS); + + DS.Finish(Diags, PP); + return; + } + + // builtin types + case tok::kw_short: + DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID); + break; + case tok::kw_long: + DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, DiagID); + break; + case tok::kw___int64: + DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, DiagID); + break; + case tok::kw_signed: + DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID); + break; + case tok::kw_unsigned: + DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, DiagID); + break; + case tok::kw_void: + DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID); + break; + case tok::kw_char: + DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID); + break; + case tok::kw_int: + DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); + break; + case tok::kw___int128: + DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, DiagID); + break; + case tok::kw_half: + DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID); + break; + case tok::kw_float: + DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); + break; + case tok::kw_double: + DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID); + break; + case tok::kw_wchar_t: + DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID); + break; + case tok::kw_char16_t: + DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID); + break; + case tok::kw_char32_t: + DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID); + break; + case tok::kw_bool: + DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID); + break; + case tok::annot_decltype: + case tok::kw_decltype: + DS.SetRangeEnd(ParseDecltypeSpecifier(DS)); + return DS.Finish(Diags, PP); + + // GNU typeof support. + case tok::kw_typeof: + ParseTypeofSpecifier(DS); + DS.Finish(Diags, PP); + return; + } + if (Tok.is(tok::annot_typename)) + DS.SetRangeEnd(Tok.getAnnotationEndLoc()); + else + DS.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); + DS.Finish(Diags, PP); +} + +/// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++ +/// [dcl.name]), which is a non-empty sequence of type-specifiers, +/// e.g., "const short int". Note that the DeclSpec is *not* finished +/// by parsing the type-specifier-seq, because these sequences are +/// typically followed by some form of declarator. Returns true and +/// emits diagnostics if this is not a type-specifier-seq, false +/// otherwise. +/// +/// type-specifier-seq: [C++ 8.1] +/// type-specifier type-specifier-seq[opt] +/// +bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) { + ParseSpecifierQualifierList(DS, AS_none, DSC_type_specifier); + DS.Finish(Diags, PP); + return false; +} + +/// \brief Finish parsing a C++ unqualified-id that is a template-id of +/// some form. +/// +/// This routine is invoked when a '<' is encountered after an identifier or +/// operator-function-id is parsed by \c ParseUnqualifiedId() to determine +/// whether the unqualified-id is actually a template-id. This routine will +/// then parse the template arguments and form the appropriate template-id to +/// return to the caller. +/// +/// \param SS the nested-name-specifier that precedes this template-id, if +/// we're actually parsing a qualified-id. +/// +/// \param Name for constructor and destructor names, this is the actual +/// identifier that may be a template-name. +/// +/// \param NameLoc the location of the class-name in a constructor or +/// destructor. +/// +/// \param EnteringContext whether we're entering the scope of the +/// nested-name-specifier. +/// +/// \param ObjectType if this unqualified-id occurs within a member access +/// expression, the type of the base object whose member is being accessed. +/// +/// \param Id as input, describes the template-name or operator-function-id +/// that precedes the '<'. If template arguments were parsed successfully, +/// will be updated with the template-id. +/// +/// \param AssumeTemplateId When true, this routine will assume that the name +/// refers to a template without performing name lookup to verify. +/// +/// \returns true if a parse error occurred, false otherwise. +bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool EnteringContext, + ParsedType ObjectType, + UnqualifiedId &Id, + bool AssumeTemplateId) { + assert((AssumeTemplateId || Tok.is(tok::less)) && + "Expected '<' to finish parsing a template-id"); + + TemplateTy Template; + TemplateNameKind TNK = TNK_Non_template; + switch (Id.getKind()) { + case UnqualifiedId::IK_Identifier: + case UnqualifiedId::IK_OperatorFunctionId: + case UnqualifiedId::IK_LiteralOperatorId: + if (AssumeTemplateId) { + TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, TemplateKWLoc, + Id, ObjectType, EnteringContext, + Template); + if (TNK == TNK_Non_template) + return true; + } else { + bool MemberOfUnknownSpecialization; + TNK = Actions.isTemplateName(getCurScope(), SS, + TemplateKWLoc.isValid(), Id, + ObjectType, EnteringContext, Template, + MemberOfUnknownSpecialization); + + if (TNK == TNK_Non_template && MemberOfUnknownSpecialization && + ObjectType && IsTemplateArgumentList()) { + // We have something like t->getAs(), where getAs is a + // member of an unknown specialization. However, this will only + // parse correctly as a template, so suggest the keyword 'template' + // before 'getAs' and treat this as a dependent template name. + std::string Name; + if (Id.getKind() == UnqualifiedId::IK_Identifier) + Name = Id.Identifier->getName(); + else { + Name = "operator "; + if (Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) + Name += getOperatorSpelling(Id.OperatorFunctionId.Operator); + else + Name += Id.Identifier->getName(); + } + Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword) + << Name + << FixItHint::CreateInsertion(Id.StartLocation, "template "); + TNK = Actions.ActOnDependentTemplateName(getCurScope(), + SS, TemplateKWLoc, Id, + ObjectType, EnteringContext, + Template); + if (TNK == TNK_Non_template) + return true; + } + } + break; + + case UnqualifiedId::IK_ConstructorName: { + UnqualifiedId TemplateName; + bool MemberOfUnknownSpecialization; + TemplateName.setIdentifier(Name, NameLoc); + TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(), + TemplateName, ObjectType, + EnteringContext, Template, + MemberOfUnknownSpecialization); + break; + } + + case UnqualifiedId::IK_DestructorName: { + UnqualifiedId TemplateName; + bool MemberOfUnknownSpecialization; + TemplateName.setIdentifier(Name, NameLoc); + if (ObjectType) { + TNK = Actions.ActOnDependentTemplateName(getCurScope(), + SS, TemplateKWLoc, TemplateName, + ObjectType, EnteringContext, + Template); + if (TNK == TNK_Non_template) + return true; + } else { + TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(), + TemplateName, ObjectType, + EnteringContext, Template, + MemberOfUnknownSpecialization); + + if (TNK == TNK_Non_template && !Id.DestructorName.get()) { + Diag(NameLoc, diag::err_destructor_template_id) + << Name << SS.getRange(); + return true; + } + } + break; + } + + default: + return false; + } + + if (TNK == TNK_Non_template) + return false; + + // Parse the enclosed template argument list. + SourceLocation LAngleLoc, RAngleLoc; + TemplateArgList TemplateArgs; + if (Tok.is(tok::less) && + ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, + SS, true, LAngleLoc, + TemplateArgs, + RAngleLoc)) + return true; + + if (Id.getKind() == UnqualifiedId::IK_Identifier || + Id.getKind() == UnqualifiedId::IK_OperatorFunctionId || + Id.getKind() == UnqualifiedId::IK_LiteralOperatorId) { + // Form a parsed representation of the template-id to be stored in the + // UnqualifiedId. + TemplateIdAnnotation *TemplateId + = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds); + + if (Id.getKind() == UnqualifiedId::IK_Identifier) { + TemplateId->Name = Id.Identifier; + TemplateId->Operator = OO_None; + TemplateId->TemplateNameLoc = Id.StartLocation; + } else { + TemplateId->Name = 0; + TemplateId->Operator = Id.OperatorFunctionId.Operator; + TemplateId->TemplateNameLoc = Id.StartLocation; + } + + TemplateId->SS = SS; + TemplateId->TemplateKWLoc = TemplateKWLoc; + TemplateId->Template = Template; + TemplateId->Kind = TNK; + TemplateId->LAngleLoc = LAngleLoc; + TemplateId->RAngleLoc = RAngleLoc; + ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); + for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); + Arg != ArgEnd; ++Arg) + Args[Arg] = TemplateArgs[Arg]; + + Id.setTemplateId(TemplateId); + return false; + } + + // Bundle the template arguments together. + ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), + TemplateArgs.size()); + + // Constructor and destructor names. + TypeResult Type + = Actions.ActOnTemplateIdType(SS, TemplateKWLoc, + Template, NameLoc, + LAngleLoc, TemplateArgsPtr, RAngleLoc, + /*IsCtorOrDtorName=*/true); + if (Type.isInvalid()) + return true; + + if (Id.getKind() == UnqualifiedId::IK_ConstructorName) + Id.setConstructorName(Type.get(), NameLoc, RAngleLoc); + else + Id.setDestructorName(Id.StartLocation, Type.get(), RAngleLoc); + + return false; +} + +/// \brief Parse an operator-function-id or conversion-function-id as part +/// of a C++ unqualified-id. +/// +/// This routine is responsible only for parsing the operator-function-id or +/// conversion-function-id; it does not handle template arguments in any way. +/// +/// \code +/// operator-function-id: [C++ 13.5] +/// 'operator' operator +/// +/// operator: one of +/// new delete new[] delete[] +/// + - * / % ^ & | ~ +/// ! = < > += -= *= /= %= +/// ^= &= |= << >> >>= <<= == != +/// <= >= && || ++ -- , ->* -> +/// () [] +/// +/// conversion-function-id: [C++ 12.3.2] +/// operator conversion-type-id +/// +/// conversion-type-id: +/// type-specifier-seq conversion-declarator[opt] +/// +/// conversion-declarator: +/// ptr-operator conversion-declarator[opt] +/// \endcode +/// +/// \param The nested-name-specifier that preceded this unqualified-id. If +/// non-empty, then we are parsing the unqualified-id of a qualified-id. +/// +/// \param EnteringContext whether we are entering the scope of the +/// nested-name-specifier. +/// +/// \param ObjectType if this unqualified-id occurs within a member access +/// expression, the type of the base object whose member is being accessed. +/// +/// \param Result on a successful parse, contains the parsed unqualified-id. +/// +/// \returns true if parsing fails, false otherwise. +bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, + ParsedType ObjectType, + UnqualifiedId &Result) { + assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword"); + + // Consume the 'operator' keyword. + SourceLocation KeywordLoc = ConsumeToken(); + + // Determine what kind of operator name we have. + unsigned SymbolIdx = 0; + SourceLocation SymbolLocations[3]; + OverloadedOperatorKind Op = OO_None; + switch (Tok.getKind()) { + case tok::kw_new: + case tok::kw_delete: { + bool isNew = Tok.getKind() == tok::kw_new; + // Consume the 'new' or 'delete'. + SymbolLocations[SymbolIdx++] = ConsumeToken(); + // Check for array new/delete. + if (Tok.is(tok::l_square) && + (!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square))) { + // Consume the '[' and ']'. + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) + return true; + + SymbolLocations[SymbolIdx++] = T.getOpenLocation(); + SymbolLocations[SymbolIdx++] = T.getCloseLocation(); + Op = isNew? OO_Array_New : OO_Array_Delete; + } else { + Op = isNew? OO_New : OO_Delete; + } + break; + } + +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + case tok::Token: \ + SymbolLocations[SymbolIdx++] = ConsumeToken(); \ + Op = OO_##Name; \ + break; +#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) +#include "clang/Basic/OperatorKinds.def" + + case tok::l_paren: { + // Consume the '(' and ')'. + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) + return true; + + SymbolLocations[SymbolIdx++] = T.getOpenLocation(); + SymbolLocations[SymbolIdx++] = T.getCloseLocation(); + Op = OO_Call; + break; + } + + case tok::l_square: { + // Consume the '[' and ']'. + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) + return true; + + SymbolLocations[SymbolIdx++] = T.getOpenLocation(); + SymbolLocations[SymbolIdx++] = T.getCloseLocation(); + Op = OO_Subscript; + break; + } + + case tok::code_completion: { + // Code completion for the operator name. + Actions.CodeCompleteOperatorName(getCurScope()); + cutOffParsing(); + // Don't try to parse any further. + return true; + } + + default: + break; + } + + if (Op != OO_None) { + // We have parsed an operator-function-id. + Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations); + return false; + } + + // Parse a literal-operator-id. + // + // literal-operator-id: [C++0x 13.5.8] + // operator "" identifier + + if (getLangOpts().CPlusPlus0x && isTokenStringLiteral()) { + Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator); + + SourceLocation DiagLoc; + unsigned DiagId = 0; + + // We're past translation phase 6, so perform string literal concatenation + // before checking for "". + llvm::SmallVector Toks; + llvm::SmallVector TokLocs; + while (isTokenStringLiteral()) { + if (!Tok.is(tok::string_literal) && !DiagId) { + DiagLoc = Tok.getLocation(); + DiagId = diag::err_literal_operator_string_prefix; + } + Toks.push_back(Tok); + TokLocs.push_back(ConsumeStringToken()); + } + + StringLiteralParser Literal(Toks.data(), Toks.size(), PP); + if (Literal.hadError) + return true; + + // Grab the literal operator's suffix, which will be either the next token + // or a ud-suffix from the string literal. + IdentifierInfo *II = 0; + SourceLocation SuffixLoc; + if (!Literal.getUDSuffix().empty()) { + II = &PP.getIdentifierTable().get(Literal.getUDSuffix()); + SuffixLoc = + Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()], + Literal.getUDSuffixOffset(), + PP.getSourceManager(), getLangOpts()); + // This form is not permitted by the standard (yet). + DiagLoc = SuffixLoc; + DiagId = diag::err_literal_operator_missing_space; + } else if (Tok.is(tok::identifier)) { + II = Tok.getIdentifierInfo(); + SuffixLoc = ConsumeToken(); + TokLocs.push_back(SuffixLoc); + } else { + Diag(Tok.getLocation(), diag::err_expected_ident); + return true; + } + + // The string literal must be empty. + if (!Literal.GetString().empty() || Literal.Pascal) { + DiagLoc = TokLocs.front(); + DiagId = diag::err_literal_operator_string_not_empty; + } + + if (DiagId) { + // This isn't a valid literal-operator-id, but we think we know + // what the user meant. Tell them what they should have written. + llvm::SmallString<32> Str; + Str += "\"\" "; + Str += II->getName(); + Diag(DiagLoc, DiagId) << FixItHint::CreateReplacement( + SourceRange(TokLocs.front(), TokLocs.back()), Str); + } + + Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc); + return false; + } + + // Parse a conversion-function-id. + // + // conversion-function-id: [C++ 12.3.2] + // operator conversion-type-id + // + // conversion-type-id: + // type-specifier-seq conversion-declarator[opt] + // + // conversion-declarator: + // ptr-operator conversion-declarator[opt] + + // Parse the type-specifier-seq. + DeclSpec DS(AttrFactory); + if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType? + return true; + + // Parse the conversion-declarator, which is merely a sequence of + // ptr-operators. + Declarator D(DS, Declarator::TypeNameContext); + ParseDeclaratorInternal(D, /*DirectDeclParser=*/0); + + // Finish up the type. + TypeResult Ty = Actions.ActOnTypeName(getCurScope(), D); + if (Ty.isInvalid()) + return true; + + // Note that this is a conversion-function-id. + Result.setConversionFunctionId(KeywordLoc, Ty.get(), + D.getSourceRange().getEnd()); + return false; +} + +/// \brief Parse a C++ unqualified-id (or a C identifier), which describes the +/// name of an entity. +/// +/// \code +/// unqualified-id: [C++ expr.prim.general] +/// identifier +/// operator-function-id +/// conversion-function-id +/// [C++0x] literal-operator-id [TODO] +/// ~ class-name +/// template-id +/// +/// \endcode +/// +/// \param The nested-name-specifier that preceded this unqualified-id. If +/// non-empty, then we are parsing the unqualified-id of a qualified-id. +/// +/// \param EnteringContext whether we are entering the scope of the +/// nested-name-specifier. +/// +/// \param AllowDestructorName whether we allow parsing of a destructor name. +/// +/// \param AllowConstructorName whether we allow parsing a constructor name. +/// +/// \param ObjectType if this unqualified-id occurs within a member access +/// expression, the type of the base object whose member is being accessed. +/// +/// \param Result on a successful parse, contains the parsed unqualified-id. +/// +/// \returns true if parsing fails, false otherwise. +bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, + bool AllowDestructorName, + bool AllowConstructorName, + ParsedType ObjectType, + SourceLocation& TemplateKWLoc, + UnqualifiedId &Result) { + + // Handle 'A::template B'. This is for template-ids which have not + // already been annotated by ParseOptionalCXXScopeSpecifier(). + bool TemplateSpecified = false; + if (getLangOpts().CPlusPlus && Tok.is(tok::kw_template) && + (ObjectType || SS.isSet())) { + TemplateSpecified = true; + TemplateKWLoc = ConsumeToken(); + } + + // unqualified-id: + // identifier + // template-id (when it hasn't already been annotated) + if (Tok.is(tok::identifier)) { + // Consume the identifier. + IdentifierInfo *Id = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + + if (!getLangOpts().CPlusPlus) { + // If we're not in C++, only identifiers matter. Record the + // identifier and return. + Result.setIdentifier(Id, IdLoc); + return false; + } + + if (AllowConstructorName && + Actions.isCurrentClassName(*Id, getCurScope(), &SS)) { + // We have parsed a constructor name. + ParsedType Ty = Actions.getTypeName(*Id, IdLoc, getCurScope(), + &SS, false, false, + ParsedType(), + /*IsCtorOrDtorName=*/true, + /*NonTrivialTypeSourceInfo=*/true); + Result.setConstructorName(Ty, IdLoc, IdLoc); + } else { + // We have parsed an identifier. + Result.setIdentifier(Id, IdLoc); + } + + // If the next token is a '<', we may have a template. + if (TemplateSpecified || Tok.is(tok::less)) + return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, Id, IdLoc, + EnteringContext, ObjectType, + Result, TemplateSpecified); + + return false; + } + + // unqualified-id: + // template-id (already parsed and annotated) + if (Tok.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + + // If the template-name names the current class, then this is a constructor + if (AllowConstructorName && TemplateId->Name && + Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) { + if (SS.isSet()) { + // C++ [class.qual]p2 specifies that a qualified template-name + // is taken as the constructor name where a constructor can be + // declared. Thus, the template arguments are extraneous, so + // complain about them and remove them entirely. + Diag(TemplateId->TemplateNameLoc, + diag::err_out_of_line_constructor_template_id) + << TemplateId->Name + << FixItHint::CreateRemoval( + SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)); + ParsedType Ty = Actions.getTypeName(*TemplateId->Name, + TemplateId->TemplateNameLoc, + getCurScope(), + &SS, false, false, + ParsedType(), + /*IsCtorOrDtorName=*/true, + /*NontrivialTypeSourceInfo=*/true); + Result.setConstructorName(Ty, TemplateId->TemplateNameLoc, + TemplateId->RAngleLoc); + ConsumeToken(); + return false; + } + + Result.setConstructorTemplateId(TemplateId); + ConsumeToken(); + return false; + } + + // We have already parsed a template-id; consume the annotation token as + // our unqualified-id. + Result.setTemplateId(TemplateId); + TemplateKWLoc = TemplateId->TemplateKWLoc; + ConsumeToken(); + return false; + } + + // unqualified-id: + // operator-function-id + // conversion-function-id + if (Tok.is(tok::kw_operator)) { + if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result)) + return true; + + // If we have an operator-function-id or a literal-operator-id and the next + // token is a '<', we may have a + // + // template-id: + // operator-function-id < template-argument-list[opt] > + if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId || + Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) && + (TemplateSpecified || Tok.is(tok::less))) + return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, + 0, SourceLocation(), + EnteringContext, ObjectType, + Result, TemplateSpecified); + + return false; + } + + if (getLangOpts().CPlusPlus && + (AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) { + // C++ [expr.unary.op]p10: + // There is an ambiguity in the unary-expression ~X(), where X is a + // class-name. The ambiguity is resolved in favor of treating ~ as a + // unary complement rather than treating ~X as referring to a destructor. + + // Parse the '~'. + SourceLocation TildeLoc = ConsumeToken(); + + if (SS.isEmpty() && Tok.is(tok::kw_decltype)) { + DeclSpec DS(AttrFactory); + SourceLocation EndLoc = ParseDecltypeSpecifier(DS); + if (ParsedType Type = Actions.getDestructorType(DS, ObjectType)) { + Result.setDestructorName(TildeLoc, Type, EndLoc); + return false; + } + return true; + } + + // Parse the class-name. + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_destructor_tilde_identifier); + return true; + } + + // Parse the class-name (or template-name in a simple-template-id). + IdentifierInfo *ClassName = Tok.getIdentifierInfo(); + SourceLocation ClassNameLoc = ConsumeToken(); + + if (TemplateSpecified || Tok.is(tok::less)) { + Result.setDestructorName(TildeLoc, ParsedType(), ClassNameLoc); + return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, + ClassName, ClassNameLoc, + EnteringContext, ObjectType, + Result, TemplateSpecified); + } + + // Note that this is a destructor name. + ParsedType Ty = Actions.getDestructorName(TildeLoc, *ClassName, + ClassNameLoc, getCurScope(), + SS, ObjectType, + EnteringContext); + if (!Ty) + return true; + + Result.setDestructorName(TildeLoc, Ty, ClassNameLoc); + return false; + } + + Diag(Tok, diag::err_expected_unqualified_id) + << getLangOpts().CPlusPlus; + return true; +} + +/// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate +/// memory in a typesafe manner and call constructors. +/// +/// This method is called to parse the new expression after the optional :: has +/// been already parsed. If the :: was present, "UseGlobal" is true and "Start" +/// is its location. Otherwise, "Start" is the location of the 'new' token. +/// +/// new-expression: +/// '::'[opt] 'new' new-placement[opt] new-type-id +/// new-initializer[opt] +/// '::'[opt] 'new' new-placement[opt] '(' type-id ')' +/// new-initializer[opt] +/// +/// new-placement: +/// '(' expression-list ')' +/// +/// new-type-id: +/// type-specifier-seq new-declarator[opt] +/// [GNU] attributes type-specifier-seq new-declarator[opt] +/// +/// new-declarator: +/// ptr-operator new-declarator[opt] +/// direct-new-declarator +/// +/// new-initializer: +/// '(' expression-list[opt] ')' +/// [C++0x] braced-init-list +/// +ExprResult +Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { + assert(Tok.is(tok::kw_new) && "expected 'new' token"); + ConsumeToken(); // Consume 'new' + + // A '(' now can be a new-placement or the '(' wrapping the type-id in the + // second form of new-expression. It can't be a new-type-id. + + ExprVector PlacementArgs(Actions); + SourceLocation PlacementLParen, PlacementRParen; + + SourceRange TypeIdParens; + DeclSpec DS(AttrFactory); + Declarator DeclaratorInfo(DS, Declarator::CXXNewContext); + if (Tok.is(tok::l_paren)) { + // If it turns out to be a placement, we change the type location. + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + PlacementLParen = T.getOpenLocation(); + if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) { + SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); + return ExprError(); + } + + T.consumeClose(); + PlacementRParen = T.getCloseLocation(); + if (PlacementRParen.isInvalid()) { + SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); + return ExprError(); + } + + if (PlacementArgs.empty()) { + // Reset the placement locations. There was no placement. + TypeIdParens = T.getRange(); + PlacementLParen = PlacementRParen = SourceLocation(); + } else { + // We still need the type. + if (Tok.is(tok::l_paren)) { + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + MaybeParseGNUAttributes(DeclaratorInfo); + ParseSpecifierQualifierList(DS); + DeclaratorInfo.SetSourceRange(DS.getSourceRange()); + ParseDeclarator(DeclaratorInfo); + T.consumeClose(); + TypeIdParens = T.getRange(); + } else { + MaybeParseGNUAttributes(DeclaratorInfo); + if (ParseCXXTypeSpecifierSeq(DS)) + DeclaratorInfo.setInvalidType(true); + else { + DeclaratorInfo.SetSourceRange(DS.getSourceRange()); + ParseDeclaratorInternal(DeclaratorInfo, + &Parser::ParseDirectNewDeclarator); + } + } + } + } else { + // A new-type-id is a simplified type-id, where essentially the + // direct-declarator is replaced by a direct-new-declarator. + MaybeParseGNUAttributes(DeclaratorInfo); + if (ParseCXXTypeSpecifierSeq(DS)) + DeclaratorInfo.setInvalidType(true); + else { + DeclaratorInfo.SetSourceRange(DS.getSourceRange()); + ParseDeclaratorInternal(DeclaratorInfo, + &Parser::ParseDirectNewDeclarator); + } + } + if (DeclaratorInfo.isInvalidType()) { + SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); + return ExprError(); + } + + ExprResult Initializer; + + if (Tok.is(tok::l_paren)) { + SourceLocation ConstructorLParen, ConstructorRParen; + ExprVector ConstructorArgs(Actions); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + ConstructorLParen = T.getOpenLocation(); + if (Tok.isNot(tok::r_paren)) { + CommaLocsTy CommaLocs; + if (ParseExpressionList(ConstructorArgs, CommaLocs)) { + SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); + return ExprError(); + } + } + T.consumeClose(); + ConstructorRParen = T.getCloseLocation(); + if (ConstructorRParen.isInvalid()) { + SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); + return ExprError(); + } + Initializer = Actions.ActOnParenListExpr(ConstructorLParen, + ConstructorRParen, + move_arg(ConstructorArgs)); + } else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus0x) { + Diag(Tok.getLocation(), + diag::warn_cxx98_compat_generalized_initializer_lists); + Initializer = ParseBraceInitializer(); + } + if (Initializer.isInvalid()) + return Initializer; + + return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen, + move_arg(PlacementArgs), PlacementRParen, + TypeIdParens, DeclaratorInfo, Initializer.take()); +} + +/// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be +/// passed to ParseDeclaratorInternal. +/// +/// direct-new-declarator: +/// '[' expression ']' +/// direct-new-declarator '[' constant-expression ']' +/// +void Parser::ParseDirectNewDeclarator(Declarator &D) { + // Parse the array dimensions. + bool first = true; + while (Tok.is(tok::l_square)) { + // An array-size expression can't start with a lambda. + if (CheckProhibitedCXX11Attribute()) + continue; + + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + + ExprResult Size(first ? ParseExpression() + : ParseConstantExpression()); + if (Size.isInvalid()) { + // Recover + SkipUntil(tok::r_square); + return; + } + first = false; + + T.consumeClose(); + + // Attributes here appertain to the array type. C++11 [expr.new]p5. + ParsedAttributes Attrs(AttrFactory); + MaybeParseCXX0XAttributes(Attrs); + + D.AddTypeInfo(DeclaratorChunk::getArray(0, + /*static=*/false, /*star=*/false, + Size.release(), + T.getOpenLocation(), + T.getCloseLocation()), + Attrs, T.getCloseLocation()); + + if (T.getCloseLocation().isInvalid()) + return; + } +} + +/// ParseExpressionListOrTypeId - Parse either an expression-list or a type-id. +/// This ambiguity appears in the syntax of the C++ new operator. +/// +/// new-expression: +/// '::'[opt] 'new' new-placement[opt] '(' type-id ')' +/// new-initializer[opt] +/// +/// new-placement: +/// '(' expression-list ')' +/// +bool Parser::ParseExpressionListOrTypeId( + SmallVectorImpl &PlacementArgs, + Declarator &D) { + // The '(' was already consumed. + if (isTypeIdInParens()) { + ParseSpecifierQualifierList(D.getMutableDeclSpec()); + D.SetSourceRange(D.getDeclSpec().getSourceRange()); + ParseDeclarator(D); + return D.isInvalidType(); + } + + // It's not a type, it has to be an expression list. + // Discard the comma locations - ActOnCXXNew has enough parameters. + CommaLocsTy CommaLocs; + return ParseExpressionList(PlacementArgs, CommaLocs); +} + +/// ParseCXXDeleteExpression - Parse a C++ delete-expression. Delete is used +/// to free memory allocated by new. +/// +/// This method is called to parse the 'delete' expression after the optional +/// '::' has been already parsed. If the '::' was present, "UseGlobal" is true +/// and "Start" is its location. Otherwise, "Start" is the location of the +/// 'delete' token. +/// +/// delete-expression: +/// '::'[opt] 'delete' cast-expression +/// '::'[opt] 'delete' '[' ']' cast-expression +ExprResult +Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { + assert(Tok.is(tok::kw_delete) && "Expected 'delete' keyword"); + ConsumeToken(); // Consume 'delete' + + // Array delete? + bool ArrayDelete = false; + if (Tok.is(tok::l_square) && NextToken().is(tok::r_square)) { + // FIXME: This could be the start of a lambda-expression. We should + // disambiguate this, but that will require arbitrary lookahead if + // the next token is '(': + // delete [](int*){ /* ... */ + ArrayDelete = true; + BalancedDelimiterTracker T(*this, tok::l_square); + + T.consumeOpen(); + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) + return ExprError(); + } + + ExprResult Operand(ParseCastExpression(false)); + if (Operand.isInvalid()) + return move(Operand); + + return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.take()); +} + +static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { + switch(kind) { + default: llvm_unreachable("Not a known unary type trait."); + case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign; + case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor; + case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy; + case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign; + case tok::kw___has_trivial_constructor: + return UTT_HasTrivialDefaultConstructor; + case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy; + case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor; + case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor; + case tok::kw___is_abstract: return UTT_IsAbstract; + case tok::kw___is_arithmetic: return UTT_IsArithmetic; + case tok::kw___is_array: return UTT_IsArray; + case tok::kw___is_class: return UTT_IsClass; + case tok::kw___is_complete_type: return UTT_IsCompleteType; + case tok::kw___is_compound: return UTT_IsCompound; + case tok::kw___is_const: return UTT_IsConst; + case tok::kw___is_empty: return UTT_IsEmpty; + case tok::kw___is_enum: return UTT_IsEnum; + case tok::kw___is_final: return UTT_IsFinal; + case tok::kw___is_floating_point: return UTT_IsFloatingPoint; + case tok::kw___is_function: return UTT_IsFunction; + case tok::kw___is_fundamental: return UTT_IsFundamental; + case tok::kw___is_integral: return UTT_IsIntegral; + case tok::kw___is_lvalue_reference: return UTT_IsLvalueReference; + case tok::kw___is_member_function_pointer: return UTT_IsMemberFunctionPointer; + case tok::kw___is_member_object_pointer: return UTT_IsMemberObjectPointer; + case tok::kw___is_member_pointer: return UTT_IsMemberPointer; + case tok::kw___is_object: return UTT_IsObject; + case tok::kw___is_literal: return UTT_IsLiteral; + case tok::kw___is_literal_type: return UTT_IsLiteral; + case tok::kw___is_pod: return UTT_IsPOD; + case tok::kw___is_pointer: return UTT_IsPointer; + case tok::kw___is_polymorphic: return UTT_IsPolymorphic; + case tok::kw___is_reference: return UTT_IsReference; + case tok::kw___is_rvalue_reference: return UTT_IsRvalueReference; + case tok::kw___is_scalar: return UTT_IsScalar; + case tok::kw___is_signed: return UTT_IsSigned; + case tok::kw___is_standard_layout: return UTT_IsStandardLayout; + case tok::kw___is_trivial: return UTT_IsTrivial; + case tok::kw___is_trivially_copyable: return UTT_IsTriviallyCopyable; + case tok::kw___is_union: return UTT_IsUnion; + case tok::kw___is_unsigned: return UTT_IsUnsigned; + case tok::kw___is_void: return UTT_IsVoid; + case tok::kw___is_volatile: return UTT_IsVolatile; + } +} + +static BinaryTypeTrait BinaryTypeTraitFromTokKind(tok::TokenKind kind) { + switch(kind) { + default: llvm_unreachable("Not a known binary type trait"); + case tok::kw___is_base_of: return BTT_IsBaseOf; + case tok::kw___is_convertible: return BTT_IsConvertible; + case tok::kw___is_same: return BTT_IsSame; + case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible; + case tok::kw___is_convertible_to: return BTT_IsConvertibleTo; + case tok::kw___is_trivially_assignable: return BTT_IsTriviallyAssignable; + } +} + +static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) { + switch (kind) { + default: llvm_unreachable("Not a known type trait"); + case tok::kw___is_trivially_constructible: + return TT_IsTriviallyConstructible; + } +} + +static ArrayTypeTrait ArrayTypeTraitFromTokKind(tok::TokenKind kind) { + switch(kind) { + default: llvm_unreachable("Not a known binary type trait"); + case tok::kw___array_rank: return ATT_ArrayRank; + case tok::kw___array_extent: return ATT_ArrayExtent; + } +} + +static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) { + switch(kind) { + default: llvm_unreachable("Not a known unary expression trait."); + case tok::kw___is_lvalue_expr: return ET_IsLValueExpr; + case tok::kw___is_rvalue_expr: return ET_IsRValueExpr; + } +} + +/// ParseUnaryTypeTrait - Parse the built-in unary type-trait +/// pseudo-functions that allow implementation of the TR1/C++0x type traits +/// templates. +/// +/// primary-expression: +/// [GNU] unary-type-trait '(' type-id ')' +/// +ExprResult Parser::ParseUnaryTypeTrait() { + UnaryTypeTrait UTT = UnaryTypeTraitFromTokKind(Tok.getKind()); + SourceLocation Loc = ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) + return ExprError(); + + // FIXME: Error reporting absolutely sucks! If the this fails to parse a type + // there will be cryptic errors about mismatched parentheses and missing + // specifiers. + TypeResult Ty = ParseTypeName(); + + T.consumeClose(); + + if (Ty.isInvalid()) + return ExprError(); + + return Actions.ActOnUnaryTypeTrait(UTT, Loc, Ty.get(), T.getCloseLocation()); +} + +/// ParseBinaryTypeTrait - Parse the built-in binary type-trait +/// pseudo-functions that allow implementation of the TR1/C++0x type traits +/// templates. +/// +/// primary-expression: +/// [GNU] binary-type-trait '(' type-id ',' type-id ')' +/// +ExprResult Parser::ParseBinaryTypeTrait() { + BinaryTypeTrait BTT = BinaryTypeTraitFromTokKind(Tok.getKind()); + SourceLocation Loc = ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) + return ExprError(); + + TypeResult LhsTy = ParseTypeName(); + if (LhsTy.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + TypeResult RhsTy = ParseTypeName(); + if (RhsTy.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + T.consumeClose(); + + return Actions.ActOnBinaryTypeTrait(BTT, Loc, LhsTy.get(), RhsTy.get(), + T.getCloseLocation()); +} + +/// \brief Parse the built-in type-trait pseudo-functions that allow +/// implementation of the TR1/C++11 type traits templates. +/// +/// primary-expression: +/// type-trait '(' type-id-seq ')' +/// +/// type-id-seq: +/// type-id ...[opt] type-id-seq[opt] +/// +ExprResult Parser::ParseTypeTrait() { + TypeTrait Kind = TypeTraitFromTokKind(Tok.getKind()); + SourceLocation Loc = ConsumeToken(); + + BalancedDelimiterTracker Parens(*this, tok::l_paren); + if (Parens.expectAndConsume(diag::err_expected_lparen)) + return ExprError(); + + llvm::SmallVector Args; + do { + // Parse the next type. + TypeResult Ty = ParseTypeName(); + if (Ty.isInvalid()) { + Parens.skipToEnd(); + return ExprError(); + } + + // Parse the ellipsis, if present. + if (Tok.is(tok::ellipsis)) { + Ty = Actions.ActOnPackExpansion(Ty.get(), ConsumeToken()); + if (Ty.isInvalid()) { + Parens.skipToEnd(); + return ExprError(); + } + } + + // Add this type to the list of arguments. + Args.push_back(Ty.get()); + + if (Tok.is(tok::comma)) { + ConsumeToken(); + continue; + } + + break; + } while (true); + + if (Parens.consumeClose()) + return ExprError(); + + return Actions.ActOnTypeTrait(Kind, Loc, Args, Parens.getCloseLocation()); +} + +/// ParseArrayTypeTrait - Parse the built-in array type-trait +/// pseudo-functions. +/// +/// primary-expression: +/// [Embarcadero] '__array_rank' '(' type-id ')' +/// [Embarcadero] '__array_extent' '(' type-id ',' expression ')' +/// +ExprResult Parser::ParseArrayTypeTrait() { + ArrayTypeTrait ATT = ArrayTypeTraitFromTokKind(Tok.getKind()); + SourceLocation Loc = ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) + return ExprError(); + + TypeResult Ty = ParseTypeName(); + if (Ty.isInvalid()) { + SkipUntil(tok::comma); + SkipUntil(tok::r_paren); + return ExprError(); + } + + switch (ATT) { + case ATT_ArrayRank: { + T.consumeClose(); + return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), NULL, + T.getCloseLocation()); + } + case ATT_ArrayExtent: { + if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + ExprResult DimExpr = ParseExpression(); + T.consumeClose(); + + return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(), + T.getCloseLocation()); + } + } + llvm_unreachable("Invalid ArrayTypeTrait!"); +} + +/// ParseExpressionTrait - Parse built-in expression-trait +/// pseudo-functions like __is_lvalue_expr( xxx ). +/// +/// primary-expression: +/// [Embarcadero] expression-trait '(' expression ')' +/// +ExprResult Parser::ParseExpressionTrait() { + ExpressionTrait ET = ExpressionTraitFromTokKind(Tok.getKind()); + SourceLocation Loc = ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) + return ExprError(); + + ExprResult Expr = ParseExpression(); + + T.consumeClose(); + + return Actions.ActOnExpressionTrait(ET, Loc, Expr.get(), + T.getCloseLocation()); +} + + +/// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a +/// parenthesized ambiguous type-id. This uses tentative parsing to disambiguate +/// based on the context past the parens. +ExprResult +Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, + ParsedType &CastTy, + BalancedDelimiterTracker &Tracker) { + assert(getLangOpts().CPlusPlus && "Should only be called for C++!"); + assert(ExprType == CastExpr && "Compound literals are not ambiguous!"); + assert(isTypeIdInParens() && "Not a type-id!"); + + ExprResult Result(true); + CastTy = ParsedType(); + + // We need to disambiguate a very ugly part of the C++ syntax: + // + // (T())x; - type-id + // (T())*x; - type-id + // (T())/x; - expression + // (T()); - expression + // + // The bad news is that we cannot use the specialized tentative parser, since + // it can only verify that the thing inside the parens can be parsed as + // type-id, it is not useful for determining the context past the parens. + // + // The good news is that the parser can disambiguate this part without + // making any unnecessary Action calls. + // + // It uses a scheme similar to parsing inline methods. The parenthesized + // tokens are cached, the context that follows is determined (possibly by + // parsing a cast-expression), and then we re-introduce the cached tokens + // into the token stream and parse them appropriately. + + ParenParseOption ParseAs; + CachedTokens Toks; + + // Store the tokens of the parentheses. We will parse them after we determine + // the context that follows them. + if (!ConsumeAndStoreUntil(tok::r_paren, Toks)) { + // We didn't find the ')' we expected. + Tracker.consumeClose(); + return ExprError(); + } + + if (Tok.is(tok::l_brace)) { + ParseAs = CompoundLiteral; + } else { + bool NotCastExpr; + // FIXME: Special-case ++ and --: "(S())++;" is not a cast-expression + if (Tok.is(tok::l_paren) && NextToken().is(tok::r_paren)) { + NotCastExpr = true; + } else { + // Try parsing the cast-expression that may follow. + // If it is not a cast-expression, NotCastExpr will be true and no token + // will be consumed. + Result = ParseCastExpression(false/*isUnaryExpression*/, + false/*isAddressofOperand*/, + NotCastExpr, + // type-id has priority. + IsTypeCast); + } + + // If we parsed a cast-expression, it's really a type-id, otherwise it's + // an expression. + ParseAs = NotCastExpr ? SimpleExpr : CastExpr; + } + + // The current token should go after the cached tokens. + Toks.push_back(Tok); + // Re-enter the stored parenthesized tokens into the token stream, so we may + // parse them now. + PP.EnterTokenStream(Toks.data(), Toks.size(), + true/*DisableMacroExpansion*/, false/*OwnsTokens*/); + // Drop the current token and bring the first cached one. It's the same token + // as when we entered this function. + ConsumeAnyToken(); + + if (ParseAs >= CompoundLiteral) { + // Parse the type declarator. + DeclSpec DS(AttrFactory); + ParseSpecifierQualifierList(DS); + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + ParseDeclarator(DeclaratorInfo); + + // Match the ')'. + Tracker.consumeClose(); + + if (ParseAs == CompoundLiteral) { + ExprType = CompoundLiteral; + TypeResult Ty = ParseTypeName(); + return ParseCompoundLiteralExpression(Ty.get(), + Tracker.getOpenLocation(), + Tracker.getCloseLocation()); + } + + // We parsed '(' type-id ')' and the thing after it wasn't a '{'. + assert(ParseAs == CastExpr); + + if (DeclaratorInfo.isInvalidType()) + return ExprError(); + + // Result is what ParseCastExpression returned earlier. + if (!Result.isInvalid()) + Result = Actions.ActOnCastExpr(getCurScope(), Tracker.getOpenLocation(), + DeclaratorInfo, CastTy, + Tracker.getCloseLocation(), Result.take()); + return move(Result); + } + + // Not a compound literal, and not followed by a cast-expression. + assert(ParseAs == SimpleExpr); + + ExprType = SimpleExpr; + Result = ParseExpression(); + if (!Result.isInvalid() && Tok.is(tok::r_paren)) + Result = Actions.ActOnParenExpr(Tracker.getOpenLocation(), + Tok.getLocation(), Result.take()); + + // Match the ')'. + if (Result.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + Tracker.consumeClose(); + return move(Result); +} diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp new file mode 100644 index 0000000..1c349fd --- /dev/null +++ b/clang/lib/Parse/ParseInit.cpp @@ -0,0 +1,547 @@ +//===--- ParseInit.cpp - Initializer Parsing ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements initializer parsing as specified by C99 6.7.8. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "RAIIObjectsForParser.h" +#include "clang/Sema/Designator.h" +#include "clang/Sema/Scope.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + + +/// MayBeDesignationStart - Return true if the current token might be the start +/// of a designator. If we can tell it is impossible that it is a designator, +/// return false. +bool Parser::MayBeDesignationStart() { + switch (Tok.getKind()) { + default: + return false; + + case tok::period: // designator: '.' identifier + return true; + + case tok::l_square: { // designator: array-designator + if (!PP.getLangOpts().CPlusPlus0x) + return true; + + // C++11 lambda expressions and C99 designators can be ambiguous all the + // way through the closing ']' and to the next character. Handle the easy + // cases here, and fall back to tentative parsing if those fail. + switch (PP.LookAhead(0).getKind()) { + case tok::equal: + case tok::r_square: + // Definitely starts a lambda expression. + return false; + + case tok::amp: + case tok::kw_this: + case tok::identifier: + // We have to do additional analysis, because these could be the + // start of a constant expression or a lambda capture list. + break; + + default: + // Anything not mentioned above cannot occur following a '[' in a + // lambda expression. + return true; + } + + // Handle the complicated case below. + break; + } + case tok::identifier: // designation: identifier ':' + return PP.LookAhead(0).is(tok::colon); + } + + // Parse up to (at most) the token after the closing ']' to determine + // whether this is a C99 designator or a lambda. + TentativeParsingAction Tentative(*this); + ConsumeBracket(); + while (true) { + switch (Tok.getKind()) { + case tok::equal: + case tok::amp: + case tok::identifier: + case tok::kw_this: + // These tokens can occur in a capture list or a constant-expression. + // Keep looking. + ConsumeToken(); + continue; + + case tok::comma: + // Since a comma cannot occur in a constant-expression, this must + // be a lambda. + Tentative.Revert(); + return false; + + case tok::r_square: { + // Once we hit the closing square bracket, we look at the next + // token. If it's an '=', this is a designator. Otherwise, it's a + // lambda expression. This decision favors lambdas over the older + // GNU designator syntax, which allows one to omit the '=', but is + // consistent with GCC. + ConsumeBracket(); + tok::TokenKind Kind = Tok.getKind(); + Tentative.Revert(); + return Kind == tok::equal; + } + + default: + // Anything else cannot occur in a lambda capture list, so it + // must be a designator. + Tentative.Revert(); + return true; + } + } + + return true; +} + +static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc, + Designation &Desig) { + // If we have exactly one array designator, this used the GNU + // 'designation: array-designator' extension, otherwise there should be no + // designators at all! + if (Desig.getNumDesignators() == 1 && + (Desig.getDesignator(0).isArrayDesignator() || + Desig.getDesignator(0).isArrayRangeDesignator())) + P.Diag(Loc, diag::ext_gnu_missing_equal_designator); + else if (Desig.getNumDesignators() > 0) + P.Diag(Loc, diag::err_expected_equal_designator); +} + +/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production +/// checking to see if the token stream starts with a designator. +/// +/// designation: +/// designator-list '=' +/// [GNU] array-designator +/// [GNU] identifier ':' +/// +/// designator-list: +/// designator +/// designator-list designator +/// +/// designator: +/// array-designator +/// '.' identifier +/// +/// array-designator: +/// '[' constant-expression ']' +/// [GNU] '[' constant-expression '...' constant-expression ']' +/// +/// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an +/// initializer (because it is an expression). We need to consider this case +/// when parsing array designators. +/// +ExprResult Parser::ParseInitializerWithPotentialDesignator() { + + // If this is the old-style GNU extension: + // designation ::= identifier ':' + // Handle it as a field designator. Otherwise, this must be the start of a + // normal expression. + if (Tok.is(tok::identifier)) { + const IdentifierInfo *FieldName = Tok.getIdentifierInfo(); + + SmallString<256> NewSyntax; + llvm::raw_svector_ostream(NewSyntax) << '.' << FieldName->getName() + << " = "; + + SourceLocation NameLoc = ConsumeToken(); // Eat the identifier. + + assert(Tok.is(tok::colon) && "MayBeDesignationStart not working properly!"); + SourceLocation ColonLoc = ConsumeToken(); + + Diag(NameLoc, diag::ext_gnu_old_style_field_designator) + << FixItHint::CreateReplacement(SourceRange(NameLoc, ColonLoc), + NewSyntax.str()); + + Designation D; + D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc)); + return Actions.ActOnDesignatedInitializer(D, ColonLoc, true, + ParseInitializer()); + } + + // Desig - This is initialized when we see our first designator. We may have + // an objc message send with no designator, so we don't want to create this + // eagerly. + Designation Desig; + + // Parse each designator in the designator list until we find an initializer. + while (Tok.is(tok::period) || Tok.is(tok::l_square)) { + if (Tok.is(tok::period)) { + // designator: '.' identifier + SourceLocation DotLoc = ConsumeToken(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_expected_field_designator); + return ExprError(); + } + + Desig.AddDesignator(Designator::getField(Tok.getIdentifierInfo(), DotLoc, + Tok.getLocation())); + ConsumeToken(); // Eat the identifier. + continue; + } + + // We must have either an array designator now or an objc message send. + assert(Tok.is(tok::l_square) && "Unexpected token!"); + + // Handle the two forms of array designator: + // array-designator: '[' constant-expression ']' + // array-designator: '[' constant-expression '...' constant-expression ']' + // + // Also, we have to handle the case where the expression after the + // designator an an objc message send: '[' objc-message-expr ']'. + // Interesting cases are: + // [foo bar] -> objc message send + // [foo] -> array designator + // [foo ... bar] -> array designator + // [4][foo bar] -> obsolete GNU designation with objc message send. + // + // We do not need to check for an expression starting with [[ here. If it + // contains an Objective-C message send, then it is not an ill-formed + // attribute. If it is a lambda-expression within an array-designator, then + // it will be rejected because a constant-expression cannot begin with a + // lambda-expression. + InMessageExpressionRAIIObject InMessage(*this, true); + + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + SourceLocation StartLoc = T.getOpenLocation(); + + ExprResult Idx; + + // If Objective-C is enabled and this is a typename (class message + // send) or send to 'super', parse this as a message send + // expression. We handle C++ and C separately, since C++ requires + // much more complicated parsing. + if (getLangOpts().ObjC1 && getLangOpts().CPlusPlus) { + // Send to 'super'. + if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super && + NextToken().isNot(tok::period) && + getCurScope()->isInObjcMethodScope()) { + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + ConsumeToken(), + ParsedType(), + 0); + } + + // Parse the receiver, which is either a type or an expression. + bool IsExpr; + void *TypeOrExpr; + if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) { + SkipUntil(tok::r_square); + return ExprError(); + } + + // If the receiver was a type, we have a class message; parse + // the rest of it. + if (!IsExpr) { + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + SourceLocation(), + ParsedType::getFromOpaquePtr(TypeOrExpr), + 0); + } + + // If the receiver was an expression, we still don't know + // whether we have a message send or an array designator; just + // adopt the expression for further analysis below. + // FIXME: potentially-potentially evaluated expression above? + Idx = ExprResult(static_cast(TypeOrExpr)); + } else if (getLangOpts().ObjC1 && Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + SourceLocation IILoc = Tok.getLocation(); + ParsedType ReceiverType; + // Three cases. This is a message send to a type: [type foo] + // This is a message send to super: [super foo] + // This is a message sent to an expr: [super.bar foo] + switch (Sema::ObjCMessageKind Kind + = Actions.getObjCMessageKind(getCurScope(), II, IILoc, + II == Ident_super, + NextToken().is(tok::period), + ReceiverType)) { + case Sema::ObjCSuperMessage: + case Sema::ObjCClassMessage: + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + if (Kind == Sema::ObjCSuperMessage) + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + ConsumeToken(), + ParsedType(), + 0); + ConsumeToken(); // the identifier + if (!ReceiverType) { + SkipUntil(tok::r_square); + return ExprError(); + } + + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + SourceLocation(), + ReceiverType, + 0); + + case Sema::ObjCInstanceMessage: + // Fall through; we'll just parse the expression and + // (possibly) treat this like an Objective-C message send + // later. + break; + } + } + + // Parse the index expression, if we haven't already gotten one + // above (which can only happen in Objective-C++). + // Note that we parse this as an assignment expression, not a constant + // expression (allowing *=, =, etc) to handle the objc case. Sema needs + // to validate that the expression is a constant. + // FIXME: We also need to tell Sema that we're in a + // potentially-potentially evaluated context. + if (!Idx.get()) { + Idx = ParseAssignmentExpression(); + if (Idx.isInvalid()) { + SkipUntil(tok::r_square); + return move(Idx); + } + } + + // Given an expression, we could either have a designator (if the next + // tokens are '...' or ']' or an objc message send. If this is an objc + // message send, handle it now. An objc-message send is the start of + // an assignment-expression production. + if (getLangOpts().ObjC1 && Tok.isNot(tok::ellipsis) && + Tok.isNot(tok::r_square)) { + CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig); + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + SourceLocation(), + ParsedType(), + Idx.take()); + } + + // If this is a normal array designator, remember it. + if (Tok.isNot(tok::ellipsis)) { + Desig.AddDesignator(Designator::getArray(Idx.release(), StartLoc)); + } else { + // Handle the gnu array range extension. + Diag(Tok, diag::ext_gnu_array_range); + SourceLocation EllipsisLoc = ConsumeToken(); + + ExprResult RHS(ParseConstantExpression()); + if (RHS.isInvalid()) { + SkipUntil(tok::r_square); + return move(RHS); + } + Desig.AddDesignator(Designator::getArrayRange(Idx.release(), + RHS.release(), + StartLoc, EllipsisLoc)); + } + + T.consumeClose(); + Desig.getDesignator(Desig.getNumDesignators() - 1).setRBracketLoc( + T.getCloseLocation()); + } + + // Okay, we're done with the designator sequence. We know that there must be + // at least one designator, because the only case we can get into this method + // without a designator is when we have an objc message send. That case is + // handled and returned from above. + assert(!Desig.empty() && "Designator is empty?"); + + // Handle a normal designator sequence end, which is an equal. + if (Tok.is(tok::equal)) { + SourceLocation EqualLoc = ConsumeToken(); + return Actions.ActOnDesignatedInitializer(Desig, EqualLoc, false, + ParseInitializer()); + } + + // We read some number of designators and found something that isn't an = or + // an initializer. If we have exactly one array designator, this + // is the GNU 'designation: array-designator' extension. Otherwise, it is a + // parse error. + if (Desig.getNumDesignators() == 1 && + (Desig.getDesignator(0).isArrayDesignator() || + Desig.getDesignator(0).isArrayRangeDesignator())) { + Diag(Tok, diag::ext_gnu_missing_equal_designator) + << FixItHint::CreateInsertion(Tok.getLocation(), "= "); + return Actions.ActOnDesignatedInitializer(Desig, Tok.getLocation(), + true, ParseInitializer()); + } + + Diag(Tok, diag::err_expected_equal_designator); + return ExprError(); +} + + +/// ParseBraceInitializer - Called when parsing an initializer that has a +/// leading open brace. +/// +/// initializer: [C99 6.7.8] +/// '{' initializer-list '}' +/// '{' initializer-list ',' '}' +/// [GNU] '{' '}' +/// +/// initializer-list: +/// designation[opt] initializer ...[opt] +/// initializer-list ',' designation[opt] initializer ...[opt] +/// +ExprResult Parser::ParseBraceInitializer() { + InMessageExpressionRAIIObject InMessage(*this, false); + + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); + SourceLocation LBraceLoc = T.getOpenLocation(); + + /// InitExprs - This is the actual list of expressions contained in the + /// initializer. + ExprVector InitExprs(Actions); + + if (Tok.is(tok::r_brace)) { + // Empty initializers are a C++ feature and a GNU extension to C. + if (!getLangOpts().CPlusPlus) + Diag(LBraceLoc, diag::ext_gnu_empty_initializer); + // Match the '}'. + return Actions.ActOnInitList(LBraceLoc, MultiExprArg(Actions), + ConsumeBrace()); + } + + bool InitExprsOk = true; + + while (1) { + // Handle Microsoft __if_exists/if_not_exists if necessary. + if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) || + Tok.is(tok::kw___if_not_exists))) { + if (ParseMicrosoftIfExistsBraceInitializer(InitExprs, InitExprsOk)) { + if (Tok.isNot(tok::comma)) break; + ConsumeToken(); + } + if (Tok.is(tok::r_brace)) break; + continue; + } + + // Parse: designation[opt] initializer + + // If we know that this cannot be a designation, just parse the nested + // initializer directly. + ExprResult SubElt; + if (MayBeDesignationStart()) + SubElt = ParseInitializerWithPotentialDesignator(); + else + SubElt = ParseInitializer(); + + if (Tok.is(tok::ellipsis)) + SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken()); + + // If we couldn't parse the subelement, bail out. + if (!SubElt.isInvalid()) { + InitExprs.push_back(SubElt.release()); + } else { + InitExprsOk = false; + + // We have two ways to try to recover from this error: if the code looks + // grammatically ok (i.e. we have a comma coming up) try to continue + // parsing the rest of the initializer. This allows us to emit + // diagnostics for later elements that we find. If we don't see a comma, + // assume there is a parse error, and just skip to recover. + // FIXME: This comment doesn't sound right. If there is a r_brace + // immediately, it can't be an error, since there is no other way of + // leaving this loop except through this if. + if (Tok.isNot(tok::comma)) { + SkipUntil(tok::r_brace, false, true); + break; + } + } + + // If we don't have a comma continued list, we're done. + if (Tok.isNot(tok::comma)) break; + + // TODO: save comma locations if some client cares. + ConsumeToken(); + + // Handle trailing comma. + if (Tok.is(tok::r_brace)) break; + } + + bool closed = !T.consumeClose(); + + if (InitExprsOk && closed) + return Actions.ActOnInitList(LBraceLoc, move_arg(InitExprs), + T.getCloseLocation()); + + return ExprError(); // an error occurred. +} + + +// Return true if a comma (or closing brace) is necessary after the +// __if_exists/if_not_exists statement. +bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs, + bool &InitExprsOk) { + bool trailingComma = false; + IfExistsCondition Result; + if (ParseMicrosoftIfExistsCondition(Result)) + return false; + + BalancedDelimiterTracker Braces(*this, tok::l_brace); + if (Braces.consumeOpen()) { + Diag(Tok, diag::err_expected_lbrace); + return false; + } + + switch (Result.Behavior) { + case IEB_Parse: + // Parse the declarations below. + break; + + case IEB_Dependent: + Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists) + << Result.IsIfExists; + // Fall through to skip. + + case IEB_Skip: + Braces.skipToEnd(); + return false; + } + + while (Tok.isNot(tok::eof)) { + trailingComma = false; + // If we know that this cannot be a designation, just parse the nested + // initializer directly. + ExprResult SubElt; + if (MayBeDesignationStart()) + SubElt = ParseInitializerWithPotentialDesignator(); + else + SubElt = ParseInitializer(); + + if (Tok.is(tok::ellipsis)) + SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken()); + + // If we couldn't parse the subelement, bail out. + if (!SubElt.isInvalid()) + InitExprs.push_back(SubElt.release()); + else + InitExprsOk = false; + + if (Tok.is(tok::comma)) { + ConsumeToken(); + trailingComma = true; + } + + if (Tok.is(tok::r_brace)) + break; + } + + Braces.consumeClose(); + + return !trailingComma; +} diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp new file mode 100644 index 0000000..789a8ae --- /dev/null +++ b/clang/lib/Parse/ParseObjc.cpp @@ -0,0 +1,2846 @@ +//===--- ParseObjC.cpp - Objective C Parsing ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Objective-C portions of the Parser interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "RAIIObjectsForParser.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/PrettyDeclStackTrace.h" +#include "clang/Sema/Scope.h" +#include "llvm/ADT/SmallVector.h" +using namespace clang; + + +/// ParseObjCAtDirectives - Handle parts of the external-declaration production: +/// external-declaration: [C99 6.9] +/// [OBJC] objc-class-definition +/// [OBJC] objc-class-declaration +/// [OBJC] objc-alias-declaration +/// [OBJC] objc-protocol-definition +/// [OBJC] objc-method-definition +/// [OBJC] '@' 'end' +Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() { + SourceLocation AtLoc = ConsumeToken(); // the "@" + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtDirective(getCurScope()); + cutOffParsing(); + return DeclGroupPtrTy(); + } + + Decl *SingleDecl = 0; + switch (Tok.getObjCKeywordID()) { + case tok::objc_class: + return ParseObjCAtClassDeclaration(AtLoc); + case tok::objc_interface: { + ParsedAttributes attrs(AttrFactory); + SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, attrs); + break; + } + case tok::objc_protocol: { + ParsedAttributes attrs(AttrFactory); + return ParseObjCAtProtocolDeclaration(AtLoc, attrs); + } + case tok::objc_implementation: + return ParseObjCAtImplementationDeclaration(AtLoc); + case tok::objc_end: + return ParseObjCAtEndDeclaration(AtLoc); + case tok::objc_compatibility_alias: + SingleDecl = ParseObjCAtAliasDeclaration(AtLoc); + break; + case tok::objc_synthesize: + SingleDecl = ParseObjCPropertySynthesize(AtLoc); + break; + case tok::objc_dynamic: + SingleDecl = ParseObjCPropertyDynamic(AtLoc); + break; + case tok::objc___experimental_modules_import: + if (getLangOpts().Modules) + return ParseModuleImport(AtLoc); + + // Fall through + + default: + Diag(AtLoc, diag::err_unexpected_at); + SkipUntil(tok::semi); + SingleDecl = 0; + break; + } + return Actions.ConvertDeclToDeclGroup(SingleDecl); +} + +/// +/// objc-class-declaration: +/// '@' 'class' identifier-list ';' +/// +Parser::DeclGroupPtrTy +Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { + ConsumeToken(); // the identifier "class" + SmallVector ClassNames; + SmallVector ClassLocs; + + + while (1) { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::semi); + return Actions.ConvertDeclToDeclGroup(0); + } + ClassNames.push_back(Tok.getIdentifierInfo()); + ClassLocs.push_back(Tok.getLocation()); + ConsumeToken(); + + if (Tok.isNot(tok::comma)) + break; + + ConsumeToken(); + } + + // Consume the ';'. + if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class")) + return Actions.ConvertDeclToDeclGroup(0); + + return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(), + ClassLocs.data(), + ClassNames.size()); +} + +void Parser::CheckNestedObjCContexts(SourceLocation AtLoc) +{ + Sema::ObjCContainerKind ock = Actions.getObjCContainerKind(); + if (ock == Sema::OCK_None) + return; + + Decl *Decl = Actions.getObjCDeclContext(); + if (CurParsedObjCImpl) { + CurParsedObjCImpl->finish(AtLoc); + } else { + Actions.ActOnAtEnd(getCurScope(), AtLoc); + } + Diag(AtLoc, diag::err_objc_missing_end) + << FixItHint::CreateInsertion(AtLoc, "@end\n"); + if (Decl) + Diag(Decl->getLocStart(), diag::note_objc_container_start) + << (int) ock; +} + +/// +/// objc-interface: +/// objc-class-interface-attributes[opt] objc-class-interface +/// objc-category-interface +/// +/// objc-class-interface: +/// '@' 'interface' identifier objc-superclass[opt] +/// objc-protocol-refs[opt] +/// objc-class-instance-variables[opt] +/// objc-interface-decl-list +/// @end +/// +/// objc-category-interface: +/// '@' 'interface' identifier '(' identifier[opt] ')' +/// objc-protocol-refs[opt] +/// objc-interface-decl-list +/// @end +/// +/// objc-superclass: +/// ':' identifier +/// +/// objc-class-interface-attributes: +/// __attribute__((visibility("default"))) +/// __attribute__((visibility("hidden"))) +/// __attribute__((deprecated)) +/// __attribute__((unavailable)) +/// __attribute__((objc_exception)) - used by NSException on 64-bit +/// __attribute__((objc_root_class)) +/// +Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, + ParsedAttributes &attrs) { + assert(Tok.isObjCAtKeyword(tok::objc_interface) && + "ParseObjCAtInterfaceDeclaration(): Expected @interface"); + CheckNestedObjCContexts(AtLoc); + ConsumeToken(); // the "interface" identifier + + // Code completion after '@interface'. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCInterfaceDecl(getCurScope()); + cutOffParsing(); + return 0; + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing class or category name. + return 0; + } + + // We have a class or category name - consume it. + IdentifierInfo *nameId = Tok.getIdentifierInfo(); + SourceLocation nameLoc = ConsumeToken(); + if (Tok.is(tok::l_paren) && + !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category. + + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + SourceLocation categoryLoc; + IdentifierInfo *categoryId = 0; + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc); + cutOffParsing(); + return 0; + } + + // For ObjC2, the category name is optional (not an error). + if (Tok.is(tok::identifier)) { + categoryId = Tok.getIdentifierInfo(); + categoryLoc = ConsumeToken(); + } + else if (!getLangOpts().ObjC2) { + Diag(Tok, diag::err_expected_ident); // missing category name. + return 0; + } + + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) + return 0; + + if (!attrs.empty()) { // categories don't support attributes. + Diag(nameLoc, diag::err_objc_no_attributes_on_category); + attrs.clear(); + } + + // Next, we need to check for any protocol references. + SourceLocation LAngleLoc, EndProtoLoc; + SmallVector ProtocolRefs; + SmallVector ProtocolLocs; + if (Tok.is(tok::less) && + ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, + LAngleLoc, EndProtoLoc)) + return 0; + + Decl *CategoryType = + Actions.ActOnStartCategoryInterface(AtLoc, + nameId, nameLoc, + categoryId, categoryLoc, + ProtocolRefs.data(), + ProtocolRefs.size(), + ProtocolLocs.data(), + EndProtoLoc); + + if (Tok.is(tok::l_brace)) + ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc); + + ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType); + return CategoryType; + } + // Parse a class interface. + IdentifierInfo *superClassId = 0; + SourceLocation superClassLoc; + + if (Tok.is(tok::colon)) { // a super class is specified. + ConsumeToken(); + + // Code completion of superclass names. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc); + cutOffParsing(); + return 0; + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing super class name. + return 0; + } + superClassId = Tok.getIdentifierInfo(); + superClassLoc = ConsumeToken(); + } + // Next, we need to check for any protocol references. + SmallVector ProtocolRefs; + SmallVector ProtocolLocs; + SourceLocation LAngleLoc, EndProtoLoc; + if (Tok.is(tok::less) && + ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, + LAngleLoc, EndProtoLoc)) + return 0; + + Decl *ClsType = + Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, + superClassId, superClassLoc, + ProtocolRefs.data(), ProtocolRefs.size(), + ProtocolLocs.data(), + EndProtoLoc, attrs.getList()); + + if (Tok.is(tok::l_brace)) + ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc); + + ParseObjCInterfaceDeclList(tok::objc_interface, ClsType); + return ClsType; +} + +/// The Objective-C property callback. This should be defined where +/// it's used, but instead it's been lifted to here to support VS2005. +struct Parser::ObjCPropertyCallback : FieldCallback { +private: + virtual void anchor(); +public: + Parser &P; + SmallVectorImpl &Props; + ObjCDeclSpec &OCDS; + SourceLocation AtLoc; + SourceLocation LParenLoc; + tok::ObjCKeywordKind MethodImplKind; + + ObjCPropertyCallback(Parser &P, + SmallVectorImpl &Props, + ObjCDeclSpec &OCDS, SourceLocation AtLoc, + SourceLocation LParenLoc, + tok::ObjCKeywordKind MethodImplKind) : + P(P), Props(Props), OCDS(OCDS), AtLoc(AtLoc), LParenLoc(LParenLoc), + MethodImplKind(MethodImplKind) { + } + + Decl *invoke(FieldDeclarator &FD) { + if (FD.D.getIdentifier() == 0) { + P.Diag(AtLoc, diag::err_objc_property_requires_field_name) + << FD.D.getSourceRange(); + return 0; + } + if (FD.BitfieldSize) { + P.Diag(AtLoc, diag::err_objc_property_bitfield) + << FD.D.getSourceRange(); + return 0; + } + + // Install the property declarator into interfaceDecl. + IdentifierInfo *SelName = + OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); + + Selector GetterSel = + P.PP.getSelectorTable().getNullarySelector(SelName); + IdentifierInfo *SetterName = OCDS.getSetterName(); + Selector SetterSel; + if (SetterName) + SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName); + else + SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(), + P.PP.getSelectorTable(), + FD.D.getIdentifier()); + bool isOverridingProperty = false; + Decl *Property = + P.Actions.ActOnProperty(P.getCurScope(), AtLoc, LParenLoc, + FD, OCDS, + GetterSel, SetterSel, + &isOverridingProperty, + MethodImplKind); + if (!isOverridingProperty) + Props.push_back(Property); + + return Property; + } +}; + +void Parser::ObjCPropertyCallback::anchor() { +} + +/// objc-interface-decl-list: +/// empty +/// objc-interface-decl-list objc-property-decl [OBJC2] +/// objc-interface-decl-list objc-method-requirement [OBJC2] +/// objc-interface-decl-list objc-method-proto ';' +/// objc-interface-decl-list declaration +/// objc-interface-decl-list ';' +/// +/// objc-method-requirement: [OBJC2] +/// @required +/// @optional +/// +void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, + Decl *CDecl) { + SmallVector allMethods; + SmallVector allProperties; + SmallVector allTUVariables; + tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword; + + SourceRange AtEnd; + + while (1) { + // If this is a method prototype, parse it. + if (Tok.is(tok::minus) || Tok.is(tok::plus)) { + Decl *methodPrototype = + ParseObjCMethodPrototype(MethodImplKind, false); + allMethods.push_back(methodPrototype); + // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for + // method definitions. + if (ExpectAndConsumeSemi(diag::err_expected_semi_after_method_proto)) { + // We didn't find a semi and we error'ed out. Skip until a ';' or '@'. + SkipUntil(tok::at, /*StopAtSemi=*/true, /*DontConsume=*/true); + if (Tok.is(tok::semi)) + ConsumeToken(); + } + continue; + } + if (Tok.is(tok::l_paren)) { + Diag(Tok, diag::err_expected_minus_or_plus); + ParseObjCMethodDecl(Tok.getLocation(), + tok::minus, + MethodImplKind, false); + continue; + } + // Ignore excess semicolons. + if (Tok.is(tok::semi)) { + ConsumeToken(); + continue; + } + + // If we got to the end of the file, exit the loop. + if (Tok.is(tok::eof)) + break; + + // Code completion within an Objective-C interface. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(getCurScope(), + CurParsedObjCImpl? Sema::PCC_ObjCImplementation + : Sema::PCC_ObjCInterface); + return cutOffParsing(); + } + + // If we don't have an @ directive, parse it as a function definition. + if (Tok.isNot(tok::at)) { + // The code below does not consume '}'s because it is afraid of eating the + // end of a namespace. Because of the way this code is structured, an + // erroneous r_brace would cause an infinite loop if not handled here. + if (Tok.is(tok::r_brace)) + break; + ParsedAttributes attrs(AttrFactory); + allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs)); + continue; + } + + // Otherwise, we have an @ directive, eat the @. + SourceLocation AtLoc = ConsumeToken(); // the "@" + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtDirective(getCurScope()); + return cutOffParsing(); + } + + tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID(); + + if (DirectiveKind == tok::objc_end) { // @end -> terminate list + AtEnd.setBegin(AtLoc); + AtEnd.setEnd(Tok.getLocation()); + break; + } else if (DirectiveKind == tok::objc_not_keyword) { + Diag(Tok, diag::err_objc_unknown_at); + SkipUntil(tok::semi); + continue; + } + + // Eat the identifier. + ConsumeToken(); + + switch (DirectiveKind) { + default: + // FIXME: If someone forgets an @end on a protocol, this loop will + // continue to eat up tons of stuff and spew lots of nonsense errors. It + // would probably be better to bail out if we saw an @class or @interface + // or something like that. + Diag(AtLoc, diag::err_objc_illegal_interface_qual); + // Skip until we see an '@' or '}' or ';'. + SkipUntil(tok::r_brace, tok::at); + break; + + case tok::objc_implementation: + case tok::objc_interface: + Diag(AtLoc, diag::err_objc_missing_end) + << FixItHint::CreateInsertion(AtLoc, "@end\n"); + Diag(CDecl->getLocStart(), diag::note_objc_container_start) + << (int) Actions.getObjCContainerKind(); + ConsumeToken(); + break; + + case tok::objc_required: + case tok::objc_optional: + // This is only valid on protocols. + // FIXME: Should this check for ObjC2 being enabled? + if (contextKey != tok::objc_protocol) + Diag(AtLoc, diag::err_objc_directive_only_in_protocol); + else + MethodImplKind = DirectiveKind; + break; + + case tok::objc_property: + if (!getLangOpts().ObjC2) + Diag(AtLoc, diag::err_objc_properties_require_objc2); + + ObjCDeclSpec OCDS; + SourceLocation LParenLoc; + // Parse property attribute list, if any. + if (Tok.is(tok::l_paren)) { + LParenLoc = Tok.getLocation(); + ParseObjCPropertyAttribute(OCDS); + } + + ObjCPropertyCallback Callback(*this, allProperties, + OCDS, AtLoc, LParenLoc, MethodImplKind); + + // Parse all the comma separated declarators. + DeclSpec DS(AttrFactory); + ParseStructDeclaration(DS, Callback); + + ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list); + break; + } + } + + // We break out of the big loop in two cases: when we see @end or when we see + // EOF. In the former case, eat the @end. In the later case, emit an error. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtDirective(getCurScope()); + return cutOffParsing(); + } else if (Tok.isObjCAtKeyword(tok::objc_end)) { + ConsumeToken(); // the "end" identifier + } else { + Diag(Tok, diag::err_objc_missing_end) + << FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n"); + Diag(CDecl->getLocStart(), diag::note_objc_container_start) + << (int) Actions.getObjCContainerKind(); + AtEnd.setBegin(Tok.getLocation()); + AtEnd.setEnd(Tok.getLocation()); + } + + // Insert collected methods declarations into the @interface object. + // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit. + Actions.ActOnAtEnd(getCurScope(), AtEnd, + allMethods.data(), allMethods.size(), + allProperties.data(), allProperties.size(), + allTUVariables.data(), allTUVariables.size()); +} + +/// Parse property attribute declarations. +/// +/// property-attr-decl: '(' property-attrlist ')' +/// property-attrlist: +/// property-attribute +/// property-attrlist ',' property-attribute +/// property-attribute: +/// getter '=' identifier +/// setter '=' identifier ':' +/// readonly +/// readwrite +/// assign +/// retain +/// copy +/// nonatomic +/// atomic +/// strong +/// weak +/// unsafe_unretained +/// +void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { + assert(Tok.getKind() == tok::l_paren); + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + while (1) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS); + return cutOffParsing(); + } + const IdentifierInfo *II = Tok.getIdentifierInfo(); + + // If this is not an identifier at all, bail out early. + if (II == 0) { + T.consumeClose(); + return; + } + + SourceLocation AttrName = ConsumeToken(); // consume last attribute name + + if (II->isStr("readonly")) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly); + else if (II->isStr("assign")) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign); + else if (II->isStr("unsafe_unretained")) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_unsafe_unretained); + else if (II->isStr("readwrite")) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite); + else if (II->isStr("retain")) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain); + else if (II->isStr("strong")) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_strong); + else if (II->isStr("copy")) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy); + else if (II->isStr("nonatomic")) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic); + else if (II->isStr("atomic")) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_atomic); + else if (II->isStr("weak")) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_weak); + else if (II->isStr("getter") || II->isStr("setter")) { + bool IsSetter = II->getNameStart()[0] == 's'; + + // getter/setter require extra treatment. + unsigned DiagID = IsSetter ? diag::err_objc_expected_equal_for_setter : + diag::err_objc_expected_equal_for_getter; + + if (ExpectAndConsume(tok::equal, DiagID, "", tok::r_paren)) + return; + + if (Tok.is(tok::code_completion)) { + if (IsSetter) + Actions.CodeCompleteObjCPropertySetter(getCurScope()); + else + Actions.CodeCompleteObjCPropertyGetter(getCurScope()); + return cutOffParsing(); + } + + + SourceLocation SelLoc; + IdentifierInfo *SelIdent = ParseObjCSelectorPiece(SelLoc); + + if (!SelIdent) { + Diag(Tok, diag::err_objc_expected_selector_for_getter_setter) + << IsSetter; + SkipUntil(tok::r_paren); + return; + } + + if (IsSetter) { + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter); + DS.setSetterName(SelIdent); + + if (ExpectAndConsume(tok::colon, + diag::err_expected_colon_after_setter_name, "", + tok::r_paren)) + return; + } else { + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter); + DS.setGetterName(SelIdent); + } + } else { + Diag(AttrName, diag::err_objc_expected_property_attr) << II; + SkipUntil(tok::r_paren); + return; + } + + if (Tok.isNot(tok::comma)) + break; + + ConsumeToken(); + } + + T.consumeClose(); +} + +/// objc-method-proto: +/// objc-instance-method objc-method-decl objc-method-attributes[opt] +/// objc-class-method objc-method-decl objc-method-attributes[opt] +/// +/// objc-instance-method: '-' +/// objc-class-method: '+' +/// +/// objc-method-attributes: [OBJC2] +/// __attribute__((deprecated)) +/// +Decl *Parser::ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind, + bool MethodDefinition) { + assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-"); + + tok::TokenKind methodType = Tok.getKind(); + SourceLocation mLoc = ConsumeToken(); + Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, MethodImplKind, + MethodDefinition); + // Since this rule is used for both method declarations and definitions, + // the caller is (optionally) responsible for consuming the ';'. + return MDecl; +} + +/// objc-selector: +/// identifier +/// one of +/// enum struct union if else while do for switch case default +/// break continue return goto asm sizeof typeof __alignof +/// unsigned long const short volatile signed restrict _Complex +/// in out inout bycopy byref oneway int char float double void _Bool +/// +IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) { + + switch (Tok.getKind()) { + default: + return 0; + case tok::ampamp: + case tok::ampequal: + case tok::amp: + case tok::pipe: + case tok::tilde: + case tok::exclaim: + case tok::exclaimequal: + case tok::pipepipe: + case tok::pipeequal: + case tok::caret: + case tok::caretequal: { + std::string ThisTok(PP.getSpelling(Tok)); + if (isalpha(ThisTok[0])) { + IdentifierInfo *II = &PP.getIdentifierTable().get(ThisTok.data()); + Tok.setKind(tok::identifier); + SelectorLoc = ConsumeToken(); + return II; + } + return 0; + } + + case tok::identifier: + case tok::kw_asm: + case tok::kw_auto: + case tok::kw_bool: + case tok::kw_break: + case tok::kw_case: + case tok::kw_catch: + case tok::kw_char: + case tok::kw_class: + case tok::kw_const: + case tok::kw_const_cast: + case tok::kw_continue: + case tok::kw_default: + case tok::kw_delete: + case tok::kw_do: + case tok::kw_double: + case tok::kw_dynamic_cast: + case tok::kw_else: + case tok::kw_enum: + case tok::kw_explicit: + case tok::kw_export: + case tok::kw_extern: + case tok::kw_false: + case tok::kw_float: + case tok::kw_for: + case tok::kw_friend: + case tok::kw_goto: + case tok::kw_if: + case tok::kw_inline: + case tok::kw_int: + case tok::kw_long: + case tok::kw_mutable: + case tok::kw_namespace: + case tok::kw_new: + case tok::kw_operator: + case tok::kw_private: + case tok::kw_protected: + case tok::kw_public: + case tok::kw_register: + case tok::kw_reinterpret_cast: + case tok::kw_restrict: + case tok::kw_return: + case tok::kw_short: + case tok::kw_signed: + case tok::kw_sizeof: + case tok::kw_static: + case tok::kw_static_cast: + case tok::kw_struct: + case tok::kw_switch: + case tok::kw_template: + case tok::kw_this: + case tok::kw_throw: + case tok::kw_true: + case tok::kw_try: + case tok::kw_typedef: + case tok::kw_typeid: + case tok::kw_typename: + case tok::kw_typeof: + case tok::kw_union: + case tok::kw_unsigned: + case tok::kw_using: + case tok::kw_virtual: + case tok::kw_void: + case tok::kw_volatile: + case tok::kw_wchar_t: + case tok::kw_while: + case tok::kw__Bool: + case tok::kw__Complex: + case tok::kw___alignof: + IdentifierInfo *II = Tok.getIdentifierInfo(); + SelectorLoc = ConsumeToken(); + return II; + } +} + +/// objc-for-collection-in: 'in' +/// +bool Parser::isTokIdentifier_in() const { + // FIXME: May have to do additional look-ahead to only allow for + // valid tokens following an 'in'; such as an identifier, unary operators, + // '[' etc. + return (getLangOpts().ObjC2 && Tok.is(tok::identifier) && + Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]); +} + +/// ParseObjCTypeQualifierList - This routine parses the objective-c's type +/// qualifier list and builds their bitmask representation in the input +/// argument. +/// +/// objc-type-qualifiers: +/// objc-type-qualifier +/// objc-type-qualifiers objc-type-qualifier +/// +void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, + Declarator::TheContext Context) { + assert(Context == Declarator::ObjCParameterContext || + Context == Declarator::ObjCResultContext); + + while (1) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCPassingType(getCurScope(), DS, + Context == Declarator::ObjCParameterContext); + return cutOffParsing(); + } + + if (Tok.isNot(tok::identifier)) + return; + + const IdentifierInfo *II = Tok.getIdentifierInfo(); + for (unsigned i = 0; i != objc_NumQuals; ++i) { + if (II != ObjCTypeQuals[i]) + continue; + + ObjCDeclSpec::ObjCDeclQualifier Qual; + switch (i) { + default: llvm_unreachable("Unknown decl qualifier"); + case objc_in: Qual = ObjCDeclSpec::DQ_In; break; + case objc_out: Qual = ObjCDeclSpec::DQ_Out; break; + case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break; + case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break; + case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break; + case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break; + } + DS.setObjCDeclQualifier(Qual); + ConsumeToken(); + II = 0; + break; + } + + // If this wasn't a recognized qualifier, bail out. + if (II) return; + } +} + +/// Take all the decl attributes out of the given list and add +/// them to the given attribute set. +static void takeDeclAttributes(ParsedAttributes &attrs, + AttributeList *list) { + while (list) { + AttributeList *cur = list; + list = cur->getNext(); + + if (!cur->isUsedAsTypeAttr()) { + // Clear out the next pointer. We're really completely + // destroying the internal invariants of the declarator here, + // but it doesn't matter because we're done with it. + cur->setNext(0); + attrs.add(cur); + } + } +} + +/// takeDeclAttributes - Take all the decl attributes from the given +/// declarator and add them to the given list. +static void takeDeclAttributes(ParsedAttributes &attrs, + Declarator &D) { + // First, take ownership of all attributes. + attrs.getPool().takeAllFrom(D.getAttributePool()); + attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool()); + + // Now actually move the attributes over. + takeDeclAttributes(attrs, D.getDeclSpec().getAttributes().getList()); + takeDeclAttributes(attrs, D.getAttributes()); + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) + takeDeclAttributes(attrs, + const_cast(D.getTypeObject(i).getAttrs())); +} + +/// objc-type-name: +/// '(' objc-type-qualifiers[opt] type-name ')' +/// '(' objc-type-qualifiers[opt] ')' +/// +ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, + Declarator::TheContext context, + ParsedAttributes *paramAttrs) { + assert(context == Declarator::ObjCParameterContext || + context == Declarator::ObjCResultContext); + assert((paramAttrs != 0) == (context == Declarator::ObjCParameterContext)); + + assert(Tok.is(tok::l_paren) && "expected ("); + + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + SourceLocation TypeStartLoc = Tok.getLocation(); + ObjCDeclContextSwitch ObjCDC(*this); + + // Parse type qualifiers, in, inout, etc. + ParseObjCTypeQualifierList(DS, context); + + ParsedType Ty; + if (isTypeSpecifierQualifier()) { + // Parse an abstract declarator. + DeclSpec declSpec(AttrFactory); + declSpec.setObjCQualifiers(&DS); + ParseSpecifierQualifierList(declSpec); + Declarator declarator(declSpec, context); + ParseDeclarator(declarator); + + // If that's not invalid, extract a type. + if (!declarator.isInvalidType()) { + TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator); + if (!type.isInvalid()) + Ty = type.get(); + + // If we're parsing a parameter, steal all the decl attributes + // and add them to the decl spec. + if (context == Declarator::ObjCParameterContext) + takeDeclAttributes(*paramAttrs, declarator); + } + } else if (context == Declarator::ObjCResultContext && + Tok.is(tok::identifier)) { + if (!Ident_instancetype) + Ident_instancetype = PP.getIdentifierInfo("instancetype"); + + if (Tok.getIdentifierInfo() == Ident_instancetype) { + Ty = Actions.ActOnObjCInstanceType(Tok.getLocation()); + ConsumeToken(); + } + } + + if (Tok.is(tok::r_paren)) + T.consumeClose(); + else if (Tok.getLocation() == TypeStartLoc) { + // If we didn't eat any tokens, then this isn't a type. + Diag(Tok, diag::err_expected_type); + SkipUntil(tok::r_paren); + } else { + // Otherwise, we found *something*, but didn't get a ')' in the right + // place. Emit an error then return what we have as the type. + T.consumeClose(); + } + return Ty; +} + +/// objc-method-decl: +/// objc-selector +/// objc-keyword-selector objc-parmlist[opt] +/// objc-type-name objc-selector +/// objc-type-name objc-keyword-selector objc-parmlist[opt] +/// +/// objc-keyword-selector: +/// objc-keyword-decl +/// objc-keyword-selector objc-keyword-decl +/// +/// objc-keyword-decl: +/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier +/// objc-selector ':' objc-keyword-attributes[opt] identifier +/// ':' objc-type-name objc-keyword-attributes[opt] identifier +/// ':' objc-keyword-attributes[opt] identifier +/// +/// objc-parmlist: +/// objc-parms objc-ellipsis[opt] +/// +/// objc-parms: +/// objc-parms , parameter-declaration +/// +/// objc-ellipsis: +/// , ... +/// +/// objc-keyword-attributes: [OBJC2] +/// __attribute__((unused)) +/// +Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, + tok::TokenKind mType, + tok::ObjCKeywordKind MethodImplKind, + bool MethodDefinition) { + ParsingDeclRAIIObject PD(*this); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, + /*ReturnType=*/ ParsedType()); + cutOffParsing(); + return 0; + } + + // Parse the return type if present. + ParsedType ReturnType; + ObjCDeclSpec DSRet; + if (Tok.is(tok::l_paren)) + ReturnType = ParseObjCTypeName(DSRet, Declarator::ObjCResultContext, 0); + + // If attributes exist before the method, parse them. + ParsedAttributes methodAttrs(AttrFactory); + if (getLangOpts().ObjC2) + MaybeParseGNUAttributes(methodAttrs); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, + ReturnType); + cutOffParsing(); + return 0; + } + + // Now parse the selector. + SourceLocation selLoc; + IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc); + + // An unnamed colon is valid. + if (!SelIdent && Tok.isNot(tok::colon)) { // missing selector name. + Diag(Tok, diag::err_expected_selector_for_method) + << SourceRange(mLoc, Tok.getLocation()); + // Skip until we get a ; or {}. + SkipUntil(tok::r_brace); + return 0; + } + + SmallVector CParamInfo; + if (Tok.isNot(tok::colon)) { + // If attributes exist after the method, parse them. + if (getLangOpts().ObjC2) + MaybeParseGNUAttributes(methodAttrs); + + Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); + Decl *Result + = Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(), + mType, DSRet, ReturnType, + selLoc, Sel, 0, + CParamInfo.data(), CParamInfo.size(), + methodAttrs.getList(), MethodImplKind, + false, MethodDefinition); + PD.complete(Result); + return Result; + } + + SmallVector KeyIdents; + SmallVector KeyLocs; + SmallVector ArgInfos; + ParseScope PrototypeScope(this, + Scope::FunctionPrototypeScope|Scope::DeclScope); + + AttributePool allParamAttrs(AttrFactory); + + while (1) { + ParsedAttributes paramAttrs(AttrFactory); + Sema::ObjCArgInfo ArgInfo; + + // Each iteration parses a single keyword argument. + if (Tok.isNot(tok::colon)) { + Diag(Tok, diag::err_expected_colon); + break; + } + ConsumeToken(); // Eat the ':'. + + ArgInfo.Type = ParsedType(); + if (Tok.is(tok::l_paren)) // Parse the argument type if present. + ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, + Declarator::ObjCParameterContext, + ¶mAttrs); + + // If attributes exist before the argument name, parse them. + // Regardless, collect all the attributes we've parsed so far. + ArgInfo.ArgAttrs = 0; + if (getLangOpts().ObjC2) { + MaybeParseGNUAttributes(paramAttrs); + ArgInfo.ArgAttrs = paramAttrs.getList(); + } + + // Code completion for the next piece of the selector. + if (Tok.is(tok::code_completion)) { + KeyIdents.push_back(SelIdent); + Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(), + mType == tok::minus, + /*AtParameterName=*/true, + ReturnType, + KeyIdents.data(), + KeyIdents.size()); + cutOffParsing(); + return 0; + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing argument name. + break; + } + + ArgInfo.Name = Tok.getIdentifierInfo(); + ArgInfo.NameLoc = Tok.getLocation(); + ConsumeToken(); // Eat the identifier. + + ArgInfos.push_back(ArgInfo); + KeyIdents.push_back(SelIdent); + KeyLocs.push_back(selLoc); + + // Make sure the attributes persist. + allParamAttrs.takeAllFrom(paramAttrs.getPool()); + + // Code completion for the next piece of the selector. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(), + mType == tok::minus, + /*AtParameterName=*/false, + ReturnType, + KeyIdents.data(), + KeyIdents.size()); + cutOffParsing(); + return 0; + } + + // Check for another keyword selector. + SelIdent = ParseObjCSelectorPiece(selLoc); + if (!SelIdent && Tok.isNot(tok::colon)) + break; + // We have a selector or a colon, continue parsing. + } + + bool isVariadic = false; + + // Parse the (optional) parameter list. + while (Tok.is(tok::comma)) { + ConsumeToken(); + if (Tok.is(tok::ellipsis)) { + isVariadic = true; + ConsumeToken(); + break; + } + DeclSpec DS(AttrFactory); + ParseDeclarationSpecifiers(DS); + // Parse the declarator. + Declarator ParmDecl(DS, Declarator::PrototypeContext); + ParseDeclarator(ParmDecl); + IdentifierInfo *ParmII = ParmDecl.getIdentifier(); + Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl); + CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, + ParmDecl.getIdentifierLoc(), + Param, + 0)); + + } + + // FIXME: Add support for optional parameter list... + // If attributes exist after the method, parse them. + if (getLangOpts().ObjC2) + MaybeParseGNUAttributes(methodAttrs); + + if (KeyIdents.size() == 0) + return 0; + + Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(), + &KeyIdents[0]); + Decl *Result + = Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(), + mType, DSRet, ReturnType, + KeyLocs, Sel, &ArgInfos[0], + CParamInfo.data(), CParamInfo.size(), + methodAttrs.getList(), + MethodImplKind, isVariadic, MethodDefinition); + + PD.complete(Result); + return Result; +} + +/// objc-protocol-refs: +/// '<' identifier-list '>' +/// +bool Parser:: +ParseObjCProtocolReferences(SmallVectorImpl &Protocols, + SmallVectorImpl &ProtocolLocs, + bool WarnOnDeclarations, + SourceLocation &LAngleLoc, SourceLocation &EndLoc) { + assert(Tok.is(tok::less) && "expected <"); + + LAngleLoc = ConsumeToken(); // the "<" + + SmallVector ProtocolIdents; + + while (1) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents.data(), + ProtocolIdents.size()); + cutOffParsing(); + return true; + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::greater); + return true; + } + ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(), + Tok.getLocation())); + ProtocolLocs.push_back(Tok.getLocation()); + ConsumeToken(); + + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); + } + + // Consume the '>'. + if (Tok.isNot(tok::greater)) { + Diag(Tok, diag::err_expected_greater); + return true; + } + + EndLoc = ConsumeToken(); + + // Convert the list of protocols identifiers into a list of protocol decls. + Actions.FindProtocolDeclaration(WarnOnDeclarations, + &ProtocolIdents[0], ProtocolIdents.size(), + Protocols); + return false; +} + +/// \brief Parse the Objective-C protocol qualifiers that follow a typename +/// in a decl-specifier-seq, starting at the '<'. +bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) { + assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'"); + assert(getLangOpts().ObjC1 && "Protocol qualifiers only exist in Objective-C"); + SourceLocation LAngleLoc, EndProtoLoc; + SmallVector ProtocolDecl; + SmallVector ProtocolLocs; + bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, + LAngleLoc, EndProtoLoc); + DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), + ProtocolLocs.data(), LAngleLoc); + if (EndProtoLoc.isValid()) + DS.SetRangeEnd(EndProtoLoc); + return Result; +} + + +/// objc-class-instance-variables: +/// '{' objc-instance-variable-decl-list[opt] '}' +/// +/// objc-instance-variable-decl-list: +/// objc-visibility-spec +/// objc-instance-variable-decl ';' +/// ';' +/// objc-instance-variable-decl-list objc-visibility-spec +/// objc-instance-variable-decl-list objc-instance-variable-decl ';' +/// objc-instance-variable-decl-list ';' +/// +/// objc-visibility-spec: +/// @private +/// @protected +/// @public +/// @package [OBJC2] +/// +/// objc-instance-variable-decl: +/// struct-declaration +/// +void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, + tok::ObjCKeywordKind visibility, + SourceLocation atLoc) { + assert(Tok.is(tok::l_brace) && "expected {"); + SmallVector AllIvarDecls; + + ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope); + ObjCDeclContextSwitch ObjCDC(*this); + + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); + + // While we still have something to read, read the instance variables. + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + // Each iteration of this loop reads one objc-instance-variable-decl. + + // Check for extraneous top-level semicolon. + if (Tok.is(tok::semi)) { + Diag(Tok, diag::ext_extra_ivar_semi) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeToken(); + continue; + } + + // Set the default visibility to private. + if (Tok.is(tok::at)) { // parse objc-visibility-spec + ConsumeToken(); // eat the @ sign + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtVisibility(getCurScope()); + return cutOffParsing(); + } + + switch (Tok.getObjCKeywordID()) { + case tok::objc_private: + case tok::objc_public: + case tok::objc_protected: + case tok::objc_package: + visibility = Tok.getObjCKeywordID(); + ConsumeToken(); + continue; + default: + Diag(Tok, diag::err_objc_illegal_visibility_spec); + continue; + } + } + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(getCurScope(), + Sema::PCC_ObjCInstanceVariableList); + return cutOffParsing(); + } + + struct ObjCIvarCallback : FieldCallback { + Parser &P; + Decl *IDecl; + tok::ObjCKeywordKind visibility; + SmallVectorImpl &AllIvarDecls; + + ObjCIvarCallback(Parser &P, Decl *IDecl, tok::ObjCKeywordKind V, + SmallVectorImpl &AllIvarDecls) : + P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) { + } + + Decl *invoke(FieldDeclarator &FD) { + P.Actions.ActOnObjCContainerStartDefinition(IDecl); + // Install the declarator into the interface decl. + Decl *Field + = P.Actions.ActOnIvar(P.getCurScope(), + FD.D.getDeclSpec().getSourceRange().getBegin(), + FD.D, FD.BitfieldSize, visibility); + P.Actions.ActOnObjCContainerFinishDefinition(); + if (Field) + AllIvarDecls.push_back(Field); + return Field; + } + } Callback(*this, interfaceDecl, visibility, AllIvarDecls); + + // Parse all the comma separated declarators. + DeclSpec DS(AttrFactory); + ParseStructDeclaration(DS, Callback); + + if (Tok.is(tok::semi)) { + ConsumeToken(); + } else { + Diag(Tok, diag::err_expected_semi_decl_list); + // Skip to end of block or statement + SkipUntil(tok::r_brace, true, true); + } + } + T.consumeClose(); + + Actions.ActOnObjCContainerStartDefinition(interfaceDecl); + Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls); + Actions.ActOnObjCContainerFinishDefinition(); + // Call ActOnFields() even if we don't have any decls. This is useful + // for code rewriting tools that need to be aware of the empty list. + Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl, + AllIvarDecls, + T.getOpenLocation(), T.getCloseLocation(), 0); + return; +} + +/// objc-protocol-declaration: +/// objc-protocol-definition +/// objc-protocol-forward-reference +/// +/// objc-protocol-definition: +/// @protocol identifier +/// objc-protocol-refs[opt] +/// objc-interface-decl-list +/// @end +/// +/// objc-protocol-forward-reference: +/// @protocol identifier-list ';' +/// +/// "@protocol identifier ;" should be resolved as "@protocol +/// identifier-list ;": objc-interface-decl-list may not start with a +/// semicolon in the first alternative if objc-protocol-refs are omitted. +Parser::DeclGroupPtrTy +Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, + ParsedAttributes &attrs) { + assert(Tok.isObjCAtKeyword(tok::objc_protocol) && + "ParseObjCAtProtocolDeclaration(): Expected @protocol"); + ConsumeToken(); // the "protocol" identifier + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCProtocolDecl(getCurScope()); + cutOffParsing(); + return DeclGroupPtrTy(); + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing protocol name. + return DeclGroupPtrTy(); + } + // Save the protocol name, then consume it. + IdentifierInfo *protocolName = Tok.getIdentifierInfo(); + SourceLocation nameLoc = ConsumeToken(); + + if (Tok.is(tok::semi)) { // forward declaration of one protocol. + IdentifierLocPair ProtoInfo(protocolName, nameLoc); + ConsumeToken(); + return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtoInfo, 1, + attrs.getList()); + } + + CheckNestedObjCContexts(AtLoc); + + if (Tok.is(tok::comma)) { // list of forward declarations. + SmallVector ProtocolRefs; + ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc)); + + // Parse the list of forward declarations. + while (1) { + ConsumeToken(); // the ',' + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::semi); + return DeclGroupPtrTy(); + } + ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(), + Tok.getLocation())); + ConsumeToken(); // the identifier + + if (Tok.isNot(tok::comma)) + break; + } + // Consume the ';'. + if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol")) + return DeclGroupPtrTy(); + + return Actions.ActOnForwardProtocolDeclaration(AtLoc, + &ProtocolRefs[0], + ProtocolRefs.size(), + attrs.getList()); + } + + // Last, and definitely not least, parse a protocol declaration. + SourceLocation LAngleLoc, EndProtoLoc; + + SmallVector ProtocolRefs; + SmallVector ProtocolLocs; + if (Tok.is(tok::less) && + ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, + LAngleLoc, EndProtoLoc)) + return DeclGroupPtrTy(); + + Decl *ProtoType = + Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc, + ProtocolRefs.data(), + ProtocolRefs.size(), + ProtocolLocs.data(), + EndProtoLoc, attrs.getList()); + + ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType); + return Actions.ConvertDeclToDeclGroup(ProtoType); +} + +/// objc-implementation: +/// objc-class-implementation-prologue +/// objc-category-implementation-prologue +/// +/// objc-class-implementation-prologue: +/// @implementation identifier objc-superclass[opt] +/// objc-class-instance-variables[opt] +/// +/// objc-category-implementation-prologue: +/// @implementation identifier ( identifier ) +Parser::DeclGroupPtrTy +Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { + assert(Tok.isObjCAtKeyword(tok::objc_implementation) && + "ParseObjCAtImplementationDeclaration(): Expected @implementation"); + CheckNestedObjCContexts(AtLoc); + ConsumeToken(); // the "implementation" identifier + + // Code completion after '@implementation'. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCImplementationDecl(getCurScope()); + cutOffParsing(); + return DeclGroupPtrTy(); + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing class or category name. + return DeclGroupPtrTy(); + } + // We have a class or category name - consume it. + IdentifierInfo *nameId = Tok.getIdentifierInfo(); + SourceLocation nameLoc = ConsumeToken(); // consume class or category name + Decl *ObjCImpDecl = 0; + + if (Tok.is(tok::l_paren)) { + // we have a category implementation. + ConsumeParen(); + SourceLocation categoryLoc, rparenLoc; + IdentifierInfo *categoryId = 0; + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc); + cutOffParsing(); + return DeclGroupPtrTy(); + } + + if (Tok.is(tok::identifier)) { + categoryId = Tok.getIdentifierInfo(); + categoryLoc = ConsumeToken(); + } else { + Diag(Tok, diag::err_expected_ident); // missing category name. + return DeclGroupPtrTy(); + } + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + SkipUntil(tok::r_paren, false); // don't stop at ';' + return DeclGroupPtrTy(); + } + rparenLoc = ConsumeParen(); + ObjCImpDecl = Actions.ActOnStartCategoryImplementation( + AtLoc, nameId, nameLoc, categoryId, + categoryLoc); + + } else { + // We have a class implementation + SourceLocation superClassLoc; + IdentifierInfo *superClassId = 0; + if (Tok.is(tok::colon)) { + // We have a super class + ConsumeToken(); + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing super class name. + return DeclGroupPtrTy(); + } + superClassId = Tok.getIdentifierInfo(); + superClassLoc = ConsumeToken(); // Consume super class name + } + ObjCImpDecl = Actions.ActOnStartClassImplementation( + AtLoc, nameId, nameLoc, + superClassId, superClassLoc); + + if (Tok.is(tok::l_brace)) // we have ivars + ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc); + } + assert(ObjCImpDecl); + + SmallVector DeclsInGroup; + + { + ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl); + while (!ObjCImplParsing.isFinished() && Tok.isNot(tok::eof)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) { + DeclGroupRef DG = DGP.get(); + DeclsInGroup.append(DG.begin(), DG.end()); + } + } + } + + return Actions.ActOnFinishObjCImplementation(ObjCImpDecl, DeclsInGroup); +} + +Parser::DeclGroupPtrTy +Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { + assert(Tok.isObjCAtKeyword(tok::objc_end) && + "ParseObjCAtEndDeclaration(): Expected @end"); + ConsumeToken(); // the "end" identifier + if (CurParsedObjCImpl) + CurParsedObjCImpl->finish(atEnd); + else + // missing @implementation + Diag(atEnd.getBegin(), diag::err_expected_objc_container); + return DeclGroupPtrTy(); +} + +Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() { + if (!Finished) { + finish(P.Tok.getLocation()); + if (P.Tok.is(tok::eof)) { + P.Diag(P.Tok, diag::err_objc_missing_end) + << FixItHint::CreateInsertion(P.Tok.getLocation(), "\n@end\n"); + P.Diag(Dcl->getLocStart(), diag::note_objc_container_start) + << Sema::OCK_Implementation; + } + } + P.CurParsedObjCImpl = 0; + assert(LateParsedObjCMethods.empty()); +} + +void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) { + assert(!Finished); + P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl); + for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i) + P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i]); + + P.Actions.ActOnAtEnd(P.getCurScope(), AtEnd); + + /// \brief Clear and free the cached objc methods. + for (LateParsedObjCMethodContainer::iterator + I = LateParsedObjCMethods.begin(), + E = LateParsedObjCMethods.end(); I != E; ++I) + delete *I; + LateParsedObjCMethods.clear(); + + Finished = true; +} + +/// compatibility-alias-decl: +/// @compatibility_alias alias-name class-name ';' +/// +Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { + assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) && + "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias"); + ConsumeToken(); // consume compatibility_alias + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + return 0; + } + IdentifierInfo *aliasId = Tok.getIdentifierInfo(); + SourceLocation aliasLoc = ConsumeToken(); // consume alias-name + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + return 0; + } + IdentifierInfo *classId = Tok.getIdentifierInfo(); + SourceLocation classLoc = ConsumeToken(); // consume class-name; + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, + "@compatibility_alias"); + return Actions.ActOnCompatiblityAlias(atLoc, aliasId, aliasLoc, + classId, classLoc); +} + +/// property-synthesis: +/// @synthesize property-ivar-list ';' +/// +/// property-ivar-list: +/// property-ivar +/// property-ivar-list ',' property-ivar +/// +/// property-ivar: +/// identifier +/// identifier '=' identifier +/// +Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { + assert(Tok.isObjCAtKeyword(tok::objc_synthesize) && + "ParseObjCPropertyDynamic(): Expected '@synthesize'"); + ConsumeToken(); // consume synthesize + + while (true) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCPropertyDefinition(getCurScope()); + cutOffParsing(); + return 0; + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_synthesized_property_name); + SkipUntil(tok::semi); + return 0; + } + + IdentifierInfo *propertyIvar = 0; + IdentifierInfo *propertyId = Tok.getIdentifierInfo(); + SourceLocation propertyLoc = ConsumeToken(); // consume property name + SourceLocation propertyIvarLoc; + if (Tok.is(tok::equal)) { + // property '=' ivar-name + ConsumeToken(); // consume '=' + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId); + cutOffParsing(); + return 0; + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + break; + } + propertyIvar = Tok.getIdentifierInfo(); + propertyIvarLoc = ConsumeToken(); // consume ivar-name + } + Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, true, + propertyId, propertyIvar, propertyIvarLoc); + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // consume ',' + } + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@synthesize"); + return 0; +} + +/// property-dynamic: +/// @dynamic property-list +/// +/// property-list: +/// identifier +/// property-list ',' identifier +/// +Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { + assert(Tok.isObjCAtKeyword(tok::objc_dynamic) && + "ParseObjCPropertyDynamic(): Expected '@dynamic'"); + ConsumeToken(); // consume dynamic + while (true) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCPropertyDefinition(getCurScope()); + cutOffParsing(); + return 0; + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::semi); + return 0; + } + + IdentifierInfo *propertyId = Tok.getIdentifierInfo(); + SourceLocation propertyLoc = ConsumeToken(); // consume property name + Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, false, + propertyId, 0, SourceLocation()); + + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // consume ',' + } + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@dynamic"); + return 0; +} + +/// objc-throw-statement: +/// throw expression[opt]; +/// +StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) { + ExprResult Res; + ConsumeToken(); // consume throw + if (Tok.isNot(tok::semi)) { + Res = ParseExpression(); + if (Res.isInvalid()) { + SkipUntil(tok::semi); + return StmtError(); + } + } + // consume ';' + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@throw"); + return Actions.ActOnObjCAtThrowStmt(atLoc, Res.take(), getCurScope()); +} + +/// objc-synchronized-statement: +/// @synchronized '(' expression ')' compound-statement +/// +StmtResult +Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) { + ConsumeToken(); // consume synchronized + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << "@synchronized"; + return StmtError(); + } + + // The operand is surrounded with parentheses. + ConsumeParen(); // '(' + ExprResult operand(ParseExpression()); + + if (Tok.is(tok::r_paren)) { + ConsumeParen(); // ')' + } else { + if (!operand.isInvalid()) + Diag(Tok, diag::err_expected_rparen); + + // Skip forward until we see a left brace, but don't consume it. + SkipUntil(tok::l_brace, true, true); + } + + // Require a compound statement. + if (Tok.isNot(tok::l_brace)) { + if (!operand.isInvalid()) + Diag(Tok, diag::err_expected_lbrace); + return StmtError(); + } + + // Check the @synchronized operand now. + if (!operand.isInvalid()) + operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.take()); + + // Parse the compound statement within a new scope. + ParseScope bodyScope(this, Scope::DeclScope); + StmtResult body(ParseCompoundStatementBody()); + bodyScope.Exit(); + + // If there was a semantic or parse error earlier with the + // operand, fail now. + if (operand.isInvalid()) + return StmtError(); + + if (body.isInvalid()) + body = Actions.ActOnNullStmt(Tok.getLocation()); + + return Actions.ActOnObjCAtSynchronizedStmt(atLoc, operand.get(), body.get()); +} + +/// objc-try-catch-statement: +/// @try compound-statement objc-catch-list[opt] +/// @try compound-statement objc-catch-list[opt] @finally compound-statement +/// +/// objc-catch-list: +/// @catch ( parameter-declaration ) compound-statement +/// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement +/// catch-parameter-declaration: +/// parameter-declaration +/// '...' [OBJC2] +/// +StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { + bool catch_or_finally_seen = false; + + ConsumeToken(); // consume try + if (Tok.isNot(tok::l_brace)) { + Diag(Tok, diag::err_expected_lbrace); + return StmtError(); + } + StmtVector CatchStmts(Actions); + StmtResult FinallyStmt; + ParseScope TryScope(this, Scope::DeclScope); + StmtResult TryBody(ParseCompoundStatementBody()); + TryScope.Exit(); + if (TryBody.isInvalid()) + TryBody = Actions.ActOnNullStmt(Tok.getLocation()); + + while (Tok.is(tok::at)) { + // At this point, we need to lookahead to determine if this @ is the start + // of an @catch or @finally. We don't want to consume the @ token if this + // is an @try or @encode or something else. + Token AfterAt = GetLookAheadToken(1); + if (!AfterAt.isObjCAtKeyword(tok::objc_catch) && + !AfterAt.isObjCAtKeyword(tok::objc_finally)) + break; + + SourceLocation AtCatchFinallyLoc = ConsumeToken(); + if (Tok.isObjCAtKeyword(tok::objc_catch)) { + Decl *FirstPart = 0; + ConsumeToken(); // consume catch + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope); + if (Tok.isNot(tok::ellipsis)) { + DeclSpec DS(AttrFactory); + ParseDeclarationSpecifiers(DS); + Declarator ParmDecl(DS, Declarator::ObjCCatchContext); + ParseDeclarator(ParmDecl); + + // Inform the actions module about the declarator, so it + // gets added to the current scope. + FirstPart = Actions.ActOnObjCExceptionDecl(getCurScope(), ParmDecl); + } else + ConsumeToken(); // consume '...' + + SourceLocation RParenLoc; + + if (Tok.is(tok::r_paren)) + RParenLoc = ConsumeParen(); + else // Skip over garbage, until we get to ')'. Eat the ')'. + SkipUntil(tok::r_paren, true, false); + + StmtResult CatchBody(true); + if (Tok.is(tok::l_brace)) + CatchBody = ParseCompoundStatementBody(); + else + Diag(Tok, diag::err_expected_lbrace); + if (CatchBody.isInvalid()) + CatchBody = Actions.ActOnNullStmt(Tok.getLocation()); + + StmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc, + RParenLoc, + FirstPart, + CatchBody.take()); + if (!Catch.isInvalid()) + CatchStmts.push_back(Catch.release()); + + } else { + Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after) + << "@catch clause"; + return StmtError(); + } + catch_or_finally_seen = true; + } else { + assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?"); + ConsumeToken(); // consume finally + ParseScope FinallyScope(this, Scope::DeclScope); + + StmtResult FinallyBody(true); + if (Tok.is(tok::l_brace)) + FinallyBody = ParseCompoundStatementBody(); + else + Diag(Tok, diag::err_expected_lbrace); + if (FinallyBody.isInvalid()) + FinallyBody = Actions.ActOnNullStmt(Tok.getLocation()); + FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc, + FinallyBody.take()); + catch_or_finally_seen = true; + break; + } + } + if (!catch_or_finally_seen) { + Diag(atLoc, diag::err_missing_catch_finally); + return StmtError(); + } + + return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.take(), + move_arg(CatchStmts), + FinallyStmt.take()); +} + +/// objc-autoreleasepool-statement: +/// @autoreleasepool compound-statement +/// +StmtResult +Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) { + ConsumeToken(); // consume autoreleasepool + if (Tok.isNot(tok::l_brace)) { + Diag(Tok, diag::err_expected_lbrace); + return StmtError(); + } + // Enter a scope to hold everything within the compound stmt. Compound + // statements can always hold declarations. + ParseScope BodyScope(this, Scope::DeclScope); + + StmtResult AutoreleasePoolBody(ParseCompoundStatementBody()); + + BodyScope.Exit(); + if (AutoreleasePoolBody.isInvalid()) + AutoreleasePoolBody = Actions.ActOnNullStmt(Tok.getLocation()); + return Actions.ActOnObjCAutoreleasePoolStmt(atLoc, + AutoreleasePoolBody.take()); +} + +/// objc-method-def: objc-method-proto ';'[opt] '{' body '}' +/// +Decl *Parser::ParseObjCMethodDefinition() { + Decl *MDecl = ParseObjCMethodPrototype(); + + PrettyDeclStackTraceEntry CrashInfo(Actions, MDecl, Tok.getLocation(), + "parsing Objective-C method"); + + // parse optional ';' + if (Tok.is(tok::semi)) { + if (CurParsedObjCImpl) { + Diag(Tok, diag::warn_semicolon_before_method_body) + << FixItHint::CreateRemoval(Tok.getLocation()); + } + ConsumeToken(); + } + + // We should have an opening brace now. + if (Tok.isNot(tok::l_brace)) { + Diag(Tok, diag::err_expected_method_body); + + // Skip over garbage, until we get to '{'. Don't eat the '{'. + SkipUntil(tok::l_brace, true, true); + + // If we didn't find the '{', bail out. + if (Tok.isNot(tok::l_brace)) + return 0; + } + + if (!MDecl) { + ConsumeBrace(); + SkipUntil(tok::r_brace, /*StopAtSemi=*/false); + return 0; + } + + // Allow the rest of sema to find private method decl implementations. + Actions.AddAnyMethodToGlobalPool(MDecl); + + if (CurParsedObjCImpl) { + // Consume the tokens and store them for later parsing. + LexedMethod* LM = new LexedMethod(this, MDecl); + CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM); + CachedTokens &Toks = LM->Toks; + // 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); + + } else { + ConsumeBrace(); + SkipUntil(tok::r_brace, /*StopAtSemi=*/false); + } + + return MDecl; +} + +StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtStatement(getCurScope()); + cutOffParsing(); + return StmtError(); + } + + if (Tok.isObjCAtKeyword(tok::objc_try)) + return ParseObjCTryStmt(AtLoc); + + if (Tok.isObjCAtKeyword(tok::objc_throw)) + return ParseObjCThrowStmt(AtLoc); + + if (Tok.isObjCAtKeyword(tok::objc_synchronized)) + return ParseObjCSynchronizedStmt(AtLoc); + + if (Tok.isObjCAtKeyword(tok::objc_autoreleasepool)) + return ParseObjCAutoreleasePoolStmt(AtLoc); + + ExprResult Res(ParseExpressionWithLeadingAt(AtLoc)); + if (Res.isInvalid()) { + // If the expression is invalid, skip ahead to the next semicolon. Not + // doing this opens us up to the possibility of infinite loops if + // ParseExpression does not consume any tokens. + SkipUntil(tok::semi); + return StmtError(); + } + + // Otherwise, eat the semicolon. + ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); + return Actions.ActOnExprStmt(Actions.MakeFullExpr(Res.take())); +} + +ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { + switch (Tok.getKind()) { + case tok::code_completion: + Actions.CodeCompleteObjCAtExpression(getCurScope()); + cutOffParsing(); + return ExprError(); + + case tok::minus: + case tok::plus: { + tok::TokenKind Kind = Tok.getKind(); + SourceLocation OpLoc = ConsumeToken(); + + if (!Tok.is(tok::numeric_constant)) { + const char *Symbol = 0; + switch (Kind) { + case tok::minus: Symbol = "-"; break; + case tok::plus: Symbol = "+"; break; + default: llvm_unreachable("missing unary operator case"); + } + Diag(Tok, diag::err_nsnumber_nonliteral_unary) + << Symbol; + return ExprError(); + } + + ExprResult Lit(Actions.ActOnNumericConstant(Tok)); + if (Lit.isInvalid()) { + return move(Lit); + } + ConsumeToken(); // Consume the literal token. + + Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.take()); + if (Lit.isInvalid()) + return move(Lit); + + return ParsePostfixExpressionSuffix( + Actions.BuildObjCNumericLiteral(AtLoc, Lit.take())); + } + + case tok::string_literal: // primary-expression: string-literal + case tok::wide_string_literal: + return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc)); + + case tok::char_constant: + return ParsePostfixExpressionSuffix(ParseObjCCharacterLiteral(AtLoc)); + + case tok::numeric_constant: + return ParsePostfixExpressionSuffix(ParseObjCNumericLiteral(AtLoc)); + + case tok::kw_true: // Objective-C++, etc. + case tok::kw___objc_yes: // c/c++/objc/objc++ __objc_yes + return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, true)); + case tok::kw_false: // Objective-C++, etc. + case tok::kw___objc_no: // c/c++/objc/objc++ __objc_no + return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, false)); + + case tok::l_square: + // Objective-C array literal + return ParsePostfixExpressionSuffix(ParseObjCArrayLiteral(AtLoc)); + + case tok::l_brace: + // Objective-C dictionary literal + return ParsePostfixExpressionSuffix(ParseObjCDictionaryLiteral(AtLoc)); + + default: + if (Tok.getIdentifierInfo() == 0) + return ExprError(Diag(AtLoc, diag::err_unexpected_at)); + + switch (Tok.getIdentifierInfo()->getObjCKeywordID()) { + case tok::objc_encode: + return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc)); + case tok::objc_protocol: + return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc)); + case tok::objc_selector: + return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc)); + default: + return ExprError(Diag(AtLoc, diag::err_unexpected_at)); + } + } +} + +/// \brirg Parse the receiver of an Objective-C++ message send. +/// +/// This routine parses the receiver of a message send in +/// Objective-C++ either as a type or as an expression. Note that this +/// routine must not be called to parse a send to 'super', since it +/// has no way to return such a result. +/// +/// \param IsExpr Whether the receiver was parsed as an expression. +/// +/// \param TypeOrExpr If the receiver was parsed as an expression (\c +/// IsExpr is true), the parsed expression. If the receiver was parsed +/// as a type (\c IsExpr is false), the parsed type. +/// +/// \returns True if an error occurred during parsing or semantic +/// analysis, in which case the arguments do not have valid +/// values. Otherwise, returns false for a successful parse. +/// +/// objc-receiver: [C++] +/// 'super' [not parsed here] +/// expression +/// simple-type-specifier +/// typename-specifier +bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { + InMessageExpressionRAIIObject InMessage(*this, true); + + if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) + TryAnnotateTypeOrScopeToken(); + + if (!isCXXSimpleTypeSpecifier()) { + // objc-receiver: + // expression + ExprResult Receiver = ParseExpression(); + if (Receiver.isInvalid()) + return true; + + IsExpr = true; + TypeOrExpr = Receiver.take(); + return false; + } + + // objc-receiver: + // typename-specifier + // simple-type-specifier + // expression (that starts with one of the above) + DeclSpec DS(AttrFactory); + ParseCXXSimpleTypeSpecifier(DS); + + if (Tok.is(tok::l_paren)) { + // If we see an opening parentheses at this point, we are + // actually parsing an expression that starts with a + // function-style cast, e.g., + // + // postfix-expression: + // simple-type-specifier ( expression-list [opt] ) + // typename-specifier ( expression-list [opt] ) + // + // Parse the remainder of this case, then the (optional) + // postfix-expression suffix, followed by the (optional) + // right-hand side of the binary expression. We have an + // instance method. + ExprResult Receiver = ParseCXXTypeConstructExpression(DS); + if (!Receiver.isInvalid()) + Receiver = ParsePostfixExpressionSuffix(Receiver.take()); + if (!Receiver.isInvalid()) + Receiver = ParseRHSOfBinaryExpression(Receiver.take(), prec::Comma); + if (Receiver.isInvalid()) + return true; + + IsExpr = true; + TypeOrExpr = Receiver.take(); + return false; + } + + // We have a class message. Turn the simple-type-specifier or + // typename-specifier we parsed into a type and parse the + // remainder of the class message. + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + TypeResult Type = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); + if (Type.isInvalid()) + return true; + + IsExpr = false; + TypeOrExpr = Type.get().getAsOpaquePtr(); + return false; +} + +/// \brief Determine whether the parser is currently referring to a an +/// Objective-C message send, using a simplified heuristic to avoid overhead. +/// +/// This routine will only return true for a subset of valid message-send +/// expressions. +bool Parser::isSimpleObjCMessageExpression() { + assert(Tok.is(tok::l_square) && getLangOpts().ObjC1 && + "Incorrect start for isSimpleObjCMessageExpression"); + return GetLookAheadToken(1).is(tok::identifier) && + GetLookAheadToken(2).is(tok::identifier); +} + +bool Parser::isStartOfObjCClassMessageMissingOpenBracket() { + if (!getLangOpts().ObjC1 || !NextToken().is(tok::identifier) || + InMessageExpression) + return false; + + + ParsedType Type; + + if (Tok.is(tok::annot_typename)) + Type = getTypeAnnotation(Tok); + else if (Tok.is(tok::identifier)) + Type = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), + getCurScope()); + else + return false; + + if (!Type.get().isNull() && Type.get()->isObjCObjectOrInterfaceType()) { + const Token &AfterNext = GetLookAheadToken(2); + if (AfterNext.is(tok::colon) || AfterNext.is(tok::r_square)) { + if (Tok.is(tok::identifier)) + TryAnnotateTypeOrScopeToken(); + + return Tok.is(tok::annot_typename); + } + } + + return false; +} + +/// objc-message-expr: +/// '[' objc-receiver objc-message-args ']' +/// +/// objc-receiver: [C] +/// 'super' +/// expression +/// class-name +/// type-name +/// +ExprResult Parser::ParseObjCMessageExpression() { + assert(Tok.is(tok::l_square) && "'[' expected"); + SourceLocation LBracLoc = ConsumeBracket(); // consume '[' + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCMessageReceiver(getCurScope()); + cutOffParsing(); + return ExprError(); + } + + InMessageExpressionRAIIObject InMessage(*this, true); + + if (getLangOpts().CPlusPlus) { + // We completely separate the C and C++ cases because C++ requires + // more complicated (read: slower) parsing. + + // Handle send to super. + // FIXME: This doesn't benefit from the same typo-correction we + // get in Objective-C. + if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super && + NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope()) + return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), + ParsedType(), 0); + + // Parse the receiver, which is either a type or an expression. + bool IsExpr; + void *TypeOrExpr = NULL; + if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) { + SkipUntil(tok::r_square); + return ExprError(); + } + + if (IsExpr) + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), + ParsedType(), + static_cast(TypeOrExpr)); + + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), + ParsedType::getFromOpaquePtr(TypeOrExpr), + 0); + } + + if (Tok.is(tok::identifier)) { + IdentifierInfo *Name = Tok.getIdentifierInfo(); + SourceLocation NameLoc = Tok.getLocation(); + ParsedType ReceiverType; + switch (Actions.getObjCMessageKind(getCurScope(), Name, NameLoc, + Name == Ident_super, + NextToken().is(tok::period), + ReceiverType)) { + case Sema::ObjCSuperMessage: + return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), + ParsedType(), 0); + + case Sema::ObjCClassMessage: + if (!ReceiverType) { + SkipUntil(tok::r_square); + return ExprError(); + } + + ConsumeToken(); // the type name + + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), + ReceiverType, 0); + + case Sema::ObjCInstanceMessage: + // Fall through to parse an expression. + break; + } + } + + // Otherwise, an arbitrary expression can be the receiver of a send. + ExprResult Res(ParseExpression()); + if (Res.isInvalid()) { + SkipUntil(tok::r_square); + return move(Res); + } + + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), + ParsedType(), Res.take()); +} + +/// \brief Parse the remainder of an Objective-C message following the +/// '[' objc-receiver. +/// +/// This routine handles sends to super, class messages (sent to a +/// class name), and instance messages (sent to an object), and the +/// target is represented by \p SuperLoc, \p ReceiverType, or \p +/// ReceiverExpr, respectively. Only one of these parameters may have +/// a valid value. +/// +/// \param LBracLoc The location of the opening '['. +/// +/// \param SuperLoc If this is a send to 'super', the location of the +/// 'super' keyword that indicates a send to the superclass. +/// +/// \param ReceiverType If this is a class message, the type of the +/// class we are sending a message to. +/// +/// \param ReceiverExpr If this is an instance message, the expression +/// used to compute the receiver object. +/// +/// objc-message-args: +/// objc-selector +/// objc-keywordarg-list +/// +/// objc-keywordarg-list: +/// objc-keywordarg +/// objc-keywordarg-list objc-keywordarg +/// +/// objc-keywordarg: +/// selector-name[opt] ':' objc-keywordexpr +/// +/// objc-keywordexpr: +/// nonempty-expr-list +/// +/// nonempty-expr-list: +/// assignment-expression +/// nonempty-expr-list , assignment-expression +/// +ExprResult +Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, + SourceLocation SuperLoc, + ParsedType ReceiverType, + ExprArg ReceiverExpr) { + InMessageExpressionRAIIObject InMessage(*this, true); + + if (Tok.is(tok::code_completion)) { + if (SuperLoc.isValid()) + Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, 0, 0, + false); + else if (ReceiverType) + Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, 0, 0, + false); + else + Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, + 0, 0, false); + cutOffParsing(); + return ExprError(); + } + + // Parse objc-selector + SourceLocation Loc; + IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc); + + SmallVector KeyIdents; + SmallVector KeyLocs; + ExprVector KeyExprs(Actions); + + if (Tok.is(tok::colon)) { + while (1) { + // Each iteration parses a single keyword argument. + KeyIdents.push_back(selIdent); + KeyLocs.push_back(Loc); + + if (Tok.isNot(tok::colon)) { + Diag(Tok, diag::err_expected_colon); + // We must manually skip to a ']', otherwise the expression skipper will + // stop at the ']' when it skips to the ';'. We want it to skip beyond + // the enclosing expression. + SkipUntil(tok::r_square); + return ExprError(); + } + + ConsumeToken(); // Eat the ':'. + /// Parse the expression after ':' + + if (Tok.is(tok::code_completion)) { + if (SuperLoc.isValid()) + Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, + KeyIdents.data(), + KeyIdents.size(), + /*AtArgumentEpression=*/true); + else if (ReceiverType) + Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, + KeyIdents.data(), + KeyIdents.size(), + /*AtArgumentEpression=*/true); + else + Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, + KeyIdents.data(), + KeyIdents.size(), + /*AtArgumentEpression=*/true); + + cutOffParsing(); + return ExprError(); + } + + ExprResult Res(ParseAssignmentExpression()); + if (Res.isInvalid()) { + // We must manually skip to a ']', otherwise the expression skipper will + // stop at the ']' when it skips to the ';'. We want it to skip beyond + // the enclosing expression. + SkipUntil(tok::r_square); + return move(Res); + } + + // We have a valid expression. + KeyExprs.push_back(Res.release()); + + // Code completion after each argument. + if (Tok.is(tok::code_completion)) { + if (SuperLoc.isValid()) + Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, + KeyIdents.data(), + KeyIdents.size(), + /*AtArgumentEpression=*/false); + else if (ReceiverType) + Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, + KeyIdents.data(), + KeyIdents.size(), + /*AtArgumentEpression=*/false); + else + Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, + KeyIdents.data(), + KeyIdents.size(), + /*AtArgumentEpression=*/false); + cutOffParsing(); + return ExprError(); + } + + // Check for another keyword selector. + selIdent = ParseObjCSelectorPiece(Loc); + if (!selIdent && Tok.isNot(tok::colon)) + break; + // We have a selector or a colon, continue parsing. + } + // Parse the, optional, argument list, comma separated. + while (Tok.is(tok::comma)) { + ConsumeToken(); // Eat the ','. + /// Parse the expression after ',' + ExprResult Res(ParseAssignmentExpression()); + if (Res.isInvalid()) { + // We must manually skip to a ']', otherwise the expression skipper will + // stop at the ']' when it skips to the ';'. We want it to skip beyond + // the enclosing expression. + SkipUntil(tok::r_square); + return move(Res); + } + + // We have a valid expression. + KeyExprs.push_back(Res.release()); + } + } else if (!selIdent) { + Diag(Tok, diag::err_expected_ident); // missing selector name. + + // We must manually skip to a ']', otherwise the expression skipper will + // stop at the ']' when it skips to the ';'. We want it to skip beyond + // the enclosing expression. + SkipUntil(tok::r_square); + return ExprError(); + } + + if (Tok.isNot(tok::r_square)) { + if (Tok.is(tok::identifier)) + Diag(Tok, diag::err_expected_colon); + else + Diag(Tok, diag::err_expected_rsquare); + // We must manually skip to a ']', otherwise the expression skipper will + // stop at the ']' when it skips to the ';'. We want it to skip beyond + // the enclosing expression. + SkipUntil(tok::r_square); + return ExprError(); + } + + SourceLocation RBracLoc = ConsumeBracket(); // consume ']' + + unsigned nKeys = KeyIdents.size(); + if (nKeys == 0) { + KeyIdents.push_back(selIdent); + KeyLocs.push_back(Loc); + } + Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]); + + if (SuperLoc.isValid()) + return Actions.ActOnSuperMessage(getCurScope(), SuperLoc, Sel, + LBracLoc, KeyLocs, RBracLoc, + MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); + else if (ReceiverType) + return Actions.ActOnClassMessage(getCurScope(), ReceiverType, Sel, + LBracLoc, KeyLocs, RBracLoc, + MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); + return Actions.ActOnInstanceMessage(getCurScope(), ReceiverExpr, Sel, + LBracLoc, KeyLocs, RBracLoc, + MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); +} + +ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { + ExprResult Res(ParseStringLiteralExpression()); + if (Res.isInvalid()) return move(Res); + + // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string + // expressions. At this point, we know that the only valid thing that starts + // with '@' is an @"". + SmallVector AtLocs; + ExprVector AtStrings(Actions); + AtLocs.push_back(AtLoc); + AtStrings.push_back(Res.release()); + + while (Tok.is(tok::at)) { + AtLocs.push_back(ConsumeToken()); // eat the @. + + // Invalid unless there is a string literal. + if (!isTokenStringLiteral()) + return ExprError(Diag(Tok, diag::err_objc_concat_string)); + + ExprResult Lit(ParseStringLiteralExpression()); + if (Lit.isInvalid()) + return move(Lit); + + AtStrings.push_back(Lit.release()); + } + + return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.take(), + AtStrings.size())); +} + +/// ParseObjCBooleanLiteral - +/// objc-scalar-literal : '@' boolean-keyword +/// ; +/// boolean-keyword: 'true' | 'false' | '__objc_yes' | '__objc_no' +/// ; +ExprResult Parser::ParseObjCBooleanLiteral(SourceLocation AtLoc, + bool ArgValue) { + SourceLocation EndLoc = ConsumeToken(); // consume the keyword. + return Actions.ActOnObjCBoolLiteral(AtLoc, EndLoc, ArgValue); +} + +/// ParseObjCCharacterLiteral - +/// objc-scalar-literal : '@' character-literal +/// ; +ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) { + ExprResult Lit(Actions.ActOnCharacterConstant(Tok)); + if (Lit.isInvalid()) { + return move(Lit); + } + ConsumeToken(); // Consume the literal token. + return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take())); +} + +/// ParseObjCNumericLiteral - +/// objc-scalar-literal : '@' scalar-literal +/// ; +/// scalar-literal : | numeric-constant /* any numeric constant. */ +/// ; +ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) { + ExprResult Lit(Actions.ActOnNumericConstant(Tok)); + if (Lit.isInvalid()) { + return move(Lit); + } + ConsumeToken(); // Consume the literal token. + return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take())); +} + +ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) { + ExprVector ElementExprs(Actions); // array elements. + ConsumeBracket(); // consume the l_square. + + while (Tok.isNot(tok::r_square)) { + // Parse list of array element expressions (all must be id types). + ExprResult Res(ParseAssignmentExpression()); + if (Res.isInvalid()) { + // We must manually skip to a ']', otherwise the expression skipper will + // stop at the ']' when it skips to the ';'. We want it to skip beyond + // the enclosing expression. + SkipUntil(tok::r_square); + return move(Res); + } + + // Parse the ellipsis that indicates a pack expansion. + if (Tok.is(tok::ellipsis)) + Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken()); + if (Res.isInvalid()) + return true; + + ElementExprs.push_back(Res.release()); + + if (Tok.is(tok::comma)) + ConsumeToken(); // Eat the ','. + else if (Tok.isNot(tok::r_square)) + return ExprError(Diag(Tok, diag::err_expected_rsquare_or_comma)); + } + SourceLocation EndLoc = ConsumeBracket(); // location of ']' + MultiExprArg Args(Actions, ElementExprs.take(), ElementExprs.size()); + return Owned(Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args)); +} + +ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { + SmallVector Elements; // dictionary elements. + ConsumeBrace(); // consume the l_square. + while (Tok.isNot(tok::r_brace)) { + // Parse the comma separated key : value expressions. + ExprResult KeyExpr; + { + ColonProtectionRAIIObject X(*this); + KeyExpr = ParseAssignmentExpression(); + if (KeyExpr.isInvalid()) { + // We must manually skip to a '}', otherwise the expression skipper will + // stop at the '}' when it skips to the ';'. We want it to skip beyond + // the enclosing expression. + SkipUntil(tok::r_brace); + return move(KeyExpr); + } + } + + if (Tok.is(tok::colon)) { + ConsumeToken(); + } else { + return ExprError(Diag(Tok, diag::err_expected_colon)); + } + + ExprResult ValueExpr(ParseAssignmentExpression()); + if (ValueExpr.isInvalid()) { + // We must manually skip to a '}', otherwise the expression skipper will + // stop at the '}' when it skips to the ';'. We want it to skip beyond + // the enclosing expression. + SkipUntil(tok::r_brace); + return move(ValueExpr); + } + + // Parse the ellipsis that designates this as a pack expansion. + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis) && getLangOpts().CPlusPlus) + EllipsisLoc = ConsumeToken(); + + // We have a valid expression. Collect it in a vector so we can + // build the argument list. + ObjCDictionaryElement Element = { + KeyExpr.get(), ValueExpr.get(), EllipsisLoc, llvm::Optional() + }; + Elements.push_back(Element); + + if (Tok.is(tok::comma)) + ConsumeToken(); // Eat the ','. + else if (Tok.isNot(tok::r_brace)) + return ExprError(Diag(Tok, diag::err_expected_rbrace_or_comma)); + } + SourceLocation EndLoc = ConsumeBrace(); + + // Create the ObjCDictionaryLiteral. + return Owned(Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc), + Elements.data(), + Elements.size())); +} + +/// objc-encode-expression: +/// @encode ( type-name ) +ExprResult +Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) { + assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!"); + + SourceLocation EncLoc = ConsumeToken(); + + if (Tok.isNot(tok::l_paren)) + return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode"); + + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + TypeResult Ty = ParseTypeName(); + + T.consumeClose(); + + if (Ty.isInvalid()) + return ExprError(); + + return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, + T.getOpenLocation(), Ty.get(), + T.getCloseLocation())); +} + +/// objc-protocol-expression +/// @protocol ( protocol-name ) +ExprResult +Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) { + SourceLocation ProtoLoc = ConsumeToken(); + + if (Tok.isNot(tok::l_paren)) + return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol"); + + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + if (Tok.isNot(tok::identifier)) + return ExprError(Diag(Tok, diag::err_expected_ident)); + + IdentifierInfo *protocolId = Tok.getIdentifierInfo(); + ConsumeToken(); + + T.consumeClose(); + + return Owned(Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc, + T.getOpenLocation(), + T.getCloseLocation())); +} + +/// objc-selector-expression +/// @selector '(' objc-keyword-selector ')' +ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { + SourceLocation SelectorLoc = ConsumeToken(); + + if (Tok.isNot(tok::l_paren)) + return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector"); + + SmallVector KeyIdents; + SourceLocation sLoc; + + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(), + KeyIdents.size()); + cutOffParsing(); + return ExprError(); + } + + IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc); + if (!SelIdent && // missing selector name. + Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon)) + return ExprError(Diag(Tok, diag::err_expected_ident)); + + KeyIdents.push_back(SelIdent); + unsigned nColons = 0; + if (Tok.isNot(tok::r_paren)) { + while (1) { + if (Tok.is(tok::coloncolon)) { // Handle :: in C++. + ++nColons; + KeyIdents.push_back(0); + } else if (Tok.isNot(tok::colon)) + return ExprError(Diag(Tok, diag::err_expected_colon)); + + ++nColons; + ConsumeToken(); // Eat the ':' or '::'. + if (Tok.is(tok::r_paren)) + break; + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(), + KeyIdents.size()); + cutOffParsing(); + return ExprError(); + } + + // Check for another keyword selector. + SourceLocation Loc; + SelIdent = ParseObjCSelectorPiece(Loc); + KeyIdents.push_back(SelIdent); + if (!SelIdent && Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon)) + break; + } + } + T.consumeClose(); + Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]); + return Owned(Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc, + T.getOpenLocation(), + T.getCloseLocation())); + } + +Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) { + + // Save the current token position. + SourceLocation OrigLoc = Tok.getLocation(); + + assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!"); + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + LM.Toks.push_back(Tok); + PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); + + // MDecl might be null due to error in method prototype, etc. + Decl *MDecl = LM.D; + // Consume the previously pushed token. + ConsumeAnyToken(); + + assert(Tok.is(tok::l_brace) && "Inline objective-c method not starting with '{'"); + SourceLocation BraceLoc = Tok.getLocation(); + // Enter a scope for the method body. + ParseScope BodyScope(this, + Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope); + + // Tell the actions module that we have entered a method definition with the + // specified Declarator for the method. + Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl); + + if (SkipFunctionBodies && trySkippingFunctionBody()) { + BodyScope.Exit(); + return Actions.ActOnFinishFunctionBody(MDecl, 0); + } + + StmtResult FnBody(ParseCompoundStatementBody()); + + // If the function body could not be parsed, make a bogus compoundstmt. + if (FnBody.isInvalid()) { + Sema::CompoundScopeRAII CompoundScope(Actions); + FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc, + MultiStmtArg(Actions), false); + } + + // Leave the function body scope. + BodyScope.Exit(); + + MDecl = Actions.ActOnFinishFunctionBody(MDecl, FnBody.take()); + + if (Tok.getLocation() != OrigLoc) { + // Due to parsing error, we either went over the cached tokens or + // there are still cached tokens left. If it's the latter case skip the + // leftover tokens. + // Since this is an uncommon situation that should be avoided, use the + // expensive isBeforeInTranslationUnit call. + if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(), + OrigLoc)) + while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof)) + ConsumeAnyToken(); + } + + return MDecl; +} diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp new file mode 100644 index 0000000..eb13e0d --- /dev/null +++ b/clang/lib/Parse/ParsePragma.cpp @@ -0,0 +1,568 @@ +//===--- ParsePragma.cpp - Language specific pragma parsing ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the language specific #pragma handlers. +// +//===----------------------------------------------------------------------===// + +#include "ParsePragma.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "clang/Lex/Preprocessor.h" +using namespace clang; + +/// \brief Handle the annotation token produced for #pragma unused(...) +/// +/// Each annot_pragma_unused is followed by the argument token so e.g. +/// "#pragma unused(x,y)" becomes: +/// annot_pragma_unused 'x' annot_pragma_unused 'y' +void Parser::HandlePragmaUnused() { + assert(Tok.is(tok::annot_pragma_unused)); + SourceLocation UnusedLoc = ConsumeToken(); + Actions.ActOnPragmaUnused(Tok, getCurScope(), UnusedLoc); + ConsumeToken(); // The argument token. +} + +void Parser::HandlePragmaVisibility() { + assert(Tok.is(tok::annot_pragma_vis)); + const IdentifierInfo *VisType = + static_cast(Tok.getAnnotationValue()); + SourceLocation VisLoc = ConsumeToken(); + Actions.ActOnPragmaVisibility(VisType, VisLoc); +} + +struct PragmaPackInfo { + Sema::PragmaPackKind Kind; + IdentifierInfo *Name; + Expr *Alignment; + SourceLocation LParenLoc; + SourceLocation RParenLoc; +}; + +void Parser::HandlePragmaPack() { + assert(Tok.is(tok::annot_pragma_pack)); + PragmaPackInfo *Info = + static_cast(Tok.getAnnotationValue()); + SourceLocation PragmaLoc = ConsumeToken(); + Actions.ActOnPragmaPack(Info->Kind, Info->Name, Info->Alignment, PragmaLoc, + Info->LParenLoc, Info->RParenLoc); +} + +// #pragma GCC visibility comes in two variants: +// 'push' '(' [visibility] ')' +// 'pop' +void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &VisTok) { + SourceLocation VisLoc = VisTok.getLocation(); + + Token Tok; + PP.LexUnexpandedToken(Tok); + + const IdentifierInfo *PushPop = Tok.getIdentifierInfo(); + + const IdentifierInfo *VisType; + if (PushPop && PushPop->isStr("pop")) { + VisType = 0; + } else if (PushPop && PushPop->isStr("push")) { + PP.LexUnexpandedToken(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) + << "visibility"; + return; + } + PP.LexUnexpandedToken(Tok); + VisType = Tok.getIdentifierInfo(); + if (!VisType) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << "visibility"; + return; + } + PP.LexUnexpandedToken(Tok); + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) + << "visibility"; + return; + } + } else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << "visibility"; + return; + } + PP.LexUnexpandedToken(Tok); + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << "visibility"; + return; + } + + Token *Toks = new Token[1]; + Toks[0].startToken(); + Toks[0].setKind(tok::annot_pragma_vis); + Toks[0].setLocation(VisLoc); + Toks[0].setAnnotationValue( + const_cast(static_cast(VisType))); + PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, + /*OwnsTokens=*/true); +} + +// #pragma pack(...) comes in the following delicious flavors: +// pack '(' [integer] ')' +// pack '(' 'show' ')' +// pack '(' ('push' | 'pop') [',' identifier] [, integer] ')' +void PragmaPackHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &PackTok) { + SourceLocation PackLoc = PackTok.getLocation(); + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "pack"; + return; + } + + Sema::PragmaPackKind Kind = Sema::PPK_Default; + IdentifierInfo *Name = 0; + ExprResult Alignment; + SourceLocation LParenLoc = Tok.getLocation(); + PP.Lex(Tok); + if (Tok.is(tok::numeric_constant)) { + Alignment = Actions.ActOnNumericConstant(Tok); + if (Alignment.isInvalid()) + return; + + PP.Lex(Tok); + + // In MSVC/gcc, #pragma pack(4) sets the alignment without affecting + // the push/pop stack. + // In Apple gcc, #pragma pack(4) is equivalent to #pragma pack(push, 4) + if (PP.getLangOpts().ApplePragmaPack) + Kind = Sema::PPK_Push; + } else if (Tok.is(tok::identifier)) { + const IdentifierInfo *II = Tok.getIdentifierInfo(); + if (II->isStr("show")) { + Kind = Sema::PPK_Show; + PP.Lex(Tok); + } else { + if (II->isStr("push")) { + Kind = Sema::PPK_Push; + } else if (II->isStr("pop")) { + Kind = Sema::PPK_Pop; + } else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_invalid_action); + return; + } + PP.Lex(Tok); + + if (Tok.is(tok::comma)) { + PP.Lex(Tok); + + if (Tok.is(tok::numeric_constant)) { + Alignment = Actions.ActOnNumericConstant(Tok); + if (Alignment.isInvalid()) + return; + + PP.Lex(Tok); + } else if (Tok.is(tok::identifier)) { + Name = Tok.getIdentifierInfo(); + PP.Lex(Tok); + + if (Tok.is(tok::comma)) { + PP.Lex(Tok); + + if (Tok.isNot(tok::numeric_constant)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed); + return; + } + + Alignment = Actions.ActOnNumericConstant(Tok); + if (Alignment.isInvalid()) + return; + + PP.Lex(Tok); + } + } else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed); + return; + } + } + } + } else if (PP.getLangOpts().ApplePragmaPack) { + // In MSVC/gcc, #pragma pack() resets the alignment without affecting + // the push/pop stack. + // In Apple gcc #pragma pack() is equivalent to #pragma pack(pop). + Kind = Sema::PPK_Pop; + } + + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "pack"; + return; + } + + SourceLocation RParenLoc = Tok.getLocation(); + PP.Lex(Tok); + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack"; + return; + } + + PragmaPackInfo *Info = + (PragmaPackInfo*) PP.getPreprocessorAllocator().Allocate( + sizeof(PragmaPackInfo), llvm::alignOf()); + new (Info) PragmaPackInfo(); + Info->Kind = Kind; + Info->Name = Name; + Info->Alignment = Alignment.release(); + Info->LParenLoc = LParenLoc; + Info->RParenLoc = RParenLoc; + + Token *Toks = + (Token*) PP.getPreprocessorAllocator().Allocate( + sizeof(Token) * 1, llvm::alignOf()); + new (Toks) Token(); + Toks[0].startToken(); + Toks[0].setKind(tok::annot_pragma_pack); + Toks[0].setLocation(PackLoc); + Toks[0].setAnnotationValue(static_cast(Info)); + PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, + /*OwnsTokens=*/false); +} + +// #pragma ms_struct on +// #pragma ms_struct off +void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &MSStructTok) { + Sema::PragmaMSStructKind Kind = Sema::PMSST_OFF; + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct); + return; + } + const IdentifierInfo *II = Tok.getIdentifierInfo(); + if (II->isStr("on")) { + Kind = Sema::PMSST_ON; + PP.Lex(Tok); + } + else if (II->isStr("off") || II->isStr("reset")) + PP.Lex(Tok); + else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct); + return; + } + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << "ms_struct"; + return; + } + Actions.ActOnPragmaMSStruct(Kind); +} + +// #pragma 'align' '=' {'native','natural','mac68k','power','reset'} +// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'} +static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok, + bool IsOptions) { + Token Tok; + + if (IsOptions) { + PP.Lex(Tok); + if (Tok.isNot(tok::identifier) || + !Tok.getIdentifierInfo()->isStr("align")) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align); + return; + } + } + + PP.Lex(Tok); + if (Tok.isNot(tok::equal)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_align_expected_equal) + << IsOptions; + return; + } + + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << (IsOptions ? "options" : "align"); + return; + } + + Sema::PragmaOptionsAlignKind Kind = Sema::POAK_Natural; + const IdentifierInfo *II = Tok.getIdentifierInfo(); + if (II->isStr("native")) + Kind = Sema::POAK_Native; + else if (II->isStr("natural")) + Kind = Sema::POAK_Natural; + else if (II->isStr("packed")) + Kind = Sema::POAK_Packed; + else if (II->isStr("power")) + Kind = Sema::POAK_Power; + else if (II->isStr("mac68k")) + Kind = Sema::POAK_Mac68k; + else if (II->isStr("reset")) + Kind = Sema::POAK_Reset; + else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_align_invalid_option) + << IsOptions; + return; + } + + SourceLocation KindLoc = Tok.getLocation(); + PP.Lex(Tok); + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << (IsOptions ? "options" : "align"); + return; + } + + Actions.ActOnPragmaOptionsAlign(Kind, FirstTok.getLocation(), KindLoc); +} + +void PragmaAlignHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &AlignTok) { + ParseAlignPragma(Actions, PP, AlignTok, /*IsOptions=*/false); +} + +void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &OptionsTok) { + ParseAlignPragma(Actions, PP, OptionsTok, /*IsOptions=*/true); +} + +// #pragma unused(identifier) +void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &UnusedTok) { + // FIXME: Should we be expanding macros here? My guess is no. + SourceLocation UnusedLoc = UnusedTok.getLocation(); + + // Lex the left '('. + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused"; + return; + } + + // Lex the declaration reference(s). + SmallVector Identifiers; + SourceLocation RParenLoc; + bool LexID = true; + + while (true) { + PP.Lex(Tok); + + if (LexID) { + if (Tok.is(tok::identifier)) { + Identifiers.push_back(Tok); + LexID = false; + continue; + } + + // Illegal token! + PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var); + return; + } + + // We are execting a ')' or a ','. + if (Tok.is(tok::comma)) { + LexID = true; + continue; + } + + if (Tok.is(tok::r_paren)) { + RParenLoc = Tok.getLocation(); + break; + } + + // Illegal token! + PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc); + return; + } + + PP.Lex(Tok); + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << + "unused"; + return; + } + + // Verify that we have a location for the right parenthesis. + assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'"); + assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments"); + + // For each identifier token, insert into the token stream a + // annot_pragma_unused token followed by the identifier token. + // This allows us to cache a "#pragma unused" that occurs inside an inline + // C++ member function. + + Token *Toks = + (Token*) PP.getPreprocessorAllocator().Allocate( + sizeof(Token) * 2 * Identifiers.size(), llvm::alignOf()); + for (unsigned i=0; i != Identifiers.size(); i++) { + Token &pragmaUnusedTok = Toks[2*i], &idTok = Toks[2*i+1]; + pragmaUnusedTok.startToken(); + pragmaUnusedTok.setKind(tok::annot_pragma_unused); + pragmaUnusedTok.setLocation(UnusedLoc); + idTok = Identifiers[i]; + } + PP.EnterTokenStream(Toks, 2*Identifiers.size(), + /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); +} + +// #pragma weak identifier +// #pragma weak identifier '=' identifier +void PragmaWeakHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &WeakTok) { + // FIXME: Should we be expanding macros here? My guess is no. + SourceLocation WeakLoc = WeakTok.getLocation(); + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak"; + return; + } + + IdentifierInfo *WeakName = Tok.getIdentifierInfo(), *AliasName = 0; + SourceLocation WeakNameLoc = Tok.getLocation(), AliasNameLoc; + + PP.Lex(Tok); + if (Tok.is(tok::equal)) { + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << "weak"; + return; + } + AliasName = Tok.getIdentifierInfo(); + AliasNameLoc = Tok.getLocation(); + PP.Lex(Tok); + } + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak"; + return; + } + + if (AliasName) { + Actions.ActOnPragmaWeakAlias(WeakName, AliasName, WeakLoc, WeakNameLoc, + AliasNameLoc); + } else { + Actions.ActOnPragmaWeakID(WeakName, WeakLoc, WeakNameLoc); + } +} + +// #pragma redefine_extname identifier identifier +void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &RedefToken) { + SourceLocation RedefLoc = RedefToken.getLocation(); + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << + "redefine_extname"; + return; + } + + IdentifierInfo *RedefName = Tok.getIdentifierInfo(), *AliasName = 0; + SourceLocation RedefNameLoc = Tok.getLocation(), AliasNameLoc; + + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << "redefine_extname"; + return; + } + AliasName = Tok.getIdentifierInfo(); + AliasNameLoc = Tok.getLocation(); + PP.Lex(Tok); + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << + "redefine_extname"; + return; + } + + Actions.ActOnPragmaRedefineExtname(RedefName, AliasName, RedefLoc, + RedefNameLoc, AliasNameLoc); +} + + +void +PragmaFPContractHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &Tok) { + tok::OnOffSwitch OOS; + if (PP.LexOnOffSwitch(OOS)) + return; + + Actions.ActOnPragmaFPContract(OOS); +} + +void +PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &Tok) { + PP.LexUnexpandedToken(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << + "OPENCL"; + return; + } + IdentifierInfo *ename = Tok.getIdentifierInfo(); + SourceLocation NameLoc = Tok.getLocation(); + + PP.Lex(Tok); + if (Tok.isNot(tok::colon)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_colon) << ename; + return; + } + + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable); + return; + } + IdentifierInfo *op = Tok.getIdentifierInfo(); + + unsigned state; + if (op->isStr("enable")) { + state = 1; + } else if (op->isStr("disable")) { + state = 0; + } else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable); + return; + } + + OpenCLOptions &f = Actions.getOpenCLOptions(); + // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions, + // overriding all previously issued extension directives, but only if the + // behavior is set to disable." + if (state == 0 && ename->isStr("all")) { +#define OPENCLEXT(nm) f.nm = 0; +#include "clang/Basic/OpenCLExtensions.def" + } +#define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; } +#include "clang/Basic/OpenCLExtensions.def" + else { + PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename; + return; + } +} + diff --git a/clang/lib/Parse/ParsePragma.h b/clang/lib/Parse/ParsePragma.h new file mode 100644 index 0000000..ebb185a --- /dev/null +++ b/clang/lib/Parse/ParsePragma.h @@ -0,0 +1,127 @@ +//===---- ParserPragmas.h - Language specific pragmas -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines #pragma handlers for language specific pragmas. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_PARSEPRAGMA_H +#define LLVM_CLANG_PARSE_PARSEPRAGMA_H + +#include "clang/Lex/Pragma.h" + +namespace clang { + class Sema; + class Parser; + +class PragmaAlignHandler : public PragmaHandler { + Sema &Actions; +public: + explicit PragmaAlignHandler(Sema &A) : PragmaHandler("align"), Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + +class PragmaGCCVisibilityHandler : public PragmaHandler { + Sema &Actions; +public: + explicit PragmaGCCVisibilityHandler(Sema &A) : PragmaHandler("visibility"), + Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + +class PragmaOptionsHandler : public PragmaHandler { + Sema &Actions; +public: + explicit PragmaOptionsHandler(Sema &A) : PragmaHandler("options"), + Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + +class PragmaPackHandler : public PragmaHandler { + Sema &Actions; +public: + explicit PragmaPackHandler(Sema &A) : PragmaHandler("pack"), + Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + +class PragmaMSStructHandler : public PragmaHandler { + Sema &Actions; +public: + explicit PragmaMSStructHandler(Sema &A) : PragmaHandler("ms_struct"), + Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + +class PragmaUnusedHandler : public PragmaHandler { + Sema &Actions; + Parser &parser; +public: + PragmaUnusedHandler(Sema &A, Parser& p) + : PragmaHandler("unused"), Actions(A), parser(p) {} + + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + +class PragmaWeakHandler : public PragmaHandler { + Sema &Actions; +public: + explicit PragmaWeakHandler(Sema &A) + : PragmaHandler("weak"), Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + +class PragmaRedefineExtnameHandler : public PragmaHandler { + Sema &Actions; +public: + explicit PragmaRedefineExtnameHandler(Sema &A) + : PragmaHandler("redefine_extname"), Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + +class PragmaOpenCLExtensionHandler : public PragmaHandler { + Sema &Actions; + Parser &parser; +public: + PragmaOpenCLExtensionHandler(Sema &S, Parser& p) : + PragmaHandler("EXTENSION"), Actions(S), parser(p) {} + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + + +class PragmaFPContractHandler : public PragmaHandler { + Sema &Actions; + Parser &parser; +public: + PragmaFPContractHandler(Sema &S, Parser& p) : + PragmaHandler("FP_CONTRACT"), Actions(S), parser(p) {} + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + + +} // end namespace clang + +#endif diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp new file mode 100644 index 0000000..44320df --- /dev/null +++ b/clang/lib/Parse/ParseStmt.cpp @@ -0,0 +1,2222 @@ +//===--- ParseStmt.cpp - Statement and Block Parser -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Statement and Block portions of the Parser +// interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "RAIIObjectsForParser.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/PrettyDeclStackTrace.h" +#include "clang/Sema/Scope.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/PrettyStackTrace.h" +#include "clang/Basic/SourceManager.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// C99 6.8: Statements and Blocks. +//===----------------------------------------------------------------------===// + +/// ParseStatementOrDeclaration - Read 'statement' or 'declaration'. +/// StatementOrDeclaration: +/// statement +/// declaration +/// +/// statement: +/// labeled-statement +/// compound-statement +/// expression-statement +/// selection-statement +/// iteration-statement +/// jump-statement +/// [C++] declaration-statement +/// [C++] try-block +/// [MS] seh-try-block +/// [OBC] objc-throw-statement +/// [OBC] objc-try-catch-statement +/// [OBC] objc-synchronized-statement +/// [GNU] asm-statement +/// [OMP] openmp-construct [TODO] +/// +/// labeled-statement: +/// identifier ':' statement +/// 'case' constant-expression ':' statement +/// 'default' ':' statement +/// +/// selection-statement: +/// if-statement +/// switch-statement +/// +/// iteration-statement: +/// while-statement +/// do-statement +/// for-statement +/// +/// expression-statement: +/// expression[opt] ';' +/// +/// jump-statement: +/// 'goto' identifier ';' +/// 'continue' ';' +/// 'break' ';' +/// 'return' expression[opt] ';' +/// [GNU] 'goto' '*' expression ';' +/// +/// [OBC] objc-throw-statement: +/// [OBC] '@' 'throw' expression ';' +/// [OBC] '@' 'throw' ';' +/// +StmtResult +Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, + SourceLocation *TrailingElseLoc) { + + ParenBraceBracketBalancer BalancerRAIIObj(*this); + + ParsedAttributesWithRange Attrs(AttrFactory); + MaybeParseCXX0XAttributes(Attrs, 0, /*MightBeObjCMessageSend*/ true); + + StmtResult Res = ParseStatementOrDeclarationAfterAttributes(Stmts, + OnlyStatement, TrailingElseLoc, Attrs); + + assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) && + "attributes on empty statement"); + + if (Attrs.empty() || Res.isInvalid()) + return Res; + + return Actions.ProcessStmtAttributes(Res.get(), Attrs.getList(), Attrs.Range); +} + +StmtResult +Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts, + bool OnlyStatement, SourceLocation *TrailingElseLoc, + ParsedAttributesWithRange &Attrs) { + const char *SemiError = 0; + StmtResult Res; + + // Cases in this switch statement should fall through if the parser expects + // the token to end in a semicolon (in which case SemiError should be set), + // or they directly 'return;' if not. +Retry: + tok::TokenKind Kind = Tok.getKind(); + SourceLocation AtLoc; + switch (Kind) { + case tok::at: // May be a @try or @throw statement + { + ProhibitAttributes(Attrs); // TODO: is it correct? + AtLoc = ConsumeToken(); // consume @ + return ParseObjCAtStatement(AtLoc); + } + + case tok::code_completion: + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement); + cutOffParsing(); + return StmtError(); + + case tok::identifier: { + Token Next = NextToken(); + if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement + // identifier ':' statement + return ParseLabeledStatement(Attrs); + } + + if (Next.isNot(tok::coloncolon)) { + CXXScopeSpec SS; + IdentifierInfo *Name = Tok.getIdentifierInfo(); + SourceLocation NameLoc = Tok.getLocation(); + + if (getLangOpts().CPlusPlus) + CheckForTemplateAndDigraph(Next, ParsedType(), + /*EnteringContext=*/false, *Name, SS); + + Sema::NameClassification Classification + = Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next); + switch (Classification.getKind()) { + case Sema::NC_Keyword: + // The identifier was corrected to a keyword. Update the token + // to this keyword, and try again. + if (Name->getTokenID() != tok::identifier) { + Tok.setIdentifierInfo(Name); + Tok.setKind(Name->getTokenID()); + goto Retry; + } + + // Fall through via the normal error path. + // FIXME: This seems like it could only happen for context-sensitive + // keywords. + + case Sema::NC_Error: + // Handle errors here by skipping up to the next semicolon or '}', and + // eat the semicolon if that's what stopped us. + SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return StmtError(); + + case Sema::NC_Unknown: + // Either we don't know anything about this identifier, or we know that + // we're in a syntactic context we haven't handled yet. + break; + + case Sema::NC_Type: + Tok.setKind(tok::annot_typename); + setTypeAnnotation(Tok, Classification.getType()); + Tok.setAnnotationEndLoc(NameLoc); + PP.AnnotateCachedTokens(Tok); + break; + + case Sema::NC_Expression: + Tok.setKind(tok::annot_primary_expr); + setExprAnnotation(Tok, Classification.getExpression()); + Tok.setAnnotationEndLoc(NameLoc); + PP.AnnotateCachedTokens(Tok); + break; + + case Sema::NC_TypeTemplate: + case Sema::NC_FunctionTemplate: { + ConsumeToken(); // the identifier + UnqualifiedId Id; + Id.setIdentifier(Name, NameLoc); + if (AnnotateTemplateIdToken( + TemplateTy::make(Classification.getTemplateName()), + Classification.getTemplateNameKind(), + SS, SourceLocation(), Id, + /*AllowTypeAnnotation=*/false)) { + // Handle errors here by skipping up to the next semicolon or '}', and + // eat the semicolon if that's what stopped us. + SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return StmtError(); + } + + // If the next token is '::', jump right into parsing a + // nested-name-specifier. We don't want to leave the template-id + // hanging. + if (NextToken().is(tok::coloncolon) && TryAnnotateCXXScopeToken(false)){ + // Handle errors here by skipping up to the next semicolon or '}', and + // eat the semicolon if that's what stopped us. + SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return StmtError(); + } + + // We've annotated a template-id, so try again now. + goto Retry; + } + + case Sema::NC_NestedNameSpecifier: + // FIXME: Implement this! + break; + } + } + + // Fall through + } + + default: { + if ((getLangOpts().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { + SourceLocation DeclStart = Tok.getLocation(), DeclEnd; + DeclGroupPtrTy Decl = ParseDeclaration(Stmts, Declarator::BlockContext, + DeclEnd, Attrs); + return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd); + } + + if (Tok.is(tok::r_brace)) { + Diag(Tok, diag::err_expected_statement); + return StmtError(); + } + + return ParseExprStatement(); + } + + case tok::kw_case: // C99 6.8.1: labeled-statement + return ParseCaseStatement(); + case tok::kw_default: // C99 6.8.1: labeled-statement + return ParseDefaultStatement(); + + case tok::l_brace: // C99 6.8.2: compound-statement + return ParseCompoundStatement(); + case tok::semi: { // C99 6.8.3p3: expression[opt] ';' + bool HasLeadingEmptyMacro = Tok.hasLeadingEmptyMacro(); + return Actions.ActOnNullStmt(ConsumeToken(), HasLeadingEmptyMacro); + } + + case tok::kw_if: // C99 6.8.4.1: if-statement + return ParseIfStatement(TrailingElseLoc); + case tok::kw_switch: // C99 6.8.4.2: switch-statement + return ParseSwitchStatement(TrailingElseLoc); + + case tok::kw_while: // C99 6.8.5.1: while-statement + return ParseWhileStatement(TrailingElseLoc); + case tok::kw_do: // C99 6.8.5.2: do-statement + Res = ParseDoStatement(); + SemiError = "do/while"; + break; + case tok::kw_for: // C99 6.8.5.3: for-statement + return ParseForStatement(TrailingElseLoc); + + case tok::kw_goto: // C99 6.8.6.1: goto-statement + Res = ParseGotoStatement(); + SemiError = "goto"; + break; + case tok::kw_continue: // C99 6.8.6.2: continue-statement + Res = ParseContinueStatement(); + SemiError = "continue"; + break; + case tok::kw_break: // C99 6.8.6.3: break-statement + Res = ParseBreakStatement(); + SemiError = "break"; + break; + case tok::kw_return: // C99 6.8.6.4: return-statement + Res = ParseReturnStatement(); + SemiError = "return"; + break; + + case tok::kw_asm: { + ProhibitAttributes(Attrs); + bool msAsm = false; + Res = ParseAsmStatement(msAsm); + Res = Actions.ActOnFinishFullStmt(Res.get()); + if (msAsm) return move(Res); + SemiError = "asm"; + break; + } + + case tok::kw_try: // C++ 15: try-block + return ParseCXXTryBlock(); + + case tok::kw___try: + ProhibitAttributes(Attrs); // TODO: is it correct? + return ParseSEHTryBlock(); + + case tok::annot_pragma_vis: + ProhibitAttributes(Attrs); + HandlePragmaVisibility(); + return StmtEmpty(); + + case tok::annot_pragma_pack: + ProhibitAttributes(Attrs); + HandlePragmaPack(); + return StmtEmpty(); + } + + // If we reached this code, the statement must end in a semicolon. + if (Tok.is(tok::semi)) { + ConsumeToken(); + } else if (!Res.isInvalid()) { + // If the result was valid, then we do want to diagnose this. Use + // ExpectAndConsume to emit the diagnostic, even though we know it won't + // succeed. + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_stmt, SemiError); + // Skip until we see a } or ;, but don't eat it. + SkipUntil(tok::r_brace, true, true); + } + + return move(Res); +} + +/// \brief Parse an expression statement. +StmtResult Parser::ParseExprStatement() { + // If a case keyword is missing, this is where it should be inserted. + Token OldToken = Tok; + + // expression[opt] ';' + ExprResult Expr(ParseExpression()); + if (Expr.isInvalid()) { + // If the expression is invalid, skip ahead to the next semicolon or '}'. + // Not doing this opens us up to the possibility of infinite loops if + // ParseExpression does not consume any tokens. + SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return StmtError(); + } + + if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() && + Actions.CheckCaseExpression(Expr.get())) { + // If a constant expression is followed by a colon inside a switch block, + // suggest a missing case keyword. + Diag(OldToken, diag::err_expected_case_before_expression) + << FixItHint::CreateInsertion(OldToken.getLocation(), "case "); + + // Recover parsing as a case statement. + return ParseCaseStatement(/*MissingCase=*/true, Expr); + } + + // Otherwise, eat the semicolon. + ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); + return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get())); +} + +StmtResult Parser::ParseSEHTryBlock() { + assert(Tok.is(tok::kw___try) && "Expected '__try'"); + SourceLocation Loc = ConsumeToken(); + return ParseSEHTryBlockCommon(Loc); +} + +/// ParseSEHTryBlockCommon +/// +/// seh-try-block: +/// '__try' compound-statement seh-handler +/// +/// seh-handler: +/// seh-except-block +/// seh-finally-block +/// +StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) { + if(Tok.isNot(tok::l_brace)) + return StmtError(Diag(Tok,diag::err_expected_lbrace)); + + StmtResult TryBlock(ParseCompoundStatement()); + if(TryBlock.isInvalid()) + return move(TryBlock); + + StmtResult Handler; + if (Tok.is(tok::identifier) && + Tok.getIdentifierInfo() == getSEHExceptKeyword()) { + SourceLocation Loc = ConsumeToken(); + Handler = ParseSEHExceptBlock(Loc); + } else if (Tok.is(tok::kw___finally)) { + SourceLocation Loc = ConsumeToken(); + Handler = ParseSEHFinallyBlock(Loc); + } else { + return StmtError(Diag(Tok,diag::err_seh_expected_handler)); + } + + if(Handler.isInvalid()) + return move(Handler); + + return Actions.ActOnSEHTryBlock(false /* IsCXXTry */, + TryLoc, + TryBlock.take(), + Handler.take()); +} + +/// ParseSEHExceptBlock - Handle __except +/// +/// seh-except-block: +/// '__except' '(' seh-filter-expression ')' compound-statement +/// +StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { + PoisonIdentifierRAIIObject raii(Ident__exception_code, false), + raii2(Ident___exception_code, false), + raii3(Ident_GetExceptionCode, false); + + if(ExpectAndConsume(tok::l_paren,diag::err_expected_lparen)) + return StmtError(); + + ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope); + + if (getLangOpts().Borland) { + Ident__exception_info->setIsPoisoned(false); + Ident___exception_info->setIsPoisoned(false); + Ident_GetExceptionInfo->setIsPoisoned(false); + } + ExprResult FilterExpr(ParseExpression()); + + if (getLangOpts().Borland) { + Ident__exception_info->setIsPoisoned(true); + Ident___exception_info->setIsPoisoned(true); + Ident_GetExceptionInfo->setIsPoisoned(true); + } + + if(FilterExpr.isInvalid()) + return StmtError(); + + if(ExpectAndConsume(tok::r_paren,diag::err_expected_rparen)) + return StmtError(); + + StmtResult Block(ParseCompoundStatement()); + + if(Block.isInvalid()) + return move(Block); + + return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.take(), Block.take()); +} + +/// ParseSEHFinallyBlock - Handle __finally +/// +/// seh-finally-block: +/// '__finally' compound-statement +/// +StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) { + PoisonIdentifierRAIIObject raii(Ident__abnormal_termination, false), + raii2(Ident___abnormal_termination, false), + raii3(Ident_AbnormalTermination, false); + + StmtResult Block(ParseCompoundStatement()); + if(Block.isInvalid()) + return move(Block); + + return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.take()); +} + +/// ParseLabeledStatement - We have an identifier and a ':' after it. +/// +/// labeled-statement: +/// identifier ':' statement +/// [GNU] identifier ':' attributes[opt] statement +/// +StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) { + assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && + "Not an identifier!"); + + Token IdentTok = Tok; // Save the whole token. + ConsumeToken(); // eat the identifier. + + assert(Tok.is(tok::colon) && "Not a label!"); + + // identifier ':' statement + SourceLocation ColonLoc = ConsumeToken(); + + // Read label attributes, if present. attrs will contain both C++11 and GNU + // attributes (if present) after this point. + MaybeParseGNUAttributes(attrs); + + StmtResult SubStmt(ParseStatement()); + + // Broken substmt shouldn't prevent the label from being added to the AST. + if (SubStmt.isInvalid()) + SubStmt = Actions.ActOnNullStmt(ColonLoc); + + LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(), + IdentTok.getLocation()); + if (AttributeList *Attrs = attrs.getList()) { + Actions.ProcessDeclAttributeList(Actions.CurScope, LD, Attrs); + attrs.clear(); + } + + return Actions.ActOnLabelStmt(IdentTok.getLocation(), LD, ColonLoc, + SubStmt.get()); +} + +/// ParseCaseStatement +/// labeled-statement: +/// 'case' constant-expression ':' statement +/// [GNU] 'case' constant-expression '...' constant-expression ':' statement +/// +StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) { + assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!"); + + // It is very very common for code to contain many case statements recursively + // nested, as in (but usually without indentation): + // case 1: + // case 2: + // case 3: + // case 4: + // case 5: etc. + // + // Parsing this naively works, but is both inefficient and can cause us to run + // out of stack space in our recursive descent parser. As a special case, + // flatten this recursion into an iterative loop. This is complex and gross, + // but all the grossness is constrained to ParseCaseStatement (and some + // wierdness in the actions), so this is just local grossness :). + + // TopLevelCase - This is the highest level we have parsed. 'case 1' in the + // example above. + StmtResult TopLevelCase(true); + + // DeepestParsedCaseStmt - This is the deepest statement we have parsed, which + // gets updated each time a new case is parsed, and whose body is unset so + // far. When parsing 'case 4', this is the 'case 3' node. + Stmt *DeepestParsedCaseStmt = 0; + + // While we have case statements, eat and stack them. + SourceLocation ColonLoc; + do { + SourceLocation CaseLoc = MissingCase ? Expr.get()->getExprLoc() : + ConsumeToken(); // eat the 'case'. + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteCase(getCurScope()); + cutOffParsing(); + return StmtError(); + } + + /// We don't want to treat 'case x : y' as a potential typo for 'case x::y'. + /// Disable this form of error recovery while we're parsing the case + /// expression. + ColonProtectionRAIIObject ColonProtection(*this); + + ExprResult LHS(MissingCase ? Expr : ParseConstantExpression()); + MissingCase = false; + if (LHS.isInvalid()) { + SkipUntil(tok::colon); + return StmtError(); + } + + // GNU case range extension. + SourceLocation DotDotDotLoc; + ExprResult RHS; + if (Tok.is(tok::ellipsis)) { + Diag(Tok, diag::ext_gnu_case_range); + DotDotDotLoc = ConsumeToken(); + + RHS = ParseConstantExpression(); + if (RHS.isInvalid()) { + SkipUntil(tok::colon); + return StmtError(); + } + } + + ColonProtection.restore(); + + if (Tok.is(tok::colon)) { + ColonLoc = ConsumeToken(); + + // Treat "case blah;" as a typo for "case blah:". + } else if (Tok.is(tok::semi)) { + ColonLoc = ConsumeToken(); + Diag(ColonLoc, diag::err_expected_colon_after) << "'case'" + << FixItHint::CreateReplacement(ColonLoc, ":"); + } else { + SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation); + Diag(ExpectedLoc, diag::err_expected_colon_after) << "'case'" + << FixItHint::CreateInsertion(ExpectedLoc, ":"); + ColonLoc = ExpectedLoc; + } + + StmtResult Case = + Actions.ActOnCaseStmt(CaseLoc, LHS.get(), DotDotDotLoc, + RHS.get(), ColonLoc); + + // If we had a sema error parsing this case, then just ignore it and + // continue parsing the sub-stmt. + if (Case.isInvalid()) { + if (TopLevelCase.isInvalid()) // No parsed case stmts. + return ParseStatement(); + // Otherwise, just don't add it as a nested case. + } else { + // If this is the first case statement we parsed, it becomes TopLevelCase. + // Otherwise we link it into the current chain. + Stmt *NextDeepest = Case.get(); + if (TopLevelCase.isInvalid()) + TopLevelCase = move(Case); + else + Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, Case.get()); + DeepestParsedCaseStmt = NextDeepest; + } + + // Handle all case statements. + } while (Tok.is(tok::kw_case)); + + assert(!TopLevelCase.isInvalid() && "Should have parsed at least one case!"); + + // If we found a non-case statement, start by parsing it. + StmtResult SubStmt; + + if (Tok.isNot(tok::r_brace)) { + SubStmt = ParseStatement(); + } else { + // Nicely diagnose the common error "switch (X) { case 4: }", which is + // not valid. + SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc); + Diag(AfterColonLoc, diag::err_label_end_of_compound_statement) + << FixItHint::CreateInsertion(AfterColonLoc, " ;"); + SubStmt = true; + } + + // Broken sub-stmt shouldn't prevent forming the case statement properly. + if (SubStmt.isInvalid()) + SubStmt = Actions.ActOnNullStmt(SourceLocation()); + + // Install the body into the most deeply-nested case. + Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get()); + + // Return the top level parsed statement tree. + return move(TopLevelCase); +} + +/// ParseDefaultStatement +/// labeled-statement: +/// 'default' ':' statement +/// Note that this does not parse the 'statement' at the end. +/// +StmtResult Parser::ParseDefaultStatement() { + assert(Tok.is(tok::kw_default) && "Not a default stmt!"); + SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. + + SourceLocation ColonLoc; + if (Tok.is(tok::colon)) { + ColonLoc = ConsumeToken(); + + // Treat "default;" as a typo for "default:". + } else if (Tok.is(tok::semi)) { + ColonLoc = ConsumeToken(); + Diag(ColonLoc, diag::err_expected_colon_after) << "'default'" + << FixItHint::CreateReplacement(ColonLoc, ":"); + } else { + SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation); + Diag(ExpectedLoc, diag::err_expected_colon_after) << "'default'" + << FixItHint::CreateInsertion(ExpectedLoc, ":"); + ColonLoc = ExpectedLoc; + } + + StmtResult SubStmt; + + if (Tok.isNot(tok::r_brace)) { + SubStmt = ParseStatement(); + } else { + // Diagnose the common error "switch (X) {... default: }", which is + // not valid. + SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc); + Diag(AfterColonLoc, diag::err_label_end_of_compound_statement) + << FixItHint::CreateInsertion(AfterColonLoc, " ;"); + SubStmt = true; + } + + // Broken sub-stmt shouldn't prevent forming the case statement properly. + if (SubStmt.isInvalid()) + SubStmt = Actions.ActOnNullStmt(ColonLoc); + + return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc, + SubStmt.get(), getCurScope()); +} + +StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { + return ParseCompoundStatement(isStmtExpr, Scope::DeclScope); +} + +/// ParseCompoundStatement - Parse a "{}" block. +/// +/// compound-statement: [C99 6.8.2] +/// { block-item-list[opt] } +/// [GNU] { label-declarations block-item-list } [TODO] +/// +/// block-item-list: +/// block-item +/// block-item-list block-item +/// +/// block-item: +/// declaration +/// [GNU] '__extension__' declaration +/// statement +/// [OMP] openmp-directive [TODO] +/// +/// [GNU] label-declarations: +/// [GNU] label-declaration +/// [GNU] label-declarations label-declaration +/// +/// [GNU] label-declaration: +/// [GNU] '__label__' identifier-list ';' +/// +/// [OMP] openmp-directive: [TODO] +/// [OMP] barrier-directive +/// [OMP] flush-directive +/// +StmtResult Parser::ParseCompoundStatement(bool isStmtExpr, + unsigned ScopeFlags) { + assert(Tok.is(tok::l_brace) && "Not a compount stmt!"); + + // Enter a scope to hold everything within the compound stmt. Compound + // statements can always hold declarations. + ParseScope CompoundScope(this, ScopeFlags); + + // Parse the statements in the body. + return ParseCompoundStatementBody(isStmtExpr); +} + +/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the +/// ActOnCompoundStmt action. This expects the '{' to be the current token, and +/// consume the '}' at the end of the block. It does not manipulate the scope +/// stack. +StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { + PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), + Tok.getLocation(), + "in compound statement ('{}')"); + InMessageExpressionRAIIObject InMessage(*this, false); + BalancedDelimiterTracker T(*this, tok::l_brace); + if (T.consumeOpen()) + return StmtError(); + + Sema::CompoundScopeRAII CompoundScope(Actions); + + StmtVector Stmts(Actions); + + // "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are + // only allowed at the start of a compound stmt regardless of the language. + while (Tok.is(tok::kw___label__)) { + SourceLocation LabelLoc = ConsumeToken(); + Diag(LabelLoc, diag::ext_gnu_local_label); + + SmallVector DeclsInGroup; + while (1) { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + break; + } + + IdentifierInfo *II = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, LabelLoc)); + + if (!Tok.is(tok::comma)) + break; + ConsumeToken(); + } + + DeclSpec DS(AttrFactory); + DeclGroupPtrTy Res = Actions.FinalizeDeclaratorGroup(getCurScope(), DS, + DeclsInGroup.data(), DeclsInGroup.size()); + StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation()); + + ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); + if (R.isUsable()) + Stmts.push_back(R.release()); + } + + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + if (Tok.is(tok::annot_pragma_unused)) { + HandlePragmaUnused(); + continue; + } + + if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) || + Tok.is(tok::kw___if_not_exists))) { + ParseMicrosoftIfExistsStatement(Stmts); + continue; + } + + StmtResult R; + if (Tok.isNot(tok::kw___extension__)) { + R = ParseStatementOrDeclaration(Stmts, false); + } else { + // __extension__ can start declarations and it can also be a unary + // operator for expressions. Consume multiple __extension__ markers here + // until we can determine which is which. + // FIXME: This loses extension expressions in the AST! + SourceLocation ExtLoc = ConsumeToken(); + while (Tok.is(tok::kw___extension__)) + ConsumeToken(); + + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs, 0, /*MightBeObjCMessageSend*/ true); + + // If this is the start of a declaration, parse it as such. + if (isDeclarationStatement()) { + // __extension__ silences extension warnings in the subdeclaration. + // FIXME: Save the __extension__ on the decl as a node somehow? + ExtensionRAIIObject O(Diags); + + SourceLocation DeclStart = Tok.getLocation(), DeclEnd; + DeclGroupPtrTy Res = ParseDeclaration(Stmts, + Declarator::BlockContext, DeclEnd, + attrs); + R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd); + } else { + // Otherwise this was a unary __extension__ marker. + ExprResult Res(ParseExpressionWithLeadingExtension(ExtLoc)); + + if (Res.isInvalid()) { + SkipUntil(tok::semi); + continue; + } + + // FIXME: Use attributes? + // Eat the semicolon at the end of stmt and convert the expr into a + // statement. + ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); + R = Actions.ActOnExprStmt(Actions.MakeFullExpr(Res.get())); + } + } + + if (R.isUsable()) + Stmts.push_back(R.release()); + } + + SourceLocation CloseLoc = Tok.getLocation(); + + // We broke out of the while loop because we found a '}' or EOF. + if (Tok.isNot(tok::r_brace)) { + Diag(Tok, diag::err_expected_rbrace); + Diag(T.getOpenLocation(), diag::note_matching) << "{"; + // Recover by creating a compound statement with what we parsed so far, + // instead of dropping everything and returning StmtError(); + } else { + if (!T.consumeClose()) + CloseLoc = T.getCloseLocation(); + } + + return Actions.ActOnCompoundStmt(T.getOpenLocation(), CloseLoc, + move_arg(Stmts), isStmtExpr); +} + +/// ParseParenExprOrCondition: +/// [C ] '(' expression ')' +/// [C++] '(' condition ')' [not allowed if OnlyAllowCondition=true] +/// +/// This function parses and performs error recovery on the specified condition +/// or expression (depending on whether we're in C++ or C mode). This function +/// goes out of its way to recover well. It returns true if there was a parser +/// error (the right paren couldn't be found), which indicates that the caller +/// should try to recover harder. It returns false if the condition is +/// successfully parsed. Note that a successful parse can still have semantic +/// errors in the condition. +bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, + Decl *&DeclResult, + SourceLocation Loc, + bool ConvertToBoolean) { + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + if (getLangOpts().CPlusPlus) + ParseCXXCondition(ExprResult, DeclResult, Loc, ConvertToBoolean); + else { + ExprResult = ParseExpression(); + DeclResult = 0; + + // If required, convert to a boolean value. + if (!ExprResult.isInvalid() && ConvertToBoolean) + ExprResult + = Actions.ActOnBooleanCondition(getCurScope(), Loc, ExprResult.get()); + } + + // If the parser was confused by the condition and we don't have a ')', try to + // recover by skipping ahead to a semi and bailing out. If condexp is + // semantically invalid but we have well formed code, keep going. + if (ExprResult.isInvalid() && !DeclResult && Tok.isNot(tok::r_paren)) { + SkipUntil(tok::semi); + // Skipping may have stopped if it found the containing ')'. If so, we can + // continue parsing the if statement. + if (Tok.isNot(tok::r_paren)) + return true; + } + + // Otherwise the condition is valid or the rparen is present. + T.consumeClose(); + return false; +} + + +/// ParseIfStatement +/// if-statement: [C99 6.8.4.1] +/// 'if' '(' expression ')' statement +/// 'if' '(' expression ')' statement 'else' statement +/// [C++] 'if' '(' condition ')' statement +/// [C++] 'if' '(' condition ')' statement 'else' statement +/// +StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { + assert(Tok.is(tok::kw_if) && "Not an if stmt!"); + SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << "if"; + SkipUntil(tok::semi); + return StmtError(); + } + + bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus; + + // C99 6.8.4p3 - In C99, the if statement is a block. This is not + // the case for C90. + // + // C++ 6.4p3: + // A name introduced by a declaration in a condition is in scope from its + // point of declaration until the end of the substatements controlled by the + // condition. + // C++ 3.3.2p4: + // Names declared in the for-init-statement, and in the condition of if, + // while, for, and switch statements are local to the if, while, for, or + // switch statement (including the controlled statement). + // + ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX); + + // Parse the condition. + ExprResult CondExp; + Decl *CondVar = 0; + if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true)) + return StmtError(); + + FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp.get())); + + // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if + // there is no compound stmt. C90 does not have this clause. We only do this + // if the body isn't a compound statement to avoid push/pop in common cases. + // + // C++ 6.4p1: + // The substatement in a selection-statement (each substatement, in the else + // form of the if statement) implicitly defines a local scope. + // + // For C++ we create a scope for the condition and a new scope for + // substatements because: + // -When the 'then' scope exits, we want the condition declaration to still be + // active for the 'else' scope too. + // -Sema will detect name clashes by considering declarations of a + // 'ControlScope' as part of its direct subscope. + // -If we wanted the condition and substatement to be in the same scope, we + // would have to notify ParseStatement not to create a new scope. It's + // simpler to let it create a new scope. + // + ParseScope InnerScope(this, Scope::DeclScope, + C99orCXX && Tok.isNot(tok::l_brace)); + + // Read the 'then' stmt. + SourceLocation ThenStmtLoc = Tok.getLocation(); + + SourceLocation InnerStatementTrailingElseLoc; + StmtResult ThenStmt(ParseStatement(&InnerStatementTrailingElseLoc)); + + // Pop the 'if' scope if needed. + InnerScope.Exit(); + + // If it has an else, parse it. + SourceLocation ElseLoc; + SourceLocation ElseStmtLoc; + StmtResult ElseStmt; + + if (Tok.is(tok::kw_else)) { + if (TrailingElseLoc) + *TrailingElseLoc = Tok.getLocation(); + + ElseLoc = ConsumeToken(); + ElseStmtLoc = Tok.getLocation(); + + // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if + // there is no compound stmt. C90 does not have this clause. We only do + // this if the body isn't a compound statement to avoid push/pop in common + // cases. + // + // C++ 6.4p1: + // The substatement in a selection-statement (each substatement, in the else + // form of the if statement) implicitly defines a local scope. + // + ParseScope InnerScope(this, Scope::DeclScope, + C99orCXX && Tok.isNot(tok::l_brace)); + + ElseStmt = ParseStatement(); + + // Pop the 'else' scope if needed. + InnerScope.Exit(); + } else if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteAfterIf(getCurScope()); + cutOffParsing(); + return StmtError(); + } else if (InnerStatementTrailingElseLoc.isValid()) { + Diag(InnerStatementTrailingElseLoc, diag::warn_dangling_else); + } + + IfScope.Exit(); + + // If the condition was invalid, discard the if statement. We could recover + // better by replacing it with a valid expr, but don't do that yet. + if (CondExp.isInvalid() && !CondVar) + return StmtError(); + + // If the then or else stmt is invalid and the other is valid (and present), + // make turn the invalid one into a null stmt to avoid dropping the other + // part. If both are invalid, return error. + if ((ThenStmt.isInvalid() && ElseStmt.isInvalid()) || + (ThenStmt.isInvalid() && ElseStmt.get() == 0) || + (ThenStmt.get() == 0 && ElseStmt.isInvalid())) { + // Both invalid, or one is invalid and other is non-present: return error. + return StmtError(); + } + + // Now if either are invalid, replace with a ';'. + if (ThenStmt.isInvalid()) + ThenStmt = Actions.ActOnNullStmt(ThenStmtLoc); + if (ElseStmt.isInvalid()) + ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); + + return Actions.ActOnIfStmt(IfLoc, FullCondExp, CondVar, ThenStmt.get(), + ElseLoc, ElseStmt.get()); +} + +/// ParseSwitchStatement +/// switch-statement: +/// 'switch' '(' expression ')' statement +/// [C++] 'switch' '(' condition ')' statement +StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) { + assert(Tok.is(tok::kw_switch) && "Not a switch stmt!"); + SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'. + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << "switch"; + SkipUntil(tok::semi); + return StmtError(); + } + + bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus; + + // C99 6.8.4p3 - In C99, the switch statement is a block. This is + // not the case for C90. Start the switch scope. + // + // C++ 6.4p3: + // A name introduced by a declaration in a condition is in scope from its + // point of declaration until the end of the substatements controlled by the + // condition. + // C++ 3.3.2p4: + // Names declared in the for-init-statement, and in the condition of if, + // while, for, and switch statements are local to the if, while, for, or + // switch statement (including the controlled statement). + // + unsigned ScopeFlags = Scope::BreakScope | Scope::SwitchScope; + if (C99orCXX) + ScopeFlags |= Scope::DeclScope | Scope::ControlScope; + ParseScope SwitchScope(this, ScopeFlags); + + // Parse the condition. + ExprResult Cond; + Decl *CondVar = 0; + if (ParseParenExprOrCondition(Cond, CondVar, SwitchLoc, false)) + return StmtError(); + + StmtResult Switch + = Actions.ActOnStartOfSwitchStmt(SwitchLoc, Cond.get(), CondVar); + + if (Switch.isInvalid()) { + // Skip the switch body. + // FIXME: This is not optimal recovery, but parsing the body is more + // dangerous due to the presence of case and default statements, which + // will have no place to connect back with the switch. + if (Tok.is(tok::l_brace)) { + ConsumeBrace(); + SkipUntil(tok::r_brace, false, false); + } else + SkipUntil(tok::semi); + return move(Switch); + } + + // C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if + // there is no compound stmt. C90 does not have this clause. We only do this + // if the body isn't a compound statement to avoid push/pop in common cases. + // + // C++ 6.4p1: + // The substatement in a selection-statement (each substatement, in the else + // form of the if statement) implicitly defines a local scope. + // + // See comments in ParseIfStatement for why we create a scope for the + // condition and a new scope for substatement in C++. + // + ParseScope InnerScope(this, Scope::DeclScope, + C99orCXX && Tok.isNot(tok::l_brace)); + + // Read the body statement. + StmtResult Body(ParseStatement(TrailingElseLoc)); + + // Pop the scopes. + InnerScope.Exit(); + SwitchScope.Exit(); + + if (Body.isInvalid()) { + // FIXME: Remove the case statement list from the Switch statement. + + // Put the synthesized null statement on the same line as the end of switch + // condition. + SourceLocation SynthesizedNullStmtLocation = Cond.get()->getLocEnd(); + Body = Actions.ActOnNullStmt(SynthesizedNullStmtLocation); + } + + return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get()); +} + +/// ParseWhileStatement +/// while-statement: [C99 6.8.5.1] +/// 'while' '(' expression ')' statement +/// [C++] 'while' '(' condition ')' statement +StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) { + assert(Tok.is(tok::kw_while) && "Not a while stmt!"); + SourceLocation WhileLoc = Tok.getLocation(); + ConsumeToken(); // eat the 'while'. + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << "while"; + SkipUntil(tok::semi); + return StmtError(); + } + + bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus; + + // C99 6.8.5p5 - In C99, the while statement is a block. This is not + // the case for C90. Start the loop scope. + // + // C++ 6.4p3: + // A name introduced by a declaration in a condition is in scope from its + // point of declaration until the end of the substatements controlled by the + // condition. + // C++ 3.3.2p4: + // Names declared in the for-init-statement, and in the condition of if, + // while, for, and switch statements are local to the if, while, for, or + // switch statement (including the controlled statement). + // + unsigned ScopeFlags; + if (C99orCXX) + ScopeFlags = Scope::BreakScope | Scope::ContinueScope | + Scope::DeclScope | Scope::ControlScope; + else + ScopeFlags = Scope::BreakScope | Scope::ContinueScope; + ParseScope WhileScope(this, ScopeFlags); + + // Parse the condition. + ExprResult Cond; + Decl *CondVar = 0; + if (ParseParenExprOrCondition(Cond, CondVar, WhileLoc, true)) + return StmtError(); + + FullExprArg FullCond(Actions.MakeFullExpr(Cond.get())); + + // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if + // there is no compound stmt. C90 does not have this clause. We only do this + // if the body isn't a compound statement to avoid push/pop in common cases. + // + // C++ 6.5p2: + // The substatement in an iteration-statement implicitly defines a local scope + // which is entered and exited each time through the loop. + // + // See comments in ParseIfStatement for why we create a scope for the + // condition and a new scope for substatement in C++. + // + ParseScope InnerScope(this, Scope::DeclScope, + C99orCXX && Tok.isNot(tok::l_brace)); + + // Read the body statement. + StmtResult Body(ParseStatement(TrailingElseLoc)); + + // Pop the body scope if needed. + InnerScope.Exit(); + WhileScope.Exit(); + + if ((Cond.isInvalid() && !CondVar) || Body.isInvalid()) + return StmtError(); + + return Actions.ActOnWhileStmt(WhileLoc, FullCond, CondVar, Body.get()); +} + +/// ParseDoStatement +/// do-statement: [C99 6.8.5.2] +/// 'do' statement 'while' '(' expression ')' ';' +/// Note: this lets the caller parse the end ';'. +StmtResult Parser::ParseDoStatement() { + assert(Tok.is(tok::kw_do) && "Not a do stmt!"); + SourceLocation DoLoc = ConsumeToken(); // eat the 'do'. + + // C99 6.8.5p5 - In C99, the do statement is a block. This is not + // the case for C90. Start the loop scope. + unsigned ScopeFlags; + if (getLangOpts().C99) + ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope; + else + ScopeFlags = Scope::BreakScope | Scope::ContinueScope; + + ParseScope DoScope(this, ScopeFlags); + + // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if + // there is no compound stmt. C90 does not have this clause. We only do this + // if the body isn't a compound statement to avoid push/pop in common cases. + // + // C++ 6.5p2: + // The substatement in an iteration-statement implicitly defines a local scope + // which is entered and exited each time through the loop. + // + ParseScope InnerScope(this, Scope::DeclScope, + (getLangOpts().C99 || getLangOpts().CPlusPlus) && + Tok.isNot(tok::l_brace)); + + // Read the body statement. + StmtResult Body(ParseStatement()); + + // Pop the body scope if needed. + InnerScope.Exit(); + + if (Tok.isNot(tok::kw_while)) { + if (!Body.isInvalid()) { + Diag(Tok, diag::err_expected_while); + Diag(DoLoc, diag::note_matching) << "do"; + SkipUntil(tok::semi, false, true); + } + return StmtError(); + } + SourceLocation WhileLoc = ConsumeToken(); + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << "do/while"; + SkipUntil(tok::semi, false, true); + return StmtError(); + } + + // Parse the parenthesized condition. + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + ExprResult Cond = ParseExpression(); + T.consumeClose(); + DoScope.Exit(); + + if (Cond.isInvalid() || Body.isInvalid()) + return StmtError(); + + return Actions.ActOnDoStmt(DoLoc, Body.get(), WhileLoc, T.getOpenLocation(), + Cond.get(), T.getCloseLocation()); +} + +/// ParseForStatement +/// for-statement: [C99 6.8.5.3] +/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement +/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement +/// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')' +/// [C++] statement +/// [C++0x] 'for' '(' for-range-declaration : for-range-initializer ) statement +/// [OBJC2] 'for' '(' declaration 'in' expr ')' statement +/// [OBJC2] 'for' '(' expr 'in' expr ')' statement +/// +/// [C++] for-init-statement: +/// [C++] expression-statement +/// [C++] simple-declaration +/// +/// [C++0x] for-range-declaration: +/// [C++0x] attribute-specifier-seq[opt] type-specifier-seq declarator +/// [C++0x] for-range-initializer: +/// [C++0x] expression +/// [C++0x] braced-init-list [TODO] +StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { + assert(Tok.is(tok::kw_for) && "Not a for stmt!"); + SourceLocation ForLoc = ConsumeToken(); // eat the 'for'. + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << "for"; + SkipUntil(tok::semi); + return StmtError(); + } + + bool C99orCXXorObjC = getLangOpts().C99 || getLangOpts().CPlusPlus || getLangOpts().ObjC1; + + // C99 6.8.5p5 - In C99, the for statement is a block. This is not + // the case for C90. Start the loop scope. + // + // C++ 6.4p3: + // A name introduced by a declaration in a condition is in scope from its + // point of declaration until the end of the substatements controlled by the + // condition. + // C++ 3.3.2p4: + // Names declared in the for-init-statement, and in the condition of if, + // while, for, and switch statements are local to the if, while, for, or + // switch statement (including the controlled statement). + // C++ 6.5.3p1: + // Names declared in the for-init-statement are in the same declarative-region + // as those declared in the condition. + // + unsigned ScopeFlags; + if (C99orCXXorObjC) + ScopeFlags = Scope::BreakScope | Scope::ContinueScope | + Scope::DeclScope | Scope::ControlScope; + else + ScopeFlags = Scope::BreakScope | Scope::ContinueScope; + + ParseScope ForScope(this, ScopeFlags); + + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + ExprResult Value; + + bool ForEach = false, ForRange = false; + StmtResult FirstPart; + bool SecondPartIsInvalid = false; + FullExprArg SecondPart(Actions); + ExprResult Collection; + ForRangeInit ForRangeInit; + FullExprArg ThirdPart(Actions); + Decl *SecondVar = 0; + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(getCurScope(), + C99orCXXorObjC? Sema::PCC_ForInit + : Sema::PCC_Expression); + cutOffParsing(); + return StmtError(); + } + + // Parse the first part of the for specifier. + if (Tok.is(tok::semi)) { // for (; + // no first part, eat the ';'. + ConsumeToken(); + } else if (isForInitDeclaration()) { // for (int X = 4; + // Parse declaration, which eats the ';'. + if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode? + Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); + + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + + // In C++0x, "for (T NS:a" might not be a typo for :: + bool MightBeForRangeStmt = getLangOpts().CPlusPlus; + ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); + + SourceLocation DeclStart = Tok.getLocation(), DeclEnd; + StmtVector Stmts(Actions); + DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext, + DeclEnd, attrs, false, + MightBeForRangeStmt ? + &ForRangeInit : 0); + FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); + + if (ForRangeInit.ParsedForRangeDecl()) { + Diag(ForRangeInit.ColonLoc, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_for_range : diag::ext_for_range); + + ForRange = true; + } else if (Tok.is(tok::semi)) { // for (int x = 4; + ConsumeToken(); + } else if ((ForEach = isTokIdentifier_in())) { + Actions.ActOnForEachDeclStmt(DG); + // ObjC: for (id x in expr) + ConsumeToken(); // consume 'in' + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCForCollection(getCurScope(), DG); + cutOffParsing(); + return StmtError(); + } + Collection = ParseExpression(); + } else { + Diag(Tok, diag::err_expected_semi_for); + } + } else { + Value = ParseExpression(); + + ForEach = isTokIdentifier_in(); + + // Turn the expression into a stmt. + if (!Value.isInvalid()) { + if (ForEach) + FirstPart = Actions.ActOnForEachLValueExpr(Value.get()); + else + FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value.get())); + } + + if (Tok.is(tok::semi)) { + ConsumeToken(); + } else if (ForEach) { + ConsumeToken(); // consume 'in' + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCForCollection(getCurScope(), DeclGroupPtrTy()); + cutOffParsing(); + return StmtError(); + } + Collection = ParseExpression(); + } else if (getLangOpts().CPlusPlus0x && Tok.is(tok::colon) && FirstPart.get()) { + // User tried to write the reasonable, but ill-formed, for-range-statement + // for (expr : expr) { ... } + Diag(Tok, diag::err_for_range_expected_decl) + << FirstPart.get()->getSourceRange(); + SkipUntil(tok::r_paren, false, true); + SecondPartIsInvalid = true; + } else { + if (!Value.isInvalid()) { + Diag(Tok, diag::err_expected_semi_for); + } else { + // Skip until semicolon or rparen, don't consume it. + SkipUntil(tok::r_paren, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + } + } + } + if (!ForEach && !ForRange) { + assert(!SecondPart.get() && "Shouldn't have a second expression yet."); + // Parse the second part of the for specifier. + if (Tok.is(tok::semi)) { // for (...;; + // no second part. + } else if (Tok.is(tok::r_paren)) { + // missing both semicolons. + } else { + ExprResult Second; + if (getLangOpts().CPlusPlus) + ParseCXXCondition(Second, SecondVar, ForLoc, true); + else { + Second = ParseExpression(); + if (!Second.isInvalid()) + Second = Actions.ActOnBooleanCondition(getCurScope(), ForLoc, + Second.get()); + } + SecondPartIsInvalid = Second.isInvalid(); + SecondPart = Actions.MakeFullExpr(Second.get()); + } + + if (Tok.isNot(tok::semi)) { + if (!SecondPartIsInvalid || SecondVar) + Diag(Tok, diag::err_expected_semi_for); + else + // Skip until semicolon or rparen, don't consume it. + SkipUntil(tok::r_paren, true, true); + } + + if (Tok.is(tok::semi)) { + ConsumeToken(); + } + + // Parse the third part of the for specifier. + if (Tok.isNot(tok::r_paren)) { // for (...;...;) + ExprResult Third = ParseExpression(); + ThirdPart = Actions.MakeFullExpr(Third.take()); + } + } + // Match the ')'. + T.consumeClose(); + + // We need to perform most of the semantic analysis for a C++0x for-range + // statememt before parsing the body, in order to be able to deduce the type + // of an auto-typed loop variable. + StmtResult ForRangeStmt; + if (ForRange) { + ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, T.getOpenLocation(), + FirstPart.take(), + ForRangeInit.ColonLoc, + ForRangeInit.RangeExpr.get(), + T.getCloseLocation()); + + + // Similarly, we need to do the semantic analysis for a for-range + // statement immediately in order to close over temporaries correctly. + } else if (ForEach) { + if (!Collection.isInvalid()) + Collection = + Actions.ActOnObjCForCollectionOperand(ForLoc, Collection.take()); + } + + // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if + // there is no compound stmt. C90 does not have this clause. We only do this + // if the body isn't a compound statement to avoid push/pop in common cases. + // + // C++ 6.5p2: + // The substatement in an iteration-statement implicitly defines a local scope + // which is entered and exited each time through the loop. + // + // See comments in ParseIfStatement for why we create a scope for + // for-init-statement/condition and a new scope for substatement in C++. + // + ParseScope InnerScope(this, Scope::DeclScope, + C99orCXXorObjC && Tok.isNot(tok::l_brace)); + + // Read the body statement. + StmtResult Body(ParseStatement(TrailingElseLoc)); + + // Pop the body scope if needed. + InnerScope.Exit(); + + // Leave the for-scope. + ForScope.Exit(); + + if (Body.isInvalid()) + return StmtError(); + + if (ForEach) + return Actions.ActOnObjCForCollectionStmt(ForLoc, T.getOpenLocation(), + FirstPart.take(), + Collection.take(), + T.getCloseLocation(), + Body.take()); + + if (ForRange) + return Actions.FinishCXXForRangeStmt(ForRangeStmt.take(), Body.take()); + + return Actions.ActOnForStmt(ForLoc, T.getOpenLocation(), FirstPart.take(), + SecondPart, SecondVar, ThirdPart, + T.getCloseLocation(), Body.take()); +} + +/// ParseGotoStatement +/// jump-statement: +/// 'goto' identifier ';' +/// [GNU] 'goto' '*' expression ';' +/// +/// Note: this lets the caller parse the end ';'. +/// +StmtResult Parser::ParseGotoStatement() { + assert(Tok.is(tok::kw_goto) && "Not a goto stmt!"); + SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'. + + StmtResult Res; + if (Tok.is(tok::identifier)) { + LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(), + Tok.getLocation()); + Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(), LD); + ConsumeToken(); + } else if (Tok.is(tok::star)) { + // GNU indirect goto extension. + Diag(Tok, diag::ext_gnu_indirect_goto); + SourceLocation StarLoc = ConsumeToken(); + ExprResult R(ParseExpression()); + if (R.isInvalid()) { // Skip to the semicolon, but don't consume it. + SkipUntil(tok::semi, false, true); + return StmtError(); + } + Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, R.take()); + } else { + Diag(Tok, diag::err_expected_ident); + return StmtError(); + } + + return move(Res); +} + +/// ParseContinueStatement +/// jump-statement: +/// 'continue' ';' +/// +/// Note: this lets the caller parse the end ';'. +/// +StmtResult Parser::ParseContinueStatement() { + SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'. + return Actions.ActOnContinueStmt(ContinueLoc, getCurScope()); +} + +/// ParseBreakStatement +/// jump-statement: +/// 'break' ';' +/// +/// Note: this lets the caller parse the end ';'. +/// +StmtResult Parser::ParseBreakStatement() { + SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. + return Actions.ActOnBreakStmt(BreakLoc, getCurScope()); +} + +/// ParseReturnStatement +/// jump-statement: +/// 'return' expression[opt] ';' +StmtResult Parser::ParseReturnStatement() { + assert(Tok.is(tok::kw_return) && "Not a return stmt!"); + SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'. + + ExprResult R; + if (Tok.isNot(tok::semi)) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteReturn(getCurScope()); + cutOffParsing(); + return StmtError(); + } + + if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus) { + R = ParseInitializer(); + if (R.isUsable()) + Diag(R.get()->getLocStart(), getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_generalized_initializer_lists : + diag::ext_generalized_initializer_lists) + << R.get()->getSourceRange(); + } else + R = ParseExpression(); + if (R.isInvalid()) { // Skip to the semicolon, but don't consume it. + SkipUntil(tok::semi, false, true); + return StmtError(); + } + } + return Actions.ActOnReturnStmt(ReturnLoc, R.take()); +} + +/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled, +/// this routine is called to collect the tokens for an MS asm statement. +StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { + SourceManager &SrcMgr = PP.getSourceManager(); + SourceLocation EndLoc = AsmLoc; + do { + bool InBraces = false; + unsigned short savedBraceCount = 0; + bool InAsmComment = false; + FileID FID; + unsigned LineNo = 0; + unsigned NumTokensRead = 0; + SourceLocation LBraceLoc; + + if (Tok.is(tok::l_brace)) { + // Braced inline asm: consume the opening brace. + InBraces = true; + savedBraceCount = BraceCount; + EndLoc = LBraceLoc = ConsumeBrace(); + ++NumTokensRead; + } else { + // Single-line inline asm; compute which line it is on. + std::pair ExpAsmLoc = + SrcMgr.getDecomposedExpansionLoc(EndLoc); + FID = ExpAsmLoc.first; + LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second); + } + + SourceLocation TokLoc = Tok.getLocation(); + do { + // If we hit EOF, we're done, period. + if (Tok.is(tok::eof)) + break; + // When we consume the closing brace, we're done. + if (InBraces && BraceCount == savedBraceCount) + break; + + if (!InAsmComment && Tok.is(tok::semi)) { + // A semicolon in an asm is the start of a comment. + InAsmComment = true; + if (InBraces) { + // Compute which line the comment is on. + std::pair ExpSemiLoc = + SrcMgr.getDecomposedExpansionLoc(TokLoc); + FID = ExpSemiLoc.first; + LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second); + } + } else if (!InBraces || InAsmComment) { + // If end-of-line is significant, check whether this token is on a + // new line. + std::pair ExpLoc = + SrcMgr.getDecomposedExpansionLoc(TokLoc); + if (ExpLoc.first != FID || + SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) { + // If this is a single-line __asm, we're done. + if (!InBraces) + break; + // We're no longer in a comment. + InAsmComment = false; + } else if (!InAsmComment && Tok.is(tok::r_brace)) { + // Single-line asm always ends when a closing brace is seen. + // FIXME: This is compatible with Apple gcc's -fasm-blocks; what + // does MSVC do here? + break; + } + } + + // Consume the next token; make sure we don't modify the brace count etc. + // if we are in a comment. + EndLoc = TokLoc; + if (InAsmComment) + PP.Lex(Tok); + else + ConsumeAnyToken(); + TokLoc = Tok.getLocation(); + ++NumTokensRead; + } while (1); + + if (InBraces && BraceCount != savedBraceCount) { + // __asm without closing brace (this can happen at EOF). + Diag(Tok, diag::err_expected_rbrace); + Diag(LBraceLoc, diag::note_matching) << "{"; + return StmtError(); + } else if (NumTokensRead == 0) { + // Empty __asm. + Diag(Tok, diag::err_expected_lbrace); + return StmtError(); + } + // Multiple adjacent asm's form together into a single asm statement + // in the AST. + if (!Tok.is(tok::kw_asm)) + break; + EndLoc = ConsumeToken(); + } while (1); + // FIXME: Need to actually grab the data and pass it on to Sema. Ideally, + // what Sema wants is a string of the entire inline asm, with one instruction + // per line and all the __asm keywords stripped out, and a way of mapping + // from any character of that string to its location in the original source + // code. I'm not entirely sure how to go about that, though. + Token t; + t.setKind(tok::string_literal); + t.setLiteralData("\"/*FIXME: not done*/\""); + t.clearFlag(Token::NeedsCleaning); + t.setLength(21); + ExprResult AsmString(Actions.ActOnStringLiteral(&t, 1)); + ExprVector Constraints(Actions); + ExprVector Exprs(Actions); + ExprVector Clobbers(Actions); + return Actions.ActOnAsmStmt(AsmLoc, true, true, 0, 0, 0, + move_arg(Constraints), move_arg(Exprs), + AsmString.take(), move_arg(Clobbers), + EndLoc, true); +} + +/// ParseAsmStatement - Parse a GNU extended asm statement. +/// asm-statement: +/// gnu-asm-statement +/// ms-asm-statement +/// +/// [GNU] gnu-asm-statement: +/// 'asm' type-qualifier[opt] '(' asm-argument ')' ';' +/// +/// [GNU] asm-argument: +/// asm-string-literal +/// asm-string-literal ':' asm-operands[opt] +/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] +/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] +/// ':' asm-clobbers +/// +/// [GNU] asm-clobbers: +/// asm-string-literal +/// asm-clobbers ',' asm-string-literal +/// +/// [MS] ms-asm-statement: +/// ms-asm-block +/// ms-asm-block ms-asm-statement +/// +/// [MS] ms-asm-block: +/// '__asm' ms-asm-line '\n' +/// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt] +/// +/// [MS] ms-asm-instruction-block +/// ms-asm-line +/// ms-asm-line '\n' ms-asm-instruction-block +/// +StmtResult Parser::ParseAsmStatement(bool &msAsm) { + assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); + SourceLocation AsmLoc = ConsumeToken(); + + if (getLangOpts().MicrosoftExt && Tok.isNot(tok::l_paren) && !isTypeQualifier()) { + msAsm = true; + return ParseMicrosoftAsmStatement(AsmLoc); + } + DeclSpec DS(AttrFactory); + SourceLocation Loc = Tok.getLocation(); + ParseTypeQualifierListOpt(DS, true, false); + + // GNU asms accept, but warn, about type-qualifiers other than volatile. + if (DS.getTypeQualifiers() & DeclSpec::TQ_const) + Diag(Loc, diag::w_asm_qualifier_ignored) << "const"; + if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) + Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict"; + + // Remember if this was a volatile asm. + bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << "asm"; + SkipUntil(tok::r_paren); + return StmtError(); + } + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + + ExprResult AsmString(ParseAsmStringLiteral()); + if (AsmString.isInvalid()) { + // Consume up to and including the closing paren. + T.skipToEnd(); + return StmtError(); + } + + SmallVector Names; + ExprVector Constraints(Actions); + ExprVector Exprs(Actions); + ExprVector Clobbers(Actions); + + if (Tok.is(tok::r_paren)) { + // We have a simple asm expression like 'asm("foo")'. + T.consumeClose(); + return Actions.ActOnAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, + /*NumOutputs*/ 0, /*NumInputs*/ 0, 0, + move_arg(Constraints), move_arg(Exprs), + AsmString.take(), move_arg(Clobbers), + T.getCloseLocation()); + } + + // Parse Outputs, if present. + bool AteExtraColon = false; + if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { + // In C++ mode, parse "::" like ": :". + AteExtraColon = Tok.is(tok::coloncolon); + ConsumeToken(); + + if (!AteExtraColon && + ParseAsmOperandsOpt(Names, Constraints, Exprs)) + return StmtError(); + } + + unsigned NumOutputs = Names.size(); + + // Parse Inputs, if present. + if (AteExtraColon || + Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { + // In C++ mode, parse "::" like ": :". + if (AteExtraColon) + AteExtraColon = false; + else { + AteExtraColon = Tok.is(tok::coloncolon); + ConsumeToken(); + } + + if (!AteExtraColon && + ParseAsmOperandsOpt(Names, Constraints, Exprs)) + return StmtError(); + } + + assert(Names.size() == Constraints.size() && + Constraints.size() == Exprs.size() && + "Input operand size mismatch!"); + + unsigned NumInputs = Names.size() - NumOutputs; + + // Parse the clobbers, if present. + if (AteExtraColon || Tok.is(tok::colon)) { + if (!AteExtraColon) + ConsumeToken(); + + // Parse the asm-string list for clobbers if present. + if (Tok.isNot(tok::r_paren)) { + while (1) { + ExprResult Clobber(ParseAsmStringLiteral()); + + if (Clobber.isInvalid()) + break; + + Clobbers.push_back(Clobber.release()); + + if (Tok.isNot(tok::comma)) break; + ConsumeToken(); + } + } + } + + T.consumeClose(); + return Actions.ActOnAsmStmt(AsmLoc, false, isVolatile, + NumOutputs, NumInputs, Names.data(), + move_arg(Constraints), move_arg(Exprs), + AsmString.take(), move_arg(Clobbers), + T.getCloseLocation()); +} + +/// ParseAsmOperands - Parse the asm-operands production as used by +/// asm-statement, assuming the leading ':' token was eaten. +/// +/// [GNU] asm-operands: +/// asm-operand +/// asm-operands ',' asm-operand +/// +/// [GNU] asm-operand: +/// asm-string-literal '(' expression ')' +/// '[' identifier ']' asm-string-literal '(' expression ')' +/// +// +// FIXME: Avoid unnecessary std::string trashing. +bool Parser::ParseAsmOperandsOpt(SmallVectorImpl &Names, + SmallVectorImpl &Constraints, + SmallVectorImpl &Exprs) { + // 'asm-operands' isn't present? + if (!isTokenStringLiteral() && Tok.isNot(tok::l_square)) + return false; + + while (1) { + // Read the [id] if present. + if (Tok.is(tok::l_square)) { + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::r_paren); + return true; + } + + IdentifierInfo *II = Tok.getIdentifierInfo(); + ConsumeToken(); + + Names.push_back(II); + T.consumeClose(); + } else + Names.push_back(0); + + ExprResult Constraint(ParseAsmStringLiteral()); + if (Constraint.isInvalid()) { + SkipUntil(tok::r_paren); + return true; + } + Constraints.push_back(Constraint.release()); + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << "asm operand"; + SkipUntil(tok::r_paren); + return true; + } + + // Read the parenthesized expression. + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + ExprResult Res(ParseExpression()); + T.consumeClose(); + if (Res.isInvalid()) { + SkipUntil(tok::r_paren); + return true; + } + Exprs.push_back(Res.release()); + // Eat the comma and continue parsing if it exists. + if (Tok.isNot(tok::comma)) return false; + ConsumeToken(); + } +} + +Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { + assert(Tok.is(tok::l_brace)); + SourceLocation LBraceLoc = Tok.getLocation(); + + if (SkipFunctionBodies && trySkippingFunctionBody()) { + BodyScope.Exit(); + return Actions.ActOnFinishFunctionBody(Decl, 0); + } + + PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc, + "parsing function body"); + + // Do not enter a scope for the brace, as the arguments are in the same scope + // (the function body) as the body itself. Instead, just read the statement + // list and put it into a CompoundStmt for safe keeping. + StmtResult FnBody(ParseCompoundStatementBody()); + + // If the function body could not be parsed, make a bogus compoundstmt. + if (FnBody.isInvalid()) { + Sema::CompoundScopeRAII CompoundScope(Actions); + FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, + MultiStmtArg(Actions), false); + } + + BodyScope.Exit(); + return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); +} + +/// ParseFunctionTryBlock - Parse a C++ function-try-block. +/// +/// function-try-block: +/// 'try' ctor-initializer[opt] compound-statement handler-seq +/// +Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { + assert(Tok.is(tok::kw_try) && "Expected 'try'"); + SourceLocation TryLoc = ConsumeToken(); + + PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, TryLoc, + "parsing function try block"); + + // Constructor initializer list? + if (Tok.is(tok::colon)) + ParseConstructorInitializer(Decl); + else + Actions.ActOnDefaultCtorInitializers(Decl); + + if (SkipFunctionBodies && trySkippingFunctionBody()) { + BodyScope.Exit(); + return Actions.ActOnFinishFunctionBody(Decl, 0); + } + + SourceLocation LBraceLoc = Tok.getLocation(); + StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc)); + // If we failed to parse the try-catch, we just give the function an empty + // compound statement as the body. + if (FnBody.isInvalid()) { + Sema::CompoundScopeRAII CompoundScope(Actions); + FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, + MultiStmtArg(Actions), false); + } + + BodyScope.Exit(); + return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); +} + +bool Parser::trySkippingFunctionBody() { + assert(Tok.is(tok::l_brace)); + assert(SkipFunctionBodies && + "Should only be called when SkipFunctionBodies is enabled"); + + // We're in code-completion mode. Skip parsing for all function bodies unless + // the body contains the code-completion point. + TentativeParsingAction PA(*this); + ConsumeBrace(); + if (SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false, + /*StopAtCodeCompletion=*/PP.isCodeCompletionEnabled())) { + PA.Commit(); + return true; + } + + PA.Revert(); + return false; +} + +/// ParseCXXTryBlock - Parse a C++ try-block. +/// +/// try-block: +/// 'try' compound-statement handler-seq +/// +StmtResult Parser::ParseCXXTryBlock() { + assert(Tok.is(tok::kw_try) && "Expected 'try'"); + + SourceLocation TryLoc = ConsumeToken(); + return ParseCXXTryBlockCommon(TryLoc); +} + +/// ParseCXXTryBlockCommon - Parse the common part of try-block and +/// function-try-block. +/// +/// try-block: +/// 'try' compound-statement handler-seq +/// +/// function-try-block: +/// 'try' ctor-initializer[opt] compound-statement handler-seq +/// +/// handler-seq: +/// handler handler-seq[opt] +/// +/// [Borland] try-block: +/// 'try' compound-statement seh-except-block +/// 'try' compound-statment seh-finally-block +/// +StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { + if (Tok.isNot(tok::l_brace)) + return StmtError(Diag(Tok, diag::err_expected_lbrace)); + // FIXME: Possible draft standard bug: attribute-specifier should be allowed? + + StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false, + Scope::DeclScope|Scope::TryScope)); + if (TryBlock.isInvalid()) + return move(TryBlock); + + // Borland allows SEH-handlers with 'try' + + if ((Tok.is(tok::identifier) && + Tok.getIdentifierInfo() == getSEHExceptKeyword()) || + Tok.is(tok::kw___finally)) { + // TODO: Factor into common return ParseSEHHandlerCommon(...) + StmtResult Handler; + if(Tok.getIdentifierInfo() == getSEHExceptKeyword()) { + SourceLocation Loc = ConsumeToken(); + Handler = ParseSEHExceptBlock(Loc); + } + else { + SourceLocation Loc = ConsumeToken(); + Handler = ParseSEHFinallyBlock(Loc); + } + if(Handler.isInvalid()) + return move(Handler); + + return Actions.ActOnSEHTryBlock(true /* IsCXXTry */, + TryLoc, + TryBlock.take(), + Handler.take()); + } + else { + StmtVector Handlers(Actions); + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + ProhibitAttributes(attrs); + + if (Tok.isNot(tok::kw_catch)) + return StmtError(Diag(Tok, diag::err_expected_catch)); + while (Tok.is(tok::kw_catch)) { + StmtResult Handler(ParseCXXCatchBlock()); + if (!Handler.isInvalid()) + Handlers.push_back(Handler.release()); + } + // Don't bother creating the full statement if we don't have any usable + // handlers. + if (Handlers.empty()) + return StmtError(); + + return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), move_arg(Handlers)); + } +} + +/// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard +/// +/// handler: +/// 'catch' '(' exception-declaration ')' compound-statement +/// +/// exception-declaration: +/// type-specifier-seq declarator +/// type-specifier-seq abstract-declarator +/// type-specifier-seq +/// '...' +/// +StmtResult Parser::ParseCXXCatchBlock() { + assert(Tok.is(tok::kw_catch) && "Expected 'catch'"); + + SourceLocation CatchLoc = ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen)) + return StmtError(); + + // C++ 3.3.2p3: + // The name in a catch exception-declaration is local to the handler and + // shall not be redeclared in the outermost block of the handler. + ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope); + + // exception-declaration is equivalent to '...' or a parameter-declaration + // without default arguments. + Decl *ExceptionDecl = 0; + if (Tok.isNot(tok::ellipsis)) { + DeclSpec DS(AttrFactory); + if (ParseCXXTypeSpecifierSeq(DS)) + return StmtError(); + Declarator ExDecl(DS, Declarator::CXXCatchContext); + ParseDeclarator(ExDecl); + ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl); + } else + ConsumeToken(); + + T.consumeClose(); + if (T.getCloseLocation().isInvalid()) + return StmtError(); + + if (Tok.isNot(tok::l_brace)) + return StmtError(Diag(Tok, diag::err_expected_lbrace)); + + // FIXME: Possible draft standard bug: attribute-specifier should be allowed? + StmtResult Block(ParseCompoundStatement()); + if (Block.isInvalid()) + return move(Block); + + return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.take()); +} + +void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { + IfExistsCondition Result; + if (ParseMicrosoftIfExistsCondition(Result)) + return; + + // Handle dependent statements by parsing the braces as a compound statement. + // This is not the same behavior as Visual C++, which don't treat this as a + // compound statement, but for Clang's type checking we can't have anything + // inside these braces escaping to the surrounding code. + if (Result.Behavior == IEB_Dependent) { + if (!Tok.is(tok::l_brace)) { + Diag(Tok, diag::err_expected_lbrace); + return; + } + + StmtResult Compound = ParseCompoundStatement(); + if (Compound.isInvalid()) + return; + + StmtResult DepResult = Actions.ActOnMSDependentExistsStmt(Result.KeywordLoc, + Result.IsIfExists, + Result.SS, + Result.Name, + Compound.get()); + if (DepResult.isUsable()) + Stmts.push_back(DepResult.get()); + return; + } + + BalancedDelimiterTracker Braces(*this, tok::l_brace); + if (Braces.consumeOpen()) { + Diag(Tok, diag::err_expected_lbrace); + return; + } + + switch (Result.Behavior) { + case IEB_Parse: + // Parse the statements below. + break; + + case IEB_Dependent: + llvm_unreachable("Dependent case handled above"); + + case IEB_Skip: + Braces.skipToEnd(); + return; + } + + // Condition is true, parse the statements. + while (Tok.isNot(tok::r_brace)) { + StmtResult R = ParseStatementOrDeclaration(Stmts, false); + if (R.isUsable()) + Stmts.push_back(R.release()); + } + Braces.consumeClose(); +} diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp new file mode 100644 index 0000000..5c3e2ba --- /dev/null +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -0,0 +1,1293 @@ +//===--- ParseTemplate.cpp - Template Parsing -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements parsing of C++ templates. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/Scope.h" +#include "RAIIObjectsForParser.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ASTConsumer.h" +using namespace clang; + +/// \brief Parse a template declaration, explicit instantiation, or +/// explicit specialization. +Decl * +Parser::ParseDeclarationStartingWithTemplate(unsigned Context, + SourceLocation &DeclEnd, + AccessSpecifier AS, + AttributeList *AccessAttrs) { + ObjCDeclContextSwitch ObjCDC(*this); + + if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) { + return ParseExplicitInstantiation(Context, + SourceLocation(), ConsumeToken(), + DeclEnd, AS); + } + return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS, + AccessAttrs); +} + +/// \brief RAII class that manages the template parameter depth. +namespace { + class TemplateParameterDepthCounter { + unsigned &Depth; + unsigned AddedLevels; + + public: + explicit TemplateParameterDepthCounter(unsigned &Depth) + : Depth(Depth), AddedLevels(0) { } + + ~TemplateParameterDepthCounter() { + Depth -= AddedLevels; + } + + void operator++() { + ++Depth; + ++AddedLevels; + } + + operator unsigned() const { return Depth; } + }; +} + +/// \brief Parse a template declaration or an explicit specialization. +/// +/// Template declarations include one or more template parameter lists +/// and either the function or class template declaration. Explicit +/// specializations contain one or more 'template < >' prefixes +/// followed by a (possibly templated) declaration. Since the +/// syntactic form of both features is nearly identical, we parse all +/// of the template headers together and let semantic analysis sort +/// the declarations from the explicit specializations. +/// +/// template-declaration: [C++ temp] +/// 'export'[opt] 'template' '<' template-parameter-list '>' declaration +/// +/// explicit-specialization: [ C++ temp.expl.spec] +/// 'template' '<' '>' declaration +Decl * +Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, + SourceLocation &DeclEnd, + AccessSpecifier AS, + AttributeList *AccessAttrs) { + assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) && + "Token does not start a template declaration."); + + // Enter template-parameter scope. + ParseScope TemplateParmScope(this, Scope::TemplateParamScope); + + // Tell the action that names should be checked in the context of + // the declaration to come. + ParsingDeclRAIIObject ParsingTemplateParams(*this); + + // Parse multiple levels of template headers within this template + // parameter scope, e.g., + // + // template + // template + // class A::B { ... }; + // + // We parse multiple levels non-recursively so that we can build a + // single data structure containing all of the template parameter + // lists to easily differentiate between the case above and: + // + // template + // class A { + // template class B; + // }; + // + // In the first case, the action for declaring A::B receives + // both template parameter lists. In the second case, the action for + // defining A::B receives just the inner template parameter list + // (and retrieves the outer template parameter list from its + // context). + bool isSpecialization = true; + bool LastParamListWasEmpty = false; + TemplateParameterLists ParamLists; + TemplateParameterDepthCounter Depth(TemplateParameterDepth); + do { + // Consume the 'export', if any. + SourceLocation ExportLoc; + if (Tok.is(tok::kw_export)) { + ExportLoc = ConsumeToken(); + } + + // Consume the 'template', which should be here. + SourceLocation TemplateLoc; + if (Tok.is(tok::kw_template)) { + TemplateLoc = ConsumeToken(); + } else { + Diag(Tok.getLocation(), diag::err_expected_template); + return 0; + } + + // Parse the '<' template-parameter-list '>' + SourceLocation LAngleLoc, RAngleLoc; + SmallVector TemplateParams; + if (ParseTemplateParameters(Depth, TemplateParams, LAngleLoc, + RAngleLoc)) { + // Skip until the semi-colon or a }. + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return 0; + } + + ParamLists.push_back( + Actions.ActOnTemplateParameterList(Depth, ExportLoc, + TemplateLoc, LAngleLoc, + TemplateParams.data(), + TemplateParams.size(), RAngleLoc)); + + if (!TemplateParams.empty()) { + isSpecialization = false; + ++Depth; + } else { + LastParamListWasEmpty = true; + } + } while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template)); + + // Parse the actual template declaration. + return ParseSingleDeclarationAfterTemplate(Context, + ParsedTemplateInfo(&ParamLists, + isSpecialization, + LastParamListWasEmpty), + ParsingTemplateParams, + DeclEnd, AS, AccessAttrs); +} + +/// \brief Parse a single declaration that declares a template, +/// template specialization, or explicit instantiation of a template. +/// +/// \param TemplateParams if non-NULL, the template parameter lists +/// that preceded this declaration. In this case, the declaration is a +/// template declaration, out-of-line definition of a template, or an +/// explicit template specialization. When NULL, the declaration is an +/// explicit template instantiation. +/// +/// \param TemplateLoc when TemplateParams is NULL, the location of +/// the 'template' keyword that indicates that we have an explicit +/// template instantiation. +/// +/// \param DeclEnd will receive the source location of the last token +/// within this declaration. +/// +/// \param AS the access specifier associated with this +/// declaration. Will be AS_none for namespace-scope declarations. +/// +/// \returns the new declaration. +Decl * +Parser::ParseSingleDeclarationAfterTemplate( + unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + ParsingDeclRAIIObject &DiagsFromTParams, + SourceLocation &DeclEnd, + AccessSpecifier AS, + AttributeList *AccessAttrs) { + assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && + "Template information required"); + + if (Context == Declarator::MemberContext) { + // We are parsing a member template. + ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo, + &DiagsFromTParams); + return 0; + } + + ParsedAttributesWithRange prefixAttrs(AttrFactory); + MaybeParseCXX0XAttributes(prefixAttrs); + + if (Tok.is(tok::kw_using)) + return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, + prefixAttrs); + + // Parse the declaration specifiers, stealing the accumulated + // diagnostics from the template parameters. + ParsingDeclSpec DS(*this, &DiagsFromTParams); + + DS.takeAttributesFrom(prefixAttrs); + + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, + getDeclSpecContextFromDeclaratorContext(Context)); + + if (Tok.is(tok::semi)) { + DeclEnd = ConsumeToken(); + Decl *Decl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); + DS.complete(Decl); + return Decl; + } + + // Parse the declarator. + ParsingDeclarator DeclaratorInfo(*this, DS, (Declarator::TheContext)Context); + ParseDeclarator(DeclaratorInfo); + // Error parsing the declarator? + if (!DeclaratorInfo.hasName()) { + // If so, skip until the semi-colon or a }. + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return 0; + } + + LateParsedAttrList LateParsedAttrs; + if (DeclaratorInfo.isFunctionDeclarator()) + MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); + + // If we have a declaration or declarator list, handle it. + if (isDeclarationAfterDeclarator()) { + // Parse this declaration. + Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo, + TemplateInfo); + + if (Tok.is(tok::comma)) { + Diag(Tok, diag::err_multiple_template_declarators) + << (int)TemplateInfo.Kind; + SkipUntil(tok::semi, true, false); + return ThisDecl; + } + + // Eat the semi colon after the declaration. + ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); + if (LateParsedAttrs.size() > 0) + ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false); + DeclaratorInfo.complete(ThisDecl); + return ThisDecl; + } + + if (DeclaratorInfo.isFunctionDeclarator() && + isStartOfFunctionDefinition(DeclaratorInfo)) { + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { + // Recover by ignoring the 'typedef'. This was probably supposed to be + // the 'typename' keyword, which we should have already suggested adding + // if it's appropriate. + Diag(DS.getStorageClassSpecLoc(), diag::err_function_declared_typedef) + << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); + DS.ClearStorageClassSpecs(); + } + return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo, + &LateParsedAttrs); + } + + if (DeclaratorInfo.isFunctionDeclarator()) + Diag(Tok, diag::err_expected_fn_body); + else + Diag(Tok, diag::err_invalid_token_after_toplevel_declarator); + SkipUntil(tok::semi); + return 0; +} + +/// ParseTemplateParameters - Parses a template-parameter-list enclosed in +/// angle brackets. Depth is the depth of this template-parameter-list, which +/// is the number of template headers directly enclosing this template header. +/// TemplateParams is the current list of template parameters we're building. +/// The template parameter we parse will be added to this list. LAngleLoc and +/// RAngleLoc will receive the positions of the '<' and '>', respectively, +/// that enclose this template parameter list. +/// +/// \returns true if an error occurred, false otherwise. +bool Parser::ParseTemplateParameters(unsigned Depth, + SmallVectorImpl &TemplateParams, + SourceLocation &LAngleLoc, + SourceLocation &RAngleLoc) { + // Get the template parameter list. + if (!Tok.is(tok::less)) { + Diag(Tok.getLocation(), diag::err_expected_less_after) << "template"; + return true; + } + LAngleLoc = ConsumeToken(); + + // Try to parse the template parameter list. + bool Failed = false; + if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater)) + Failed = ParseTemplateParameterList(Depth, TemplateParams); + + if (Tok.is(tok::greatergreater)) { + Tok.setKind(tok::greater); + RAngleLoc = Tok.getLocation(); + Tok.setLocation(Tok.getLocation().getLocWithOffset(1)); + } else if (Tok.is(tok::greater)) + RAngleLoc = ConsumeToken(); + else if (Failed) { + Diag(Tok.getLocation(), diag::err_expected_greater); + return true; + } + return false; +} + +/// ParseTemplateParameterList - Parse a template parameter list. If +/// the parsing fails badly (i.e., closing bracket was left out), this +/// will try to put the token stream in a reasonable position (closing +/// a statement, etc.) and return false. +/// +/// template-parameter-list: [C++ temp] +/// template-parameter +/// template-parameter-list ',' template-parameter +bool +Parser::ParseTemplateParameterList(unsigned Depth, + SmallVectorImpl &TemplateParams) { + while (1) { + if (Decl *TmpParam + = ParseTemplateParameter(Depth, TemplateParams.size())) { + TemplateParams.push_back(TmpParam); + } else { + // If we failed to parse a template parameter, skip until we find + // a comma or closing brace. + SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true); + } + + // Did we find a comma or the end of the template parmeter list? + if (Tok.is(tok::comma)) { + ConsumeToken(); + } else if (Tok.is(tok::greater) || Tok.is(tok::greatergreater)) { + // Don't consume this... that's done by template parser. + break; + } else { + // Somebody probably forgot to close the template. Skip ahead and + // try to get out of the expression. This error is currently + // subsumed by whatever goes on in ParseTemplateParameter. + Diag(Tok.getLocation(), diag::err_expected_comma_greater); + SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true); + return false; + } + } + return true; +} + +/// \brief Determine whether the parser is at the start of a template +/// type parameter. +bool Parser::isStartOfTemplateTypeParameter() { + if (Tok.is(tok::kw_class)) { + // "class" may be the start of an elaborated-type-specifier or a + // type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter. + switch (NextToken().getKind()) { + case tok::equal: + case tok::comma: + case tok::greater: + case tok::greatergreater: + case tok::ellipsis: + return true; + + case tok::identifier: + // This may be either a type-parameter or an elaborated-type-specifier. + // We have to look further. + break; + + default: + return false; + } + + switch (GetLookAheadToken(2).getKind()) { + case tok::equal: + case tok::comma: + case tok::greater: + case tok::greatergreater: + return true; + + default: + return false; + } + } + + if (Tok.isNot(tok::kw_typename)) + return false; + + // C++ [temp.param]p2: + // There is no semantic difference between class and typename in a + // template-parameter. typename followed by an unqualified-id + // names a template type parameter. typename followed by a + // qualified-id denotes the type in a non-type + // parameter-declaration. + Token Next = NextToken(); + + // If we have an identifier, skip over it. + if (Next.getKind() == tok::identifier) + Next = GetLookAheadToken(2); + + switch (Next.getKind()) { + case tok::equal: + case tok::comma: + case tok::greater: + case tok::greatergreater: + case tok::ellipsis: + return true; + + default: + return false; + } +} + +/// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]). +/// +/// template-parameter: [C++ temp.param] +/// type-parameter +/// parameter-declaration +/// +/// type-parameter: (see below) +/// 'class' ...[opt] identifier[opt] +/// 'class' identifier[opt] '=' type-id +/// 'typename' ...[opt] identifier[opt] +/// 'typename' identifier[opt] '=' type-id +/// 'template' '<' template-parameter-list '>' +/// 'class' ...[opt] identifier[opt] +/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] +/// = id-expression +Decl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { + if (isStartOfTemplateTypeParameter()) + return ParseTypeParameter(Depth, Position); + + if (Tok.is(tok::kw_template)) + return ParseTemplateTemplateParameter(Depth, Position); + + // If it's none of the above, then it must be a parameter declaration. + // NOTE: This will pick up errors in the closure of the template parameter + // list (e.g., template < ; Check here to implement >> style closures. + return ParseNonTypeTemplateParameter(Depth, Position); +} + +/// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]). +/// Other kinds of template parameters are parsed in +/// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter. +/// +/// type-parameter: [C++ temp.param] +/// 'class' ...[opt][C++0x] identifier[opt] +/// 'class' identifier[opt] '=' type-id +/// 'typename' ...[opt][C++0x] identifier[opt] +/// 'typename' identifier[opt] '=' type-id +Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { + assert((Tok.is(tok::kw_class) || Tok.is(tok::kw_typename)) && + "A type-parameter starts with 'class' or 'typename'"); + + // Consume the 'class' or 'typename' keyword. + bool TypenameKeyword = Tok.is(tok::kw_typename); + SourceLocation KeyLoc = ConsumeToken(); + + // Grab the ellipsis (if given). + bool Ellipsis = false; + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) { + Ellipsis = true; + EllipsisLoc = ConsumeToken(); + + Diag(EllipsisLoc, + getLangOpts().CPlusPlus0x + ? diag::warn_cxx98_compat_variadic_templates + : diag::ext_variadic_templates); + } + + // Grab the template parameter name (if given) + SourceLocation NameLoc; + IdentifierInfo* ParamName = 0; + if (Tok.is(tok::identifier)) { + ParamName = Tok.getIdentifierInfo(); + NameLoc = ConsumeToken(); + } else if (Tok.is(tok::equal) || Tok.is(tok::comma) || + Tok.is(tok::greater) || Tok.is(tok::greatergreater)) { + // Unnamed template parameter. Don't have to do anything here, just + // don't consume this token. + } else { + Diag(Tok.getLocation(), diag::err_expected_ident); + return 0; + } + + // Grab a default argument (if available). + // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before + // we introduce the type parameter into the local scope. + SourceLocation EqualLoc; + ParsedType DefaultArg; + if (Tok.is(tok::equal)) { + EqualLoc = ConsumeToken(); + DefaultArg = ParseTypeName(/*Range=*/0, + Declarator::TemplateTypeArgContext).get(); + } + + return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, Ellipsis, + EllipsisLoc, KeyLoc, ParamName, NameLoc, + Depth, Position, EqualLoc, DefaultArg); +} + +/// ParseTemplateTemplateParameter - Handle the parsing of template +/// template parameters. +/// +/// type-parameter: [C++ temp.param] +/// 'template' '<' template-parameter-list '>' 'class' +/// ...[opt] identifier[opt] +/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] +/// = id-expression +Decl * +Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { + assert(Tok.is(tok::kw_template) && "Expected 'template' keyword"); + + // Handle the template <...> part. + SourceLocation TemplateLoc = ConsumeToken(); + SmallVector TemplateParams; + SourceLocation LAngleLoc, RAngleLoc; + { + ParseScope TemplateParmScope(this, Scope::TemplateParamScope); + if (ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc, + RAngleLoc)) { + return 0; + } + } + + // Generate a meaningful error if the user forgot to put class before the + // identifier, comma, or greater. Provide a fixit if the identifier, comma, + // or greater appear immediately or after 'typename' or 'struct'. In the + // latter case, replace the keyword with 'class'. + if (!Tok.is(tok::kw_class)) { + bool Replace = Tok.is(tok::kw_typename) || Tok.is(tok::kw_struct); + const Token& Next = Replace ? NextToken() : Tok; + if (Next.is(tok::identifier) || Next.is(tok::comma) || + Next.is(tok::greater) || Next.is(tok::greatergreater) || + Next.is(tok::ellipsis)) + Diag(Tok.getLocation(), diag::err_class_on_template_template_param) + << (Replace ? FixItHint::CreateReplacement(Tok.getLocation(), "class") + : FixItHint::CreateInsertion(Tok.getLocation(), "class ")); + else + Diag(Tok.getLocation(), diag::err_class_on_template_template_param); + + if (Replace) + ConsumeToken(); + } else + ConsumeToken(); + + // Parse the ellipsis, if given. + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) { + EllipsisLoc = ConsumeToken(); + + Diag(EllipsisLoc, + getLangOpts().CPlusPlus0x + ? diag::warn_cxx98_compat_variadic_templates + : diag::ext_variadic_templates); + } + + // Get the identifier, if given. + SourceLocation NameLoc; + IdentifierInfo* ParamName = 0; + if (Tok.is(tok::identifier)) { + ParamName = Tok.getIdentifierInfo(); + NameLoc = ConsumeToken(); + } else if (Tok.is(tok::equal) || Tok.is(tok::comma) || + Tok.is(tok::greater) || Tok.is(tok::greatergreater)) { + // Unnamed template parameter. Don't have to do anything here, just + // don't consume this token. + } else { + Diag(Tok.getLocation(), diag::err_expected_ident); + return 0; + } + + TemplateParameterList *ParamList = + Actions.ActOnTemplateParameterList(Depth, SourceLocation(), + TemplateLoc, LAngleLoc, + TemplateParams.data(), + TemplateParams.size(), + RAngleLoc); + + // Grab a default argument (if available). + // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before + // we introduce the template parameter into the local scope. + SourceLocation EqualLoc; + ParsedTemplateArgument DefaultArg; + if (Tok.is(tok::equal)) { + EqualLoc = ConsumeToken(); + DefaultArg = ParseTemplateTemplateArgument(); + if (DefaultArg.isInvalid()) { + Diag(Tok.getLocation(), + diag::err_default_template_template_parameter_not_template); + SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true); + } + } + + return Actions.ActOnTemplateTemplateParameter(getCurScope(), TemplateLoc, + ParamList, EllipsisLoc, + ParamName, NameLoc, Depth, + Position, EqualLoc, DefaultArg); +} + +/// ParseNonTypeTemplateParameter - Handle the parsing of non-type +/// template parameters (e.g., in "template class array;"). +/// +/// template-parameter: +/// ... +/// parameter-declaration +Decl * +Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { + // Parse the declaration-specifiers (i.e., the type). + // FIXME: The type should probably be restricted in some way... Not all + // declarators (parts of declarators?) are accepted for parameters. + DeclSpec DS(AttrFactory); + ParseDeclarationSpecifiers(DS); + + // Parse this as a typename. + Declarator ParamDecl(DS, Declarator::TemplateParamContext); + ParseDeclarator(ParamDecl); + if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { + Diag(Tok.getLocation(), diag::err_expected_template_parameter); + return 0; + } + + // If there is a default value, parse it. + // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before + // we introduce the template parameter into the local scope. + SourceLocation EqualLoc; + ExprResult DefaultArg; + if (Tok.is(tok::equal)) { + EqualLoc = ConsumeToken(); + + // C++ [temp.param]p15: + // When parsing a default template-argument for a non-type + // template-parameter, the first non-nested > is taken as the + // end of the template-parameter-list rather than a greater-than + // operator. + GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + + DefaultArg = ParseAssignmentExpression(); + if (DefaultArg.isInvalid()) + SkipUntil(tok::comma, tok::greater, true, true); + } + + // Create the parameter. + return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl, + Depth, Position, EqualLoc, + DefaultArg.take()); +} + +/// \brief Parses a template-id that after the template name has +/// already been parsed. +/// +/// This routine takes care of parsing the enclosed template argument +/// list ('<' template-parameter-list [opt] '>') and placing the +/// results into a form that can be transferred to semantic analysis. +/// +/// \param Template the template declaration produced by isTemplateName +/// +/// \param TemplateNameLoc the source location of the template name +/// +/// \param SS if non-NULL, the nested-name-specifier preceding the +/// template name. +/// +/// \param ConsumeLastToken if true, then we will consume the last +/// token that forms the template-id. Otherwise, we will leave the +/// last token in the stream (e.g., so that it can be replaced with an +/// annotation token). +bool +Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, + SourceLocation TemplateNameLoc, + const CXXScopeSpec &SS, + bool ConsumeLastToken, + SourceLocation &LAngleLoc, + TemplateArgList &TemplateArgs, + SourceLocation &RAngleLoc) { + assert(Tok.is(tok::less) && "Must have already parsed the template-name"); + + // Consume the '<'. + LAngleLoc = ConsumeToken(); + + // Parse the optional template-argument-list. + bool Invalid = false; + { + GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); + if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater)) + Invalid = ParseTemplateArgumentList(TemplateArgs); + + if (Invalid) { + // Try to find the closing '>'. + SkipUntil(tok::greater, true, !ConsumeLastToken); + + return true; + } + } + + if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater)) { + Diag(Tok.getLocation(), diag::err_expected_greater); + return true; + } + + // Determine the location of the '>' or '>>'. Only consume this + // token if the caller asked us to. + RAngleLoc = Tok.getLocation(); + + if (Tok.is(tok::greatergreater)) { + const char *ReplaceStr = "> >"; + if (NextToken().is(tok::greater) || NextToken().is(tok::greatergreater)) + ReplaceStr = "> > "; + + Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_two_right_angle_brackets : + diag::err_two_right_angle_brackets_need_space) + << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), + ReplaceStr); + + Tok.setKind(tok::greater); + if (!ConsumeLastToken) { + // Since we're not supposed to consume the '>>' token, we need + // to insert a second '>' token after the first. + PP.EnterToken(Tok); + } + } else if (ConsumeLastToken) + ConsumeToken(); + + return false; +} + +/// \brief Replace the tokens that form a simple-template-id with an +/// annotation token containing the complete template-id. +/// +/// The first token in the stream must be the name of a template that +/// is followed by a '<'. This routine will parse the complete +/// simple-template-id and replace the tokens with a single annotation +/// token with one of two different kinds: if the template-id names a +/// type (and \p AllowTypeAnnotation is true), the annotation token is +/// a type annotation that includes the optional nested-name-specifier +/// (\p SS). Otherwise, the annotation token is a template-id +/// annotation that does not include the optional +/// nested-name-specifier. +/// +/// \param Template the declaration of the template named by the first +/// token (an identifier), as returned from \c Action::isTemplateName(). +/// +/// \param TemplateNameKind the kind of template that \p Template +/// refers to, as returned from \c Action::isTemplateName(). +/// +/// \param SS if non-NULL, the nested-name-specifier that precedes +/// this template name. +/// +/// \param TemplateKWLoc if valid, specifies that this template-id +/// annotation was preceded by the 'template' keyword and gives the +/// location of that keyword. If invalid (the default), then this +/// template-id was not preceded by a 'template' keyword. +/// +/// \param AllowTypeAnnotation if true (the default), then a +/// simple-template-id that refers to a class template, template +/// template parameter, or other template that produces a type will be +/// replaced with a type annotation token. Otherwise, the +/// simple-template-id is always replaced with a template-id +/// annotation token. +/// +/// If an unrecoverable parse error occurs and no annotation token can be +/// formed, this function returns true. +/// +bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + UnqualifiedId &TemplateName, + bool AllowTypeAnnotation) { + assert(getLangOpts().CPlusPlus && "Can only annotate template-ids in C++"); + assert(Template && Tok.is(tok::less) && + "Parser isn't at the beginning of a template-id"); + + // Consume the template-name. + SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin(); + + // Parse the enclosed template argument list. + SourceLocation LAngleLoc, RAngleLoc; + TemplateArgList TemplateArgs; + bool Invalid = ParseTemplateIdAfterTemplateName(Template, + TemplateNameLoc, + SS, false, LAngleLoc, + TemplateArgs, + RAngleLoc); + + if (Invalid) { + // If we failed to parse the template ID but skipped ahead to a >, we're not + // going to be able to form a token annotation. Eat the '>' if present. + if (Tok.is(tok::greater)) + ConsumeToken(); + return true; + } + + ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), + TemplateArgs.size()); + + // Build the annotation token. + if (TNK == TNK_Type_template && AllowTypeAnnotation) { + TypeResult Type + = Actions.ActOnTemplateIdType(SS, TemplateKWLoc, + Template, TemplateNameLoc, + LAngleLoc, TemplateArgsPtr, RAngleLoc); + if (Type.isInvalid()) { + // If we failed to parse the template ID but skipped ahead to a >, we're not + // going to be able to form a token annotation. Eat the '>' if present. + if (Tok.is(tok::greater)) + ConsumeToken(); + return true; + } + + Tok.setKind(tok::annot_typename); + setTypeAnnotation(Tok, Type.get()); + if (SS.isNotEmpty()) + Tok.setLocation(SS.getBeginLoc()); + else if (TemplateKWLoc.isValid()) + Tok.setLocation(TemplateKWLoc); + else + Tok.setLocation(TemplateNameLoc); + } else { + // Build a template-id annotation token that can be processed + // later. + Tok.setKind(tok::annot_template_id); + TemplateIdAnnotation *TemplateId + = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds); + TemplateId->TemplateNameLoc = TemplateNameLoc; + if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) { + TemplateId->Name = TemplateName.Identifier; + TemplateId->Operator = OO_None; + } else { + TemplateId->Name = 0; + TemplateId->Operator = TemplateName.OperatorFunctionId.Operator; + } + TemplateId->SS = SS; + TemplateId->TemplateKWLoc = TemplateKWLoc; + TemplateId->Template = Template; + TemplateId->Kind = TNK; + TemplateId->LAngleLoc = LAngleLoc; + TemplateId->RAngleLoc = RAngleLoc; + ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); + for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) + Args[Arg] = ParsedTemplateArgument(TemplateArgs[Arg]); + Tok.setAnnotationValue(TemplateId); + if (TemplateKWLoc.isValid()) + Tok.setLocation(TemplateKWLoc); + else + Tok.setLocation(TemplateNameLoc); + + TemplateArgsPtr.release(); + } + + // Common fields for the annotation token + Tok.setAnnotationEndLoc(RAngleLoc); + + // In case the tokens were cached, have Preprocessor replace them with the + // annotation token. + PP.AnnotateCachedTokens(Tok); + return false; +} + +/// \brief Replaces a template-id annotation token with a type +/// annotation token. +/// +/// If there was a failure when forming the type from the template-id, +/// a type annotation token will still be created, but will have a +/// NULL type pointer to signify an error. +void Parser::AnnotateTemplateIdTokenAsType() { + assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens"); + + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + assert((TemplateId->Kind == TNK_Type_template || + TemplateId->Kind == TNK_Dependent_template_name) && + "Only works for type and dependent templates"); + + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + + TypeResult Type + = Actions.ActOnTemplateIdType(TemplateId->SS, + TemplateId->TemplateKWLoc, + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); + // Create the new "type" annotation token. + Tok.setKind(tok::annot_typename); + setTypeAnnotation(Tok, Type.isInvalid() ? ParsedType() : Type.get()); + if (TemplateId->SS.isNotEmpty()) // it was a C++ qualified type name. + Tok.setLocation(TemplateId->SS.getBeginLoc()); + // End location stays the same + + // Replace the template-id annotation token, and possible the scope-specifier + // that precedes it, with the typename annotation token. + PP.AnnotateCachedTokens(Tok); +} + +/// \brief Determine whether the given token can end a template argument. +static bool isEndOfTemplateArgument(Token Tok) { + return Tok.is(tok::comma) || Tok.is(tok::greater) || + Tok.is(tok::greatergreater); +} + +/// \brief Parse a C++ template template argument. +ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { + if (!Tok.is(tok::identifier) && !Tok.is(tok::coloncolon) && + !Tok.is(tok::annot_cxxscope)) + return ParsedTemplateArgument(); + + // C++0x [temp.arg.template]p1: + // A template-argument for a template template-parameter shall be the name + // of a class template or an alias template, expressed as id-expression. + // + // We parse an id-expression that refers to a class template or alias + // template. The grammar we parse is: + // + // nested-name-specifier[opt] template[opt] identifier ...[opt] + // + // followed by a token that terminates a template argument, such as ',', + // '>', or (in some cases) '>>'. + CXXScopeSpec SS; // nested-name-specifier, if present + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*EnteringContext=*/false); + + ParsedTemplateArgument Result; + SourceLocation EllipsisLoc; + if (SS.isSet() && Tok.is(tok::kw_template)) { + // Parse the optional 'template' keyword following the + // nested-name-specifier. + SourceLocation TemplateKWLoc = ConsumeToken(); + + if (Tok.is(tok::identifier)) { + // We appear to have a dependent template name. + UnqualifiedId Name; + Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); // the identifier + + // Parse the ellipsis. + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + + // If the next token signals the end of a template argument, + // then we have a dependent template name that could be a template + // template argument. + TemplateTy Template; + if (isEndOfTemplateArgument(Tok) && + Actions.ActOnDependentTemplateName(getCurScope(), + SS, TemplateKWLoc, Name, + /*ObjectType=*/ ParsedType(), + /*EnteringContext=*/false, + Template)) + Result = ParsedTemplateArgument(SS, Template, Name.StartLocation); + } + } else if (Tok.is(tok::identifier)) { + // We may have a (non-dependent) template name. + TemplateTy Template; + UnqualifiedId Name; + Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); // the identifier + + // Parse the ellipsis. + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + + if (isEndOfTemplateArgument(Tok)) { + bool MemberOfUnknownSpecialization; + TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, + Name, + /*ObjectType=*/ ParsedType(), + /*EnteringContext=*/false, + Template, + MemberOfUnknownSpecialization); + if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) { + // We have an id-expression that refers to a class template or + // (C++0x) alias template. + Result = ParsedTemplateArgument(SS, Template, Name.StartLocation); + } + } + } + + // If this is a pack expansion, build it as such. + if (EllipsisLoc.isValid() && !Result.isInvalid()) + Result = Actions.ActOnPackExpansion(Result, EllipsisLoc); + + return Result; +} + +/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]). +/// +/// template-argument: [C++ 14.2] +/// constant-expression +/// type-id +/// id-expression +ParsedTemplateArgument Parser::ParseTemplateArgument() { + // C++ [temp.arg]p2: + // In a template-argument, an ambiguity between a type-id and an + // expression is resolved to a type-id, regardless of the form of + // the corresponding template-parameter. + // + // Therefore, we initially try to parse a type-id. + if (isCXXTypeId(TypeIdAsTemplateArgument)) { + SourceLocation Loc = Tok.getLocation(); + TypeResult TypeArg = ParseTypeName(/*Range=*/0, + Declarator::TemplateTypeArgContext); + if (TypeArg.isInvalid()) + return ParsedTemplateArgument(); + + return ParsedTemplateArgument(ParsedTemplateArgument::Type, + TypeArg.get().getAsOpaquePtr(), + Loc); + } + + // Try to parse a template template argument. + { + TentativeParsingAction TPA(*this); + + ParsedTemplateArgument TemplateTemplateArgument + = ParseTemplateTemplateArgument(); + if (!TemplateTemplateArgument.isInvalid()) { + TPA.Commit(); + return TemplateTemplateArgument; + } + + // Revert this tentative parse to parse a non-type template argument. + TPA.Revert(); + } + + // Parse a non-type template argument. + SourceLocation Loc = Tok.getLocation(); + ExprResult ExprArg = ParseConstantExpression(MaybeTypeCast); + if (ExprArg.isInvalid() || !ExprArg.get()) + return ParsedTemplateArgument(); + + return ParsedTemplateArgument(ParsedTemplateArgument::NonType, + ExprArg.release(), Loc); +} + +/// \brief Determine whether the current tokens can only be parsed as a +/// template argument list (starting with the '<') and never as a '<' +/// expression. +bool Parser::IsTemplateArgumentList(unsigned Skip) { + struct AlwaysRevertAction : TentativeParsingAction { + AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { } + ~AlwaysRevertAction() { Revert(); } + } Tentative(*this); + + while (Skip) { + ConsumeToken(); + --Skip; + } + + // '<' + if (!Tok.is(tok::less)) + return false; + ConsumeToken(); + + // An empty template argument list. + if (Tok.is(tok::greater)) + return true; + + // See whether we have declaration specifiers, which indicate a type. + while (isCXXDeclarationSpecifier() == TPResult::True()) + ConsumeToken(); + + // If we have a '>' or a ',' then this is a template argument list. + return Tok.is(tok::greater) || Tok.is(tok::comma); +} + +/// ParseTemplateArgumentList - Parse a C++ template-argument-list +/// (C++ [temp.names]). Returns true if there was an error. +/// +/// template-argument-list: [C++ 14.2] +/// template-argument +/// template-argument-list ',' template-argument +bool +Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { + while (true) { + ParsedTemplateArgument Arg = ParseTemplateArgument(); + if (Tok.is(tok::ellipsis)) { + SourceLocation EllipsisLoc = ConsumeToken(); + Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc); + } + + if (Arg.isInvalid()) { + SkipUntil(tok::comma, tok::greater, true, true); + return true; + } + + // Save this template argument. + TemplateArgs.push_back(Arg); + + // If the next token is a comma, consume it and keep reading + // arguments. + if (Tok.isNot(tok::comma)) break; + + // Consume the comma. + ConsumeToken(); + } + + return false; +} + +/// \brief Parse a C++ explicit template instantiation +/// (C++ [temp.explicit]). +/// +/// explicit-instantiation: +/// 'extern' [opt] 'template' declaration +/// +/// Note that the 'extern' is a GNU extension and C++0x feature. +Decl *Parser::ParseExplicitInstantiation(unsigned Context, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + SourceLocation &DeclEnd, + AccessSpecifier AS) { + // This isn't really required here. + ParsingDeclRAIIObject ParsingTemplateParams(*this); + + return ParseSingleDeclarationAfterTemplate(Context, + ParsedTemplateInfo(ExternLoc, + TemplateLoc), + ParsingTemplateParams, + DeclEnd, AS); +} + +SourceRange Parser::ParsedTemplateInfo::getSourceRange() const { + if (TemplateParams) + return getTemplateParamsRange(TemplateParams->data(), + TemplateParams->size()); + + SourceRange R(TemplateLoc); + if (ExternLoc.isValid()) + R.setBegin(ExternLoc); + return R; +} + +void Parser::LateTemplateParserCallback(void *P, const FunctionDecl *FD) { + ((Parser*)P)->LateTemplateParser(FD); +} + + +void Parser::LateTemplateParser(const FunctionDecl *FD) { + LateParsedTemplatedFunction *LPT = LateParsedTemplateMap[FD]; + if (LPT) { + ParseLateTemplatedFuncDef(*LPT); + return; + } + + llvm_unreachable("Late templated function without associated lexed tokens"); +} + +/// \brief Late parse a C++ function template in Microsoft mode. +void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { + if(!LMT.D) + return; + + // Get the FunctionDecl. + FunctionDecl *FD = 0; + if (FunctionTemplateDecl *FunTmpl = dyn_cast(LMT.D)) + FD = FunTmpl->getTemplatedDecl(); + else + FD = cast(LMT.D); + + // To restore the context after late parsing. + Sema::ContextRAII GlobalSavedContext(Actions, Actions.CurContext); + + SmallVector TemplateParamScopeStack; + DeclaratorDecl* Declarator = dyn_cast(FD); + if (Declarator && Declarator->getNumTemplateParameterLists() != 0) { + TemplateParamScopeStack.push_back(new ParseScope(this, Scope::TemplateParamScope)); + Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator); + Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); + } else { + // Get the list of DeclContext to reenter. + SmallVector DeclContextToReenter; + DeclContext *DD = FD->getLexicalParent(); + while (DD && !DD->isTranslationUnit()) { + DeclContextToReenter.push_back(DD); + DD = DD->getLexicalParent(); + } + + // Reenter template scopes from outmost to innermost. + SmallVector::reverse_iterator II = + DeclContextToReenter.rbegin(); + for (; II != DeclContextToReenter.rend(); ++II) { + if (ClassTemplatePartialSpecializationDecl* MD = + dyn_cast_or_null(*II)) { + 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 )); + Actions.ActOnReenterTemplateScope(getCurScope(), + MD->getDescribedClassTemplate()); + } + TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope)); + Actions.PushDeclContext(Actions.getCurScope(), *II); + } + TemplateParamScopeStack.push_back(new ParseScope(this, + Scope::TemplateParamScope)); + Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); + } + + assert(!LMT.Toks.empty() && "Empty body!"); + + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + LMT.Toks.push_back(Tok); + PP.EnterTokenStream(LMT.Toks.data(), LMT.Toks.size(), true, false); + + // Consume the previously pushed token. + ConsumeAnyToken(); + assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) + && "Inline method not starting with '{', ':' or 'try'"); + + // Parse the method body. Function body parsing code is similar enough + // to be re-used for method bodies as well. + ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); + + // Recreate the containing function DeclContext. + Sema::ContextRAII FunctionSavedContext(Actions, Actions.getContainingDC(FD)); + + if (FunctionTemplateDecl *FunctionTemplate + = dyn_cast_or_null(LMT.D)) + Actions.ActOnStartOfFunctionDef(getCurScope(), + FunctionTemplate->getTemplatedDecl()); + if (FunctionDecl *Function = dyn_cast_or_null(LMT.D)) + Actions.ActOnStartOfFunctionDef(getCurScope(), Function); + + + if (Tok.is(tok::kw_try)) { + ParseFunctionTryBlock(LMT.D, FnScope); + } else { + if (Tok.is(tok::colon)) + ParseConstructorInitializer(LMT.D); + else + Actions.ActOnDefaultCtorInitializers(LMT.D); + + if (Tok.is(tok::l_brace)) { + ParseFunctionStatementBody(LMT.D, FnScope); + Actions.MarkAsLateParsedTemplate(FD, false); + } else + Actions.ActOnFinishFunctionBody(LMT.D, 0); + } + + // Exit scopes. + FnScope.Exit(); + SmallVector::reverse_iterator I = + TemplateParamScopeStack.rbegin(); + for (; I != TemplateParamScopeStack.rend(); ++I) + delete *I; + + DeclGroupPtrTy grp = Actions.ConvertDeclToDeclGroup(LMT.D); + if (grp) + Actions.getASTConsumer().HandleTopLevelDecl(grp.get()); +} + +/// \brief Lex a delayed template function for late parsing. +void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) { + tok::TokenKind kind = Tok.getKind(); + if (!ConsumeAndStoreFunctionPrologue(Toks)) { + // 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) { + while (Tok.is(tok::kw_catch)) { + ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); + } + } +} diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp new file mode 100644 index 0000000..28c5e8b --- /dev/null +++ b/clang/lib/Parse/ParseTentative.cpp @@ -0,0 +1,1444 @@ +//===--- ParseTentative.cpp - Ambiguity Resolution Parsing ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the tentative parsing portions of the Parser +// interfaces, for ambiguity resolution. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Sema/ParsedTemplate.h" +using namespace clang; + +/// isCXXDeclarationStatement - C++-specialized function that disambiguates +/// between a declaration or an expression statement, when parsing function +/// bodies. Returns true for declaration, false for expression. +/// +/// declaration-statement: +/// block-declaration +/// +/// block-declaration: +/// simple-declaration +/// asm-definition +/// namespace-alias-definition +/// using-declaration +/// using-directive +/// [C++0x] static_assert-declaration +/// +/// asm-definition: +/// 'asm' '(' string-literal ')' ';' +/// +/// namespace-alias-definition: +/// 'namespace' identifier = qualified-namespace-specifier ';' +/// +/// using-declaration: +/// 'using' typename[opt] '::'[opt] nested-name-specifier +/// unqualified-id ';' +/// 'using' '::' unqualified-id ; +/// +/// using-directive: +/// 'using' 'namespace' '::'[opt] nested-name-specifier[opt] +/// namespace-name ';' +/// +bool Parser::isCXXDeclarationStatement() { + switch (Tok.getKind()) { + // asm-definition + case tok::kw_asm: + // namespace-alias-definition + case tok::kw_namespace: + // using-declaration + // using-directive + case tok::kw_using: + // static_assert-declaration + case tok::kw_static_assert: + case tok::kw__Static_assert: + return true; + // simple-declaration + default: + return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false); + } +} + +/// isCXXSimpleDeclaration - C++-specialized function that disambiguates +/// between a simple-declaration or an expression-statement. +/// If during the disambiguation process a parsing error is encountered, +/// the function returns true to let the declaration parsing code handle it. +/// Returns false if the statement is disambiguated as expression. +/// +/// simple-declaration: +/// decl-specifier-seq init-declarator-list[opt] ';' +/// +/// (if AllowForRangeDecl specified) +/// for ( for-range-declaration : for-range-initializer ) statement +/// for-range-declaration: +/// attribute-specifier-seqopt type-specifier-seq declarator +bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) { + // C++ 6.8p1: + // There is an ambiguity in the grammar involving expression-statements and + // declarations: An expression-statement with a function-style explicit type + // conversion (5.2.3) as its leftmost subexpression can be indistinguishable + // from a declaration where the first declarator starts with a '('. In those + // cases the statement is a declaration. [Note: To disambiguate, the whole + // statement might have to be examined to determine if it is an + // expression-statement or a declaration]. + + // C++ 6.8p3: + // The disambiguation is purely syntactic; that is, the meaning of the names + // occurring in such a statement, beyond whether they are type-names or not, + // is not generally used in or changed by the disambiguation. Class + // templates are instantiated as necessary to determine if a qualified name + // is a type-name. Disambiguation precedes parsing, and a statement + // disambiguated as a declaration may be an ill-formed declaration. + + // We don't have to parse all of the decl-specifier-seq part. There's only + // an ambiguity if the first decl-specifier is + // simple-type-specifier/typename-specifier followed by a '(', which may + // indicate a function-style cast expression. + // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such + // a case. + + TPResult TPR = isCXXDeclarationSpecifier(); + if (TPR != TPResult::Ambiguous()) + return TPR != TPResult::False(); // Returns true for TPResult::True() or + // TPResult::Error(). + + // FIXME: Add statistics about the number of ambiguous statements encountered + // and how they were resolved (number of declarations+number of expressions). + + // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. + // We need tentative parsing... + + TentativeParsingAction PA(*this); + TPR = TryParseSimpleDeclaration(AllowForRangeDecl); + PA.Revert(); + + // In case of an error, let the declaration parsing code handle it. + if (TPR == TPResult::Error()) + return true; + + // Declarations take precedence over expressions. + if (TPR == TPResult::Ambiguous()) + TPR = TPResult::True(); + + assert(TPR == TPResult::True() || TPR == TPResult::False()); + return TPR == TPResult::True(); +} + +/// simple-declaration: +/// decl-specifier-seq init-declarator-list[opt] ';' +/// +/// (if AllowForRangeDecl specified) +/// for ( for-range-declaration : for-range-initializer ) statement +/// for-range-declaration: +/// attribute-specifier-seqopt type-specifier-seq declarator +/// +Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { + // We know that we have a simple-type-specifier/typename-specifier followed + // by a '('. + assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous()); + + if (Tok.is(tok::kw_typeof)) + TryParseTypeofSpecifier(); + else { + ConsumeToken(); + + if (getLangOpts().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } + + assert(Tok.is(tok::l_paren) && "Expected '('"); + + TPResult TPR = TryParseInitDeclaratorList(); + if (TPR != TPResult::Ambiguous()) + return TPR; + + if (Tok.isNot(tok::semi) && (!AllowForRangeDecl || Tok.isNot(tok::colon))) + return TPResult::False(); + + return TPResult::Ambiguous(); +} + +/// init-declarator-list: +/// init-declarator +/// init-declarator-list ',' init-declarator +/// +/// init-declarator: +/// declarator initializer[opt] +/// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt] +/// +/// initializer: +/// '=' initializer-clause +/// '(' expression-list ')' +/// +/// initializer-clause: +/// assignment-expression +/// '{' initializer-list ','[opt] '}' +/// '{' '}' +/// +Parser::TPResult Parser::TryParseInitDeclaratorList() { + while (1) { + // declarator + TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/); + if (TPR != TPResult::Ambiguous()) + return TPR; + + // [GNU] simple-asm-expr[opt] attributes[opt] + if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute)) + return TPResult::True(); + + // initializer[opt] + if (Tok.is(tok::l_paren)) { + // Parse through the parens. + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + } else if (Tok.is(tok::equal) || isTokIdentifier_in()) { + // MSVC and g++ won't examine the rest of declarators if '=' is + // encountered; they just conclude that we have a declaration. + // EDG parses the initializer completely, which is the proper behavior + // for this case. + // + // At present, Clang follows MSVC and g++, since the parser does not have + // the ability to parse an expression fully without recording the + // results of that parse. + // Also allow 'in' after on objective-c declaration as in: + // for (int (^b)(void) in array). Ideally this should be done in the + // context of parsing for-init-statement of a foreach statement only. But, + // in any other context 'in' is invalid after a declaration and parser + // issues the error regardless of outcome of this decision. + // FIXME. Change if above assumption does not hold. + return TPResult::True(); + } + + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // the comma. + } + + return TPResult::Ambiguous(); +} + +/// isCXXConditionDeclaration - Disambiguates between a declaration or an +/// expression for a condition of a if/switch/while/for statement. +/// If during the disambiguation process a parsing error is encountered, +/// the function returns true to let the declaration parsing code handle it. +/// +/// condition: +/// expression +/// type-specifier-seq declarator '=' assignment-expression +/// [C++11] type-specifier-seq declarator '=' initializer-clause +/// [C++11] type-specifier-seq declarator braced-init-list +/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] +/// '=' assignment-expression +/// +bool Parser::isCXXConditionDeclaration() { + TPResult TPR = isCXXDeclarationSpecifier(); + if (TPR != TPResult::Ambiguous()) + return TPR != TPResult::False(); // Returns true for TPResult::True() or + // TPResult::Error(). + + // FIXME: Add statistics about the number of ambiguous statements encountered + // and how they were resolved (number of declarations+number of expressions). + + // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. + // We need tentative parsing... + + TentativeParsingAction PA(*this); + + // type-specifier-seq + if (Tok.is(tok::kw_typeof)) + TryParseTypeofSpecifier(); + else { + ConsumeToken(); + + if (getLangOpts().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } + assert(Tok.is(tok::l_paren) && "Expected '('"); + + // declarator + TPR = TryParseDeclarator(false/*mayBeAbstract*/); + + // In case of an error, let the declaration parsing code handle it. + if (TPR == TPResult::Error()) + TPR = TPResult::True(); + + if (TPR == TPResult::Ambiguous()) { + // '=' + // [GNU] simple-asm-expr[opt] attributes[opt] + if (Tok.is(tok::equal) || + Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute)) + TPR = TPResult::True(); + else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) + TPR = TPResult::True(); + else + TPR = TPResult::False(); + } + + PA.Revert(); + + assert(TPR == TPResult::True() || TPR == TPResult::False()); + return TPR == TPResult::True(); +} + + /// \brief Determine whether the next set of tokens contains a type-id. + /// + /// The context parameter states what context we're parsing right + /// now, which affects how this routine copes with the token + /// following the type-id. If the context is TypeIdInParens, we have + /// already parsed the '(' and we will cease lookahead when we hit + /// the corresponding ')'. If the context is + /// TypeIdAsTemplateArgument, we've already parsed the '<' or ',' + /// before this template argument, and will cease lookahead when we + /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id + /// and false for an expression. If during the disambiguation + /// process a parsing error is encountered, the function returns + /// true to let the declaration parsing code handle it. + /// + /// type-id: + /// type-specifier-seq abstract-declarator[opt] + /// +bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { + + isAmbiguous = false; + + // C++ 8.2p2: + // The ambiguity arising from the similarity between a function-style cast and + // a type-id can occur in different contexts. The ambiguity appears as a + // choice between a function-style cast expression and a declaration of a + // type. The resolution is that any construct that could possibly be a type-id + // in its syntactic context shall be considered a type-id. + + TPResult TPR = isCXXDeclarationSpecifier(); + if (TPR != TPResult::Ambiguous()) + return TPR != TPResult::False(); // Returns true for TPResult::True() or + // TPResult::Error(). + + // FIXME: Add statistics about the number of ambiguous statements encountered + // and how they were resolved (number of declarations+number of expressions). + + // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. + // We need tentative parsing... + + TentativeParsingAction PA(*this); + + // type-specifier-seq + if (Tok.is(tok::kw_typeof)) + TryParseTypeofSpecifier(); + else { + ConsumeToken(); + + if (getLangOpts().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } + + assert(Tok.is(tok::l_paren) && "Expected '('"); + + // declarator + TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/); + + // In case of an error, let the declaration parsing code handle it. + if (TPR == TPResult::Error()) + TPR = TPResult::True(); + + if (TPR == TPResult::Ambiguous()) { + // We are supposed to be inside parens, so if after the abstract declarator + // we encounter a ')' this is a type-id, otherwise it's an expression. + if (Context == TypeIdInParens && Tok.is(tok::r_paren)) { + TPR = TPResult::True(); + isAmbiguous = true; + + // We are supposed to be inside a template argument, so if after + // the abstract declarator we encounter a '>', '>>' (in C++0x), or + // ',', this is a type-id. Otherwise, it's an expression. + } else if (Context == TypeIdAsTemplateArgument && + (Tok.is(tok::greater) || Tok.is(tok::comma) || + (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater)))) { + TPR = TPResult::True(); + isAmbiguous = true; + + } else + TPR = TPResult::False(); + } + + PA.Revert(); + + assert(TPR == TPResult::True() || TPR == TPResult::False()); + return TPR == TPResult::True(); +} + +/// \brief Returns true if this is a C++11 attribute-specifier. Per +/// C++11 [dcl.attr.grammar]p6, two consecutive left square bracket tokens +/// always introduce an attribute. In Objective-C++11, this rule does not +/// apply if either '[' begins a message-send. +/// +/// If Disambiguate is true, we try harder to determine whether a '[[' starts +/// an attribute-specifier, and return CAK_InvalidAttributeSpecifier if not. +/// +/// If OuterMightBeMessageSend is true, we assume the outer '[' is either an +/// Obj-C message send or the start of an attribute. Otherwise, we assume it +/// is not an Obj-C message send. +/// +/// C++11 [dcl.attr.grammar]: +/// +/// attribute-specifier: +/// '[' '[' attribute-list ']' ']' +/// alignment-specifier +/// +/// attribute-list: +/// attribute[opt] +/// attribute-list ',' attribute[opt] +/// attribute '...' +/// attribute-list ',' attribute '...' +/// +/// attribute: +/// attribute-token attribute-argument-clause[opt] +/// +/// attribute-token: +/// identifier +/// identifier '::' identifier +/// +/// attribute-argument-clause: +/// '(' balanced-token-seq ')' +Parser::CXX11AttributeKind +Parser::isCXX11AttributeSpecifier(bool Disambiguate, + bool OuterMightBeMessageSend) { + if (Tok.is(tok::kw_alignas)) + return CAK_AttributeSpecifier; + + if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) + return CAK_NotAttributeSpecifier; + + // No tentative parsing if we don't need to look for ']]' or a lambda. + if (!Disambiguate && !getLangOpts().ObjC1) + return CAK_AttributeSpecifier; + + TentativeParsingAction PA(*this); + + // Opening brackets were checked for above. + ConsumeBracket(); + + // Outside Obj-C++11, treat anything with a matching ']]' as an attribute. + if (!getLangOpts().ObjC1) { + ConsumeBracket(); + + bool IsAttribute = SkipUntil(tok::r_square, false); + IsAttribute &= Tok.is(tok::r_square); + + PA.Revert(); + + return IsAttribute ? CAK_AttributeSpecifier : CAK_InvalidAttributeSpecifier; + } + + // In Obj-C++11, we need to distinguish four situations: + // 1a) int x[[attr]]; C++11 attribute. + // 1b) [[attr]]; C++11 statement attribute. + // 2) int x[[obj](){ return 1; }()]; Lambda in array size/index. + // 3a) int x[[obj get]]; Message send in array size/index. + // 3b) [[Class alloc] init]; Message send in message send. + // 4) [[obj]{ return self; }() doStuff]; Lambda in message send. + // (1) is an attribute, (2) is ill-formed, and (3) and (4) are accepted. + + // If we have a lambda-introducer, then this is definitely not a message send. + // FIXME: If this disambiguation is too slow, fold the tentative lambda parse + // into the tentative attribute parse below. + LambdaIntroducer Intro; + if (!TryParseLambdaIntroducer(Intro)) { + // A lambda cannot end with ']]', and an attribute must. + bool IsAttribute = Tok.is(tok::r_square); + + PA.Revert(); + + if (IsAttribute) + // Case 1: C++11 attribute. + return CAK_AttributeSpecifier; + + if (OuterMightBeMessageSend) + // Case 4: Lambda in message send. + return CAK_NotAttributeSpecifier; + + // Case 2: Lambda in array size / index. + return CAK_InvalidAttributeSpecifier; + } + + ConsumeBracket(); + + // If we don't have a lambda-introducer, then we have an attribute or a + // message-send. + bool IsAttribute = true; + while (Tok.isNot(tok::r_square)) { + if (Tok.is(tok::comma)) { + // Case 1: Stray commas can only occur in attributes. + PA.Revert(); + return CAK_AttributeSpecifier; + } + + // Parse the attribute-token, if present. + // C++11 [dcl.attr.grammar]: + // If a keyword or an alternative token that satisfies the syntactic + // requirements of an identifier is contained in an attribute-token, + // it is considered an identifier. + SourceLocation Loc; + if (!TryParseCXX11AttributeIdentifier(Loc)) { + IsAttribute = false; + break; + } + if (Tok.is(tok::coloncolon)) { + ConsumeToken(); + if (!TryParseCXX11AttributeIdentifier(Loc)) { + IsAttribute = false; + break; + } + } + + // Parse the attribute-argument-clause, if present. + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + if (!SkipUntil(tok::r_paren, false)) { + IsAttribute = false; + break; + } + } + + if (Tok.is(tok::ellipsis)) + ConsumeToken(); + + if (Tok.isNot(tok::comma)) + break; + + ConsumeToken(); + } + + // An attribute must end ']]'. + if (IsAttribute) { + if (Tok.is(tok::r_square)) { + ConsumeBracket(); + IsAttribute = Tok.is(tok::r_square); + } else { + IsAttribute = false; + } + } + + PA.Revert(); + + if (IsAttribute) + // Case 1: C++11 statement attribute. + return CAK_AttributeSpecifier; + + // Case 3: Message send. + return CAK_NotAttributeSpecifier; +} + +/// declarator: +/// direct-declarator +/// ptr-operator declarator +/// +/// direct-declarator: +/// declarator-id +/// direct-declarator '(' parameter-declaration-clause ')' +/// cv-qualifier-seq[opt] exception-specification[opt] +/// direct-declarator '[' constant-expression[opt] ']' +/// '(' declarator ')' +/// [GNU] '(' attributes declarator ')' +/// +/// abstract-declarator: +/// ptr-operator abstract-declarator[opt] +/// direct-abstract-declarator +/// ... +/// +/// direct-abstract-declarator: +/// direct-abstract-declarator[opt] +/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] +/// exception-specification[opt] +/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']' +/// '(' abstract-declarator ')' +/// +/// ptr-operator: +/// '*' cv-qualifier-seq[opt] +/// '&' +/// [C++0x] '&&' [TODO] +/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] +/// +/// cv-qualifier-seq: +/// cv-qualifier cv-qualifier-seq[opt] +/// +/// cv-qualifier: +/// 'const' +/// 'volatile' +/// +/// declarator-id: +/// '...'[opt] id-expression +/// +/// id-expression: +/// unqualified-id +/// qualified-id [TODO] +/// +/// unqualified-id: +/// identifier +/// operator-function-id [TODO] +/// conversion-function-id [TODO] +/// '~' class-name [TODO] +/// template-id [TODO] +/// +Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, + bool mayHaveIdentifier) { + // declarator: + // direct-declarator + // ptr-operator declarator + + while (1) { + if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier)) + if (TryAnnotateCXXScopeToken(true)) + return TPResult::Error(); + + if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) || + Tok.is(tok::ampamp) || + (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { + // ptr-operator + ConsumeToken(); + while (Tok.is(tok::kw_const) || + Tok.is(tok::kw_volatile) || + Tok.is(tok::kw_restrict)) + ConsumeToken(); + } else { + break; + } + } + + // direct-declarator: + // direct-abstract-declarator: + if (Tok.is(tok::ellipsis)) + ConsumeToken(); + + if ((Tok.is(tok::identifier) || + (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) && + mayHaveIdentifier) { + // declarator-id + if (Tok.is(tok::annot_cxxscope)) + ConsumeToken(); + ConsumeToken(); + } else if (Tok.is(tok::l_paren)) { + ConsumeParen(); + if (mayBeAbstract && + (Tok.is(tok::r_paren) || // 'int()' is a function. + // 'int(...)' is a function. + (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) || + isDeclarationSpecifier())) { // 'int(int)' is a function. + // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] + // exception-specification[opt] + TPResult TPR = TryParseFunctionDeclarator(); + if (TPR != TPResult::Ambiguous()) + return TPR; + } else { + // '(' declarator ')' + // '(' attributes declarator ')' + // '(' abstract-declarator ')' + if (Tok.is(tok::kw___attribute) || + Tok.is(tok::kw___declspec) || + Tok.is(tok::kw___cdecl) || + Tok.is(tok::kw___stdcall) || + Tok.is(tok::kw___fastcall) || + Tok.is(tok::kw___thiscall) || + Tok.is(tok::kw___unaligned)) + return TPResult::True(); // attributes indicate declaration + TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier); + if (TPR != TPResult::Ambiguous()) + return TPR; + if (Tok.isNot(tok::r_paren)) + return TPResult::False(); + ConsumeParen(); + } + } else if (!mayBeAbstract) { + return TPResult::False(); + } + + while (1) { + TPResult TPR(TPResult::Ambiguous()); + + // abstract-declarator: ... + if (Tok.is(tok::ellipsis)) + ConsumeToken(); + + if (Tok.is(tok::l_paren)) { + // Check whether we have a function declarator or a possible ctor-style + // initializer that follows the declarator. Note that ctor-style + // initializers are not possible in contexts where abstract declarators + // are allowed. + if (!mayBeAbstract && !isCXXFunctionDeclarator(false/*warnIfAmbiguous*/)) + break; + + // direct-declarator '(' parameter-declaration-clause ')' + // cv-qualifier-seq[opt] exception-specification[opt] + ConsumeParen(); + TPR = TryParseFunctionDeclarator(); + } else if (Tok.is(tok::l_square)) { + // direct-declarator '[' constant-expression[opt] ']' + // direct-abstract-declarator[opt] '[' constant-expression[opt] ']' + TPR = TryParseBracketDeclarator(); + } else { + break; + } + + if (TPR != TPResult::Ambiguous()) + return TPR; + } + + return TPResult::Ambiguous(); +} + +Parser::TPResult +Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { + switch (Kind) { + // Obviously starts an expression. + case tok::numeric_constant: + case tok::char_constant: + case tok::wide_char_constant: + case tok::utf16_char_constant: + case tok::utf32_char_constant: + case tok::string_literal: + case tok::wide_string_literal: + case tok::utf8_string_literal: + case tok::utf16_string_literal: + case tok::utf32_string_literal: + case tok::l_square: + case tok::l_paren: + case tok::amp: + case tok::ampamp: + case tok::star: + case tok::plus: + case tok::plusplus: + case tok::minus: + case tok::minusminus: + case tok::tilde: + case tok::exclaim: + case tok::kw_sizeof: + case tok::kw___func__: + case tok::kw_const_cast: + case tok::kw_delete: + case tok::kw_dynamic_cast: + case tok::kw_false: + case tok::kw_new: + case tok::kw_operator: + case tok::kw_reinterpret_cast: + case tok::kw_static_cast: + case tok::kw_this: + case tok::kw_throw: + case tok::kw_true: + case tok::kw_typeid: + case tok::kw_alignof: + case tok::kw_noexcept: + case tok::kw_nullptr: + case tok::kw___null: + case tok::kw___alignof: + case tok::kw___builtin_choose_expr: + case tok::kw___builtin_offsetof: + case tok::kw___builtin_types_compatible_p: + case tok::kw___builtin_va_arg: + case tok::kw___imag: + case tok::kw___real: + case tok::kw___FUNCTION__: + case tok::kw___PRETTY_FUNCTION__: + case tok::kw___has_nothrow_assign: + case tok::kw___has_nothrow_copy: + case tok::kw___has_nothrow_constructor: + case tok::kw___has_trivial_assign: + case tok::kw___has_trivial_copy: + case tok::kw___has_trivial_constructor: + case tok::kw___has_trivial_destructor: + case tok::kw___has_virtual_destructor: + case tok::kw___is_abstract: + case tok::kw___is_base_of: + case tok::kw___is_class: + case tok::kw___is_convertible_to: + case tok::kw___is_empty: + case tok::kw___is_enum: + case tok::kw___is_final: + case tok::kw___is_literal: + case tok::kw___is_literal_type: + case tok::kw___is_pod: + case tok::kw___is_polymorphic: + case tok::kw___is_trivial: + case tok::kw___is_trivially_assignable: + case tok::kw___is_trivially_constructible: + case tok::kw___is_trivially_copyable: + case tok::kw___is_union: + case tok::kw___uuidof: + return TPResult::True(); + + // Obviously starts a type-specifier-seq: + case tok::kw_char: + case tok::kw_const: + case tok::kw_double: + case tok::kw_enum: + case tok::kw_half: + case tok::kw_float: + case tok::kw_int: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_restrict: + case tok::kw_short: + case tok::kw_signed: + case tok::kw_struct: + case tok::kw_union: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_volatile: + case tok::kw__Bool: + case tok::kw__Complex: + case tok::kw_class: + case tok::kw_typename: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw___underlying_type: + case tok::kw_thread_local: + case tok::kw__Decimal32: + case tok::kw__Decimal64: + case tok::kw__Decimal128: + case tok::kw___thread: + case tok::kw_typeof: + case tok::kw___cdecl: + case tok::kw___stdcall: + case tok::kw___fastcall: + case tok::kw___thiscall: + case tok::kw___unaligned: + case tok::kw___vector: + case tok::kw___pixel: + case tok::kw__Atomic: + return TPResult::False(); + + default: + break; + } + + return TPResult::Ambiguous(); +} + +/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration +/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could +/// be either a decl-specifier or a function-style cast, and TPResult::Error() +/// if a parsing error was found and reported. +/// +/// decl-specifier: +/// storage-class-specifier +/// type-specifier +/// function-specifier +/// 'friend' +/// 'typedef' +/// [C++0x] 'constexpr' +/// [GNU] attributes declaration-specifiers[opt] +/// +/// storage-class-specifier: +/// 'register' +/// 'static' +/// 'extern' +/// 'mutable' +/// 'auto' +/// [GNU] '__thread' +/// +/// function-specifier: +/// 'inline' +/// 'virtual' +/// 'explicit' +/// +/// typedef-name: +/// identifier +/// +/// type-specifier: +/// simple-type-specifier +/// class-specifier +/// enum-specifier +/// elaborated-type-specifier +/// typename-specifier +/// cv-qualifier +/// +/// simple-type-specifier: +/// '::'[opt] nested-name-specifier[opt] type-name +/// '::'[opt] nested-name-specifier 'template' +/// simple-template-id [TODO] +/// 'char' +/// 'wchar_t' +/// 'bool' +/// 'short' +/// 'int' +/// 'long' +/// 'signed' +/// 'unsigned' +/// 'float' +/// 'double' +/// 'void' +/// [GNU] typeof-specifier +/// [GNU] '_Complex' +/// [C++0x] 'auto' [TODO] +/// [C++0x] 'decltype' ( expression ) +/// +/// type-name: +/// class-name +/// enum-name +/// typedef-name +/// +/// elaborated-type-specifier: +/// class-key '::'[opt] nested-name-specifier[opt] identifier +/// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt] +/// simple-template-id +/// 'enum' '::'[opt] nested-name-specifier[opt] identifier +/// +/// enum-name: +/// identifier +/// +/// enum-specifier: +/// 'enum' identifier[opt] '{' enumerator-list[opt] '}' +/// 'enum' identifier[opt] '{' enumerator-list ',' '}' +/// +/// class-specifier: +/// class-head '{' member-specification[opt] '}' +/// +/// class-head: +/// class-key identifier[opt] base-clause[opt] +/// class-key nested-name-specifier identifier base-clause[opt] +/// class-key nested-name-specifier[opt] simple-template-id +/// base-clause[opt] +/// +/// class-key: +/// 'class' +/// 'struct' +/// 'union' +/// +/// cv-qualifier: +/// 'const' +/// 'volatile' +/// [GNU] restrict +/// +Parser::TPResult +Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) { + switch (Tok.getKind()) { + case tok::identifier: // foo::bar + // Check for need to substitute AltiVec __vector keyword + // for "vector" identifier. + if (TryAltiVecVectorToken()) + return TPResult::True(); + // Fall through. + case tok::kw_typename: // typename T::type + // Annotate typenames and C++ scope specifiers. If we get one, just + // recurse to handle whatever we get. + if (TryAnnotateTypeOrScopeToken()) + return TPResult::Error(); + if (Tok.is(tok::identifier)) + return TPResult::False(); + return isCXXDeclarationSpecifier(BracedCastResult); + + case tok::coloncolon: { // ::foo::bar + const Token &Next = NextToken(); + if (Next.is(tok::kw_new) || // ::new + Next.is(tok::kw_delete)) // ::delete + return TPResult::False(); + } + // Fall through. + case tok::kw_decltype: + // Annotate typenames and C++ scope specifiers. If we get one, just + // recurse to handle whatever we get. + if (TryAnnotateTypeOrScopeToken()) + return TPResult::Error(); + return isCXXDeclarationSpecifier(BracedCastResult); + + // decl-specifier: + // storage-class-specifier + // type-specifier + // function-specifier + // 'friend' + // 'typedef' + // 'constexpr' + case tok::kw_friend: + case tok::kw_typedef: + case tok::kw_constexpr: + // storage-class-specifier + case tok::kw_register: + case tok::kw_static: + case tok::kw_extern: + case tok::kw_mutable: + case tok::kw_auto: + case tok::kw___thread: + // function-specifier + case tok::kw_inline: + case tok::kw_virtual: + case tok::kw_explicit: + + // Modules + case tok::kw___module_private__: + + // type-specifier: + // simple-type-specifier + // class-specifier + // enum-specifier + // elaborated-type-specifier + // typename-specifier + // cv-qualifier + + // class-specifier + // elaborated-type-specifier + case tok::kw_class: + case tok::kw_struct: + case tok::kw_union: + // enum-specifier + case tok::kw_enum: + // cv-qualifier + case tok::kw_const: + case tok::kw_volatile: + + // GNU + case tok::kw_restrict: + case tok::kw__Complex: + case tok::kw___attribute: + return TPResult::True(); + + // Microsoft + case tok::kw___declspec: + case tok::kw___cdecl: + case tok::kw___stdcall: + case tok::kw___fastcall: + case tok::kw___thiscall: + case tok::kw___w64: + case tok::kw___ptr64: + case tok::kw___ptr32: + case tok::kw___forceinline: + case tok::kw___unaligned: + return TPResult::True(); + + // Borland + case tok::kw___pascal: + return TPResult::True(); + + // AltiVec + case tok::kw___vector: + return TPResult::True(); + + case tok::annot_template_id: { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (TemplateId->Kind != TNK_Type_template) + return TPResult::False(); + CXXScopeSpec SS; + AnnotateTemplateIdTokenAsType(); + assert(Tok.is(tok::annot_typename)); + goto case_typename; + } + + case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed + // We've already annotated a scope; try to annotate a type. + if (TryAnnotateTypeOrScopeToken()) + return TPResult::Error(); + if (!Tok.is(tok::annot_typename)) { + // If the next token is an identifier or a type qualifier, then this + // can't possibly be a valid expression either. + if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) { + CXXScopeSpec SS; + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); + if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) { + TentativeParsingAction PA(*this); + ConsumeToken(); + ConsumeToken(); + bool isIdentifier = Tok.is(tok::identifier); + TPResult TPR = TPResult::False(); + if (!isIdentifier) + TPR = isCXXDeclarationSpecifier(BracedCastResult); + PA.Revert(); + + if (isIdentifier || + TPR == TPResult::True() || TPR == TPResult::Error()) + return TPResult::Error(); + } + } + return TPResult::False(); + } + // If that succeeded, fallthrough into the generic simple-type-id case. + + // The ambiguity resides in a simple-type-specifier/typename-specifier + // followed by a '('. The '(' could either be the start of: + // + // direct-declarator: + // '(' declarator ')' + // + // direct-abstract-declarator: + // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] + // exception-specification[opt] + // '(' abstract-declarator ')' + // + // or part of a function-style cast expression: + // + // simple-type-specifier '(' expression-list[opt] ')' + // + + // simple-type-specifier: + + case tok::annot_typename: + case_typename: + // In Objective-C, we might have a protocol-qualified type. + if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { + // Tentatively parse the + TentativeParsingAction PA(*this); + ConsumeToken(); // The type token + + TPResult TPR = TryParseProtocolQualifiers(); + bool isFollowedByParen = Tok.is(tok::l_paren); + bool isFollowedByBrace = Tok.is(tok::l_brace); + + PA.Revert(); + + if (TPR == TPResult::Error()) + return TPResult::Error(); + + if (isFollowedByParen) + return TPResult::Ambiguous(); + + if (getLangOpts().CPlusPlus0x && isFollowedByBrace) + return BracedCastResult; + + return TPResult::True(); + } + + case tok::kw_char: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_bool: + case tok::kw_short: + case tok::kw_int: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_half: + case tok::kw_float: + case tok::kw_double: + case tok::kw_void: + case tok::annot_decltype: + if (NextToken().is(tok::l_paren)) + return TPResult::Ambiguous(); + + // This is a function-style cast in all cases we disambiguate other than + // one: + // struct S { + // enum E : int { a = 4 }; // enum + // enum E : int { 4 }; // bit-field + // }; + if (getLangOpts().CPlusPlus0x && NextToken().is(tok::l_brace)) + return BracedCastResult; + + if (isStartOfObjCClassMessageMissingOpenBracket()) + return TPResult::False(); + + return TPResult::True(); + + // GNU typeof support. + case tok::kw_typeof: { + if (NextToken().isNot(tok::l_paren)) + return TPResult::True(); + + TentativeParsingAction PA(*this); + + TPResult TPR = TryParseTypeofSpecifier(); + bool isFollowedByParen = Tok.is(tok::l_paren); + bool isFollowedByBrace = Tok.is(tok::l_brace); + + PA.Revert(); + + if (TPR == TPResult::Error()) + return TPResult::Error(); + + if (isFollowedByParen) + return TPResult::Ambiguous(); + + if (getLangOpts().CPlusPlus0x && isFollowedByBrace) + return BracedCastResult; + + return TPResult::True(); + } + + // C++0x type traits support + case tok::kw___underlying_type: + return TPResult::True(); + + // C11 _Atomic + case tok::kw__Atomic: + return TPResult::True(); + + default: + return TPResult::False(); + } +} + +/// [GNU] typeof-specifier: +/// 'typeof' '(' expressions ')' +/// 'typeof' '(' type-name ')' +/// +Parser::TPResult Parser::TryParseTypeofSpecifier() { + assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!"); + ConsumeToken(); + + assert(Tok.is(tok::l_paren) && "Expected '('"); + // Parse through the parens after 'typeof'. + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + + return TPResult::Ambiguous(); +} + +/// [ObjC] protocol-qualifiers: +//// '<' identifier-list '>' +Parser::TPResult Parser::TryParseProtocolQualifiers() { + assert(Tok.is(tok::less) && "Expected '<' for qualifier list"); + ConsumeToken(); + do { + if (Tok.isNot(tok::identifier)) + return TPResult::Error(); + ConsumeToken(); + + if (Tok.is(tok::comma)) { + ConsumeToken(); + continue; + } + + if (Tok.is(tok::greater)) { + ConsumeToken(); + return TPResult::Ambiguous(); + } + } while (false); + + return TPResult::Error(); +} + +Parser::TPResult Parser::TryParseDeclarationSpecifier() { + TPResult TPR = isCXXDeclarationSpecifier(); + if (TPR != TPResult::Ambiguous()) + return TPR; + + if (Tok.is(tok::kw_typeof)) + TryParseTypeofSpecifier(); + else { + ConsumeToken(); + + if (getLangOpts().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } + + assert(Tok.is(tok::l_paren) && "Expected '('!"); + return TPResult::Ambiguous(); +} + +/// isCXXFunctionDeclarator - Disambiguates between a function declarator or +/// a constructor-style initializer, when parsing declaration statements. +/// Returns true for function declarator and false for constructor-style +/// initializer. +/// If during the disambiguation process a parsing error is encountered, +/// the function returns true to let the declaration parsing code handle it. +/// +/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] +/// exception-specification[opt] +/// +bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) { + + // C++ 8.2p1: + // The ambiguity arising from the similarity between a function-style cast and + // a declaration mentioned in 6.8 can also occur in the context of a + // declaration. In that context, the choice is between a function declaration + // with a redundant set of parentheses around a parameter name and an object + // declaration with a function-style cast as the initializer. Just as for the + // ambiguities mentioned in 6.8, the resolution is to consider any construct + // that could possibly be a declaration a declaration. + + TentativeParsingAction PA(*this); + + ConsumeParen(); + TPResult TPR = TryParseParameterDeclarationClause(); + if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren)) + TPR = TPResult::False(); + + SourceLocation TPLoc = Tok.getLocation(); + PA.Revert(); + + // In case of an error, let the declaration parsing code handle it. + if (TPR == TPResult::Error()) + return true; + + if (TPR == TPResult::Ambiguous()) { + // Function declarator has precedence over constructor-style initializer. + // Emit a warning just in case the author intended a variable definition. + if (warnIfAmbiguous) + Diag(Tok, diag::warn_parens_disambiguated_as_function_decl) + << SourceRange(Tok.getLocation(), TPLoc); + return true; + } + + return TPR == TPResult::True(); +} + +/// parameter-declaration-clause: +/// parameter-declaration-list[opt] '...'[opt] +/// parameter-declaration-list ',' '...' +/// +/// parameter-declaration-list: +/// parameter-declaration +/// parameter-declaration-list ',' parameter-declaration +/// +/// parameter-declaration: +/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt] +/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt] +/// '=' assignment-expression +/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] +/// attributes[opt] +/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] +/// attributes[opt] '=' assignment-expression +/// +Parser::TPResult Parser::TryParseParameterDeclarationClause() { + + if (Tok.is(tok::r_paren)) + return TPResult::True(); + + // parameter-declaration-list[opt] '...'[opt] + // parameter-declaration-list ',' '...' + // + // parameter-declaration-list: + // parameter-declaration + // parameter-declaration-list ',' parameter-declaration + // + while (1) { + // '...'[opt] + if (Tok.is(tok::ellipsis)) { + ConsumeToken(); + if (Tok.is(tok::r_paren)) + return TPResult::True(); // '...)' is a sign of a function declarator. + else + return TPResult::False(); + } + + // An attribute-specifier-seq here is a sign of a function declarator. + if (isCXX11AttributeSpecifier(/*Disambiguate*/false, + /*OuterMightBeMessageSend*/true)) + return TPResult::True(); + + ParsedAttributes attrs(AttrFactory); + MaybeParseMicrosoftAttributes(attrs); + + // decl-specifier-seq + // A parameter-declaration's initializer must be preceded by an '=', so + // decl-specifier-seq '{' is not a parameter in C++11. + TPResult TPR = TryParseDeclarationSpecifier(); + if (TPR != TPResult::Ambiguous()) + return TPR; + + // declarator + // abstract-declarator[opt] + TPR = TryParseDeclarator(true/*mayBeAbstract*/); + if (TPR != TPResult::Ambiguous()) + return TPR; + + // [GNU] attributes[opt] + if (Tok.is(tok::kw___attribute)) + return TPResult::True(); + + if (Tok.is(tok::equal)) { + // '=' assignment-expression + // Parse through assignment-expression. + if (!SkipUntil(tok::comma, tok::r_paren, true/*StopAtSemi*/, + true/*DontConsume*/)) + return TPResult::Error(); + } + + if (Tok.is(tok::ellipsis)) { + ConsumeToken(); + if (Tok.is(tok::r_paren)) + return TPResult::True(); // '...)' is a sign of a function declarator. + else + return TPResult::False(); + } + + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // the comma. + } + + return TPResult::Ambiguous(); +} + +/// TryParseFunctionDeclarator - We parsed a '(' and we want to try to continue +/// parsing as a function declarator. +/// If TryParseFunctionDeclarator fully parsed the function declarator, it will +/// return TPResult::Ambiguous(), otherwise it will return either False() or +/// Error(). +/// +/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] +/// exception-specification[opt] +/// +/// exception-specification: +/// 'throw' '(' type-id-list[opt] ')' +/// +Parser::TPResult Parser::TryParseFunctionDeclarator() { + + // The '(' is already parsed. + + TPResult TPR = TryParseParameterDeclarationClause(); + if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren)) + TPR = TPResult::False(); + + if (TPR == TPResult::False() || TPR == TPResult::Error()) + return TPR; + + // Parse through the parens. + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + + // cv-qualifier-seq + while (Tok.is(tok::kw_const) || + Tok.is(tok::kw_volatile) || + Tok.is(tok::kw_restrict) ) + ConsumeToken(); + + // ref-qualifier[opt] + if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) + ConsumeToken(); + + // exception-specification + if (Tok.is(tok::kw_throw)) { + ConsumeToken(); + if (Tok.isNot(tok::l_paren)) + return TPResult::Error(); + + // Parse through the parens after 'throw'. + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + } + if (Tok.is(tok::kw_noexcept)) { + ConsumeToken(); + // Possibly an expression as well. + if (Tok.is(tok::l_paren)) { + // Find the matching rparen. + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + } + } + + return TPResult::Ambiguous(); +} + +/// '[' constant-expression[opt] ']' +/// +Parser::TPResult Parser::TryParseBracketDeclarator() { + ConsumeBracket(); + if (!SkipUntil(tok::r_square)) + return TPResult::Error(); + + return TPResult::Ambiguous(); +} diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp new file mode 100644 index 0000000..f1b99fb --- /dev/null +++ b/clang/lib/Parse/Parser.cpp @@ -0,0 +1,1720 @@ +//===--- Parser.cpp - C Language Family Parser ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Parser interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ParsedTemplate.h" +#include "llvm/Support/raw_ostream.h" +#include "RAIIObjectsForParser.h" +#include "ParsePragma.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ASTConsumer.h" +using namespace clang; + +IdentifierInfo *Parser::getSEHExceptKeyword() { + // __except is accepted as a (contextual) keyword + if (!Ident__except && (getLangOpts().MicrosoftExt || getLangOpts().Borland)) + Ident__except = PP.getIdentifierInfo("__except"); + + return Ident__except; +} + +Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies) + : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), + GreaterThanIsOperator(true), ColonIsSacred(false), + InMessageExpression(false), TemplateParameterDepth(0), + SkipFunctionBodies(SkipFunctionBodies) { + Tok.setKind(tok::eof); + Actions.CurScope = 0; + NumCachedScopes = 0; + ParenCount = BracketCount = BraceCount = 0; + CurParsedObjCImpl = 0; + + // Add #pragma handlers. These are removed and destroyed in the + // destructor. + AlignHandler.reset(new PragmaAlignHandler(actions)); + PP.AddPragmaHandler(AlignHandler.get()); + + GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler(actions)); + PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get()); + + OptionsHandler.reset(new PragmaOptionsHandler(actions)); + PP.AddPragmaHandler(OptionsHandler.get()); + + PackHandler.reset(new PragmaPackHandler(actions)); + PP.AddPragmaHandler(PackHandler.get()); + + MSStructHandler.reset(new PragmaMSStructHandler(actions)); + PP.AddPragmaHandler(MSStructHandler.get()); + + UnusedHandler.reset(new PragmaUnusedHandler(actions, *this)); + PP.AddPragmaHandler(UnusedHandler.get()); + + WeakHandler.reset(new PragmaWeakHandler(actions)); + PP.AddPragmaHandler(WeakHandler.get()); + + RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler(actions)); + PP.AddPragmaHandler(RedefineExtnameHandler.get()); + + FPContractHandler.reset(new PragmaFPContractHandler(actions, *this)); + PP.AddPragmaHandler("STDC", FPContractHandler.get()); + + if (getLangOpts().OpenCL) { + OpenCLExtensionHandler.reset( + new PragmaOpenCLExtensionHandler(actions, *this)); + PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get()); + + PP.AddPragmaHandler("OPENCL", FPContractHandler.get()); + } + + PP.setCodeCompletionHandler(*this); +} + +/// If a crash happens while the parser is active, print out a line indicating +/// what the current token is. +void PrettyStackTraceParserEntry::print(raw_ostream &OS) const { + const Token &Tok = P.getCurToken(); + if (Tok.is(tok::eof)) { + OS << " parser at end of file\n"; + return; + } + + if (Tok.getLocation().isInvalid()) { + OS << " parser at unknown location\n"; + return; + } + + const Preprocessor &PP = P.getPreprocessor(); + Tok.getLocation().print(OS, PP.getSourceManager()); + if (Tok.isAnnotation()) + OS << ": at annotation token \n"; + else + OS << ": current parser token '" << PP.getSpelling(Tok) << "'\n"; +} + + +DiagnosticBuilder Parser::Diag(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(Loc, DiagID); +} + +DiagnosticBuilder Parser::Diag(const Token &Tok, unsigned DiagID) { + return Diag(Tok.getLocation(), DiagID); +} + +/// \brief Emits a diagnostic suggesting parentheses surrounding a +/// given range. +/// +/// \param Loc The location where we'll emit the diagnostic. +/// \param Loc The kind of diagnostic to emit. +/// \param ParenRange Source range enclosing code that should be parenthesized. +void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK, + SourceRange ParenRange) { + SourceLocation EndLoc = PP.getLocForEndOfToken(ParenRange.getEnd()); + if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { + // We can't display the parentheses, so just dig the + // warning/error and return. + Diag(Loc, DK); + return; + } + + Diag(Loc, DK) + << FixItHint::CreateInsertion(ParenRange.getBegin(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); +} + +static bool IsCommonTypo(tok::TokenKind ExpectedTok, const Token &Tok) { + switch (ExpectedTok) { + case tok::semi: return Tok.is(tok::colon); // : for ; + default: return false; + } +} + +/// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the +/// input. If so, it is consumed and false is returned. +/// +/// If the input is malformed, this emits the specified diagnostic. Next, if +/// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is +/// returned. +bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, + const char *Msg, tok::TokenKind SkipToTok) { + if (Tok.is(ExpectedTok) || Tok.is(tok::code_completion)) { + ConsumeAnyToken(); + return false; + } + + // Detect common single-character typos and resume. + if (IsCommonTypo(ExpectedTok, Tok)) { + SourceLocation Loc = Tok.getLocation(); + Diag(Loc, DiagID) + << Msg + << FixItHint::CreateReplacement(SourceRange(Loc), + getTokenSimpleSpelling(ExpectedTok)); + ConsumeAnyToken(); + + // Pretend there wasn't a problem. + return false; + } + + const char *Spelling = 0; + SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation); + if (EndLoc.isValid() && + (Spelling = tok::getTokenSimpleSpelling(ExpectedTok))) { + // Show what code to insert to fix this problem. + Diag(EndLoc, DiagID) + << Msg + << FixItHint::CreateInsertion(EndLoc, Spelling); + } else + Diag(Tok, DiagID) << Msg; + + if (SkipToTok != tok::unknown) + SkipUntil(SkipToTok); + return true; +} + +bool Parser::ExpectAndConsumeSemi(unsigned DiagID) { + if (Tok.is(tok::semi) || Tok.is(tok::code_completion)) { + ConsumeAnyToken(); + return false; + } + + if ((Tok.is(tok::r_paren) || Tok.is(tok::r_square)) && + NextToken().is(tok::semi)) { + Diag(Tok, diag::err_extraneous_token_before_semi) + << PP.getSpelling(Tok) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeAnyToken(); // The ')' or ']'. + ConsumeToken(); // The ';'. + return false; + } + + return ExpectAndConsume(tok::semi, DiagID); +} + +//===----------------------------------------------------------------------===// +// Error recovery. +//===----------------------------------------------------------------------===// + +/// SkipUntil - Read tokens until we get to the specified token, then consume +/// it (unless DontConsume is true). Because we cannot guarantee that the +/// token will ever occur, this skips to the next token, or to some likely +/// good stopping point. If StopAtSemi is true, skipping will stop at a ';' +/// character. +/// +/// If SkipUntil finds the specified token, it returns true, otherwise it +/// returns false. +bool Parser::SkipUntil(ArrayRef Toks, bool StopAtSemi, + bool DontConsume, bool StopAtCodeCompletion) { + // We always want this function to skip at least one token if the first token + // isn't T and if not at EOF. + bool isFirstTokenSkipped = true; + while (1) { + // If we found one of the tokens, stop and return true. + for (unsigned i = 0, NumToks = Toks.size(); i != NumToks; ++i) { + if (Tok.is(Toks[i])) { + if (DontConsume) { + // Noop, don't consume the token. + } else { + ConsumeAnyToken(); + } + return true; + } + } + + switch (Tok.getKind()) { + case tok::eof: + // Ran out of tokens. + return false; + + case tok::code_completion: + if (!StopAtCodeCompletion) + ConsumeToken(); + return false; + + case tok::l_paren: + // Recursively skip properly-nested parens. + ConsumeParen(); + SkipUntil(tok::r_paren, false, false, StopAtCodeCompletion); + break; + case tok::l_square: + // Recursively skip properly-nested square brackets. + ConsumeBracket(); + SkipUntil(tok::r_square, false, false, StopAtCodeCompletion); + break; + case tok::l_brace: + // Recursively skip properly-nested braces. + ConsumeBrace(); + SkipUntil(tok::r_brace, false, false, StopAtCodeCompletion); + break; + + // Okay, we found a ']' or '}' or ')', which we think should be balanced. + // Since the user wasn't looking for this token (if they were, it would + // already be handled), this isn't balanced. If there is a LHS token at a + // higher level, we will assume that this matches the unbalanced token + // and return it. Otherwise, this is a spurious RHS token, which we skip. + case tok::r_paren: + if (ParenCount && !isFirstTokenSkipped) + return false; // Matches something. + ConsumeParen(); + break; + case tok::r_square: + if (BracketCount && !isFirstTokenSkipped) + return false; // Matches something. + ConsumeBracket(); + break; + case tok::r_brace: + if (BraceCount && !isFirstTokenSkipped) + return false; // Matches something. + ConsumeBrace(); + break; + + case tok::string_literal: + case tok::wide_string_literal: + case tok::utf8_string_literal: + case tok::utf16_string_literal: + case tok::utf32_string_literal: + ConsumeStringToken(); + break; + + case tok::semi: + if (StopAtSemi) + return false; + // FALL THROUGH. + default: + // Skip this token. + ConsumeToken(); + break; + } + isFirstTokenSkipped = false; + } +} + +//===----------------------------------------------------------------------===// +// Scope manipulation +//===----------------------------------------------------------------------===// + +/// EnterScope - Start a new scope. +void Parser::EnterScope(unsigned ScopeFlags) { + if (NumCachedScopes) { + Scope *N = ScopeCache[--NumCachedScopes]; + N->Init(getCurScope(), ScopeFlags); + Actions.CurScope = N; + } else { + Actions.CurScope = new Scope(getCurScope(), ScopeFlags, Diags); + } +} + +/// ExitScope - Pop a scope off the scope stack. +void Parser::ExitScope() { + assert(getCurScope() && "Scope imbalance!"); + + // Inform the actions module that this scope is going away if there are any + // decls in it. + if (!getCurScope()->decl_empty()) + Actions.ActOnPopScope(Tok.getLocation(), getCurScope()); + + Scope *OldScope = getCurScope(); + Actions.CurScope = OldScope->getParent(); + + if (NumCachedScopes == ScopeCacheSize) + delete OldScope; + else + ScopeCache[NumCachedScopes++] = OldScope; +} + +/// Set the flags for the current scope to ScopeFlags. If ManageFlags is false, +/// this object does nothing. +Parser::ParseScopeFlags::ParseScopeFlags(Parser *Self, unsigned ScopeFlags, + bool ManageFlags) + : CurScope(ManageFlags ? Self->getCurScope() : 0) { + if (CurScope) { + OldFlags = CurScope->getFlags(); + CurScope->setFlags(ScopeFlags); + } +} + +/// Restore the flags for the current scope to what they were before this +/// object overrode them. +Parser::ParseScopeFlags::~ParseScopeFlags() { + if (CurScope) + CurScope->setFlags(OldFlags); +} + + +//===----------------------------------------------------------------------===// +// C99 6.9: External Definitions. +//===----------------------------------------------------------------------===// + +Parser::~Parser() { + // If we still have scopes active, delete the scope tree. + delete getCurScope(); + Actions.CurScope = 0; + + // Free the scope cache. + for (unsigned i = 0, e = NumCachedScopes; i != e; ++i) + delete ScopeCache[i]; + + // Free LateParsedTemplatedFunction nodes. + for (LateParsedTemplateMapT::iterator it = LateParsedTemplateMap.begin(); + it != LateParsedTemplateMap.end(); ++it) + delete it->second; + + // Remove the pragma handlers we installed. + PP.RemovePragmaHandler(AlignHandler.get()); + AlignHandler.reset(); + PP.RemovePragmaHandler("GCC", GCCVisibilityHandler.get()); + GCCVisibilityHandler.reset(); + PP.RemovePragmaHandler(OptionsHandler.get()); + OptionsHandler.reset(); + PP.RemovePragmaHandler(PackHandler.get()); + PackHandler.reset(); + PP.RemovePragmaHandler(MSStructHandler.get()); + MSStructHandler.reset(); + PP.RemovePragmaHandler(UnusedHandler.get()); + UnusedHandler.reset(); + PP.RemovePragmaHandler(WeakHandler.get()); + WeakHandler.reset(); + PP.RemovePragmaHandler(RedefineExtnameHandler.get()); + RedefineExtnameHandler.reset(); + + if (getLangOpts().OpenCL) { + PP.RemovePragmaHandler("OPENCL", OpenCLExtensionHandler.get()); + OpenCLExtensionHandler.reset(); + PP.RemovePragmaHandler("OPENCL", FPContractHandler.get()); + } + + PP.RemovePragmaHandler("STDC", FPContractHandler.get()); + FPContractHandler.reset(); + PP.clearCodeCompletionHandler(); + + assert(TemplateIds.empty() && "Still alive TemplateIdAnnotations around?"); +} + +/// Initialize - Warm up the parser. +/// +void Parser::Initialize() { + // Create the translation unit scope. Install it as the current scope. + assert(getCurScope() == 0 && "A scope is already active?"); + EnterScope(Scope::DeclScope); + Actions.ActOnTranslationUnitScope(getCurScope()); + + // Prime the lexer look-ahead. + ConsumeToken(); + + if (Tok.is(tok::eof) && + !getLangOpts().CPlusPlus) // Empty source file is an extension in C + Diag(Tok, diag::ext_empty_source_file); + + // Initialization for Objective-C context sensitive keywords recognition. + // Referenced in Parser::ParseObjCTypeQualifierList. + if (getLangOpts().ObjC1) { + ObjCTypeQuals[objc_in] = &PP.getIdentifierTable().get("in"); + ObjCTypeQuals[objc_out] = &PP.getIdentifierTable().get("out"); + ObjCTypeQuals[objc_inout] = &PP.getIdentifierTable().get("inout"); + ObjCTypeQuals[objc_oneway] = &PP.getIdentifierTable().get("oneway"); + ObjCTypeQuals[objc_bycopy] = &PP.getIdentifierTable().get("bycopy"); + ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref"); + } + + Ident_instancetype = 0; + Ident_final = 0; + Ident_override = 0; + + Ident_super = &PP.getIdentifierTable().get("super"); + + if (getLangOpts().AltiVec) { + Ident_vector = &PP.getIdentifierTable().get("vector"); + Ident_pixel = &PP.getIdentifierTable().get("pixel"); + } + + Ident_introduced = 0; + Ident_deprecated = 0; + Ident_obsoleted = 0; + Ident_unavailable = 0; + + Ident__except = 0; + + Ident__exception_code = Ident__exception_info = Ident__abnormal_termination = 0; + Ident___exception_code = Ident___exception_info = Ident___abnormal_termination = 0; + Ident_GetExceptionCode = Ident_GetExceptionInfo = Ident_AbnormalTermination = 0; + + if(getLangOpts().Borland) { + Ident__exception_info = PP.getIdentifierInfo("_exception_info"); + Ident___exception_info = PP.getIdentifierInfo("__exception_info"); + Ident_GetExceptionInfo = PP.getIdentifierInfo("GetExceptionInformation"); + Ident__exception_code = PP.getIdentifierInfo("_exception_code"); + Ident___exception_code = PP.getIdentifierInfo("__exception_code"); + Ident_GetExceptionCode = PP.getIdentifierInfo("GetExceptionCode"); + Ident__abnormal_termination = PP.getIdentifierInfo("_abnormal_termination"); + Ident___abnormal_termination = PP.getIdentifierInfo("__abnormal_termination"); + Ident_AbnormalTermination = PP.getIdentifierInfo("AbnormalTermination"); + + PP.SetPoisonReason(Ident__exception_code,diag::err_seh___except_block); + PP.SetPoisonReason(Ident___exception_code,diag::err_seh___except_block); + PP.SetPoisonReason(Ident_GetExceptionCode,diag::err_seh___except_block); + PP.SetPoisonReason(Ident__exception_info,diag::err_seh___except_filter); + PP.SetPoisonReason(Ident___exception_info,diag::err_seh___except_filter); + PP.SetPoisonReason(Ident_GetExceptionInfo,diag::err_seh___except_filter); + PP.SetPoisonReason(Ident__abnormal_termination,diag::err_seh___finally_block); + PP.SetPoisonReason(Ident___abnormal_termination,diag::err_seh___finally_block); + PP.SetPoisonReason(Ident_AbnormalTermination,diag::err_seh___finally_block); + } +} + +namespace { + /// \brief RAIIObject to destroy the contents of a SmallVector of + /// TemplateIdAnnotation pointers and clear the vector. + class DestroyTemplateIdAnnotationsRAIIObj { + SmallVectorImpl &Container; + public: + DestroyTemplateIdAnnotationsRAIIObj(SmallVectorImpl + &Container) + : Container(Container) {} + + ~DestroyTemplateIdAnnotationsRAIIObj() { + for (SmallVectorImpl::iterator I = + Container.begin(), E = Container.end(); + I != E; ++I) + (*I)->Destroy(); + Container.clear(); + } + }; +} + +/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the +/// action tells us to. This returns true if the EOF was encountered. +bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { + DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds); + + // Skip over the EOF token, flagging end of previous input for incremental + // processing + if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof)) + ConsumeToken(); + + while (Tok.is(tok::annot_pragma_unused)) + HandlePragmaUnused(); + + Result = DeclGroupPtrTy(); + if (Tok.is(tok::eof)) { + // Late template parsing can begin. + if (getLangOpts().DelayedTemplateParsing) + Actions.SetLateTemplateParser(LateTemplateParserCallback, this); + if (!PP.isIncrementalProcessingEnabled()) + Actions.ActOnEndOfTranslationUnit(); + //else don't tell Sema that we ended parsing: more input might come. + + return true; + } + + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + + Result = ParseExternalDeclaration(attrs); + return false; +} + +/// ParseTranslationUnit: +/// translation-unit: [C99 6.9] +/// external-declaration +/// translation-unit external-declaration +void Parser::ParseTranslationUnit() { + Initialize(); + + DeclGroupPtrTy Res; + while (!ParseTopLevelDecl(Res)) + /*parse them all*/; + + ExitScope(); + assert(getCurScope() == 0 && "Scope imbalance!"); +} + +/// ParseExternalDeclaration: +/// +/// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl] +/// function-definition +/// declaration +/// [C++0x] empty-declaration +/// [GNU] asm-definition +/// [GNU] __extension__ external-declaration +/// [OBJC] objc-class-definition +/// [OBJC] objc-class-declaration +/// [OBJC] objc-alias-declaration +/// [OBJC] objc-protocol-definition +/// [OBJC] objc-method-definition +/// [OBJC] @end +/// [C++] linkage-specification +/// [GNU] asm-definition: +/// simple-asm-expr ';' +/// +/// [C++0x] empty-declaration: +/// ';' +/// +/// [C++0x/GNU] 'extern' 'template' declaration +Parser::DeclGroupPtrTy +Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, + ParsingDeclSpec *DS) { + DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds); + ParenBraceBracketBalancer BalancerRAIIObj(*this); + + if (PP.isCodeCompletionReached()) { + cutOffParsing(); + return DeclGroupPtrTy(); + } + + Decl *SingleDecl = 0; + switch (Tok.getKind()) { + case tok::annot_pragma_vis: + HandlePragmaVisibility(); + return DeclGroupPtrTy(); + case tok::annot_pragma_pack: + HandlePragmaPack(); + return DeclGroupPtrTy(); + case tok::semi: + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_top_level_semi : diag::ext_top_level_semi) + << FixItHint::CreateRemoval(Tok.getLocation()); + + ConsumeToken(); + // TODO: Invoke action for top-level semicolon. + return DeclGroupPtrTy(); + case tok::r_brace: + Diag(Tok, diag::err_extraneous_closing_brace); + ConsumeBrace(); + return DeclGroupPtrTy(); + case tok::eof: + Diag(Tok, diag::err_expected_external_declaration); + return DeclGroupPtrTy(); + case tok::kw___extension__: { + // __extension__ silences extension warnings in the subexpression. + ExtensionRAIIObject O(Diags); // Use RAII to do this. + ConsumeToken(); + return ParseExternalDeclaration(attrs); + } + case tok::kw_asm: { + ProhibitAttributes(attrs); + + SourceLocation StartLoc = Tok.getLocation(); + SourceLocation EndLoc; + ExprResult Result(ParseSimpleAsm(&EndLoc)); + + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, + "top-level asm block"); + + if (Result.isInvalid()) + return DeclGroupPtrTy(); + SingleDecl = Actions.ActOnFileScopeAsmDecl(Result.get(), StartLoc, EndLoc); + break; + } + case tok::at: + return ParseObjCAtDirectives(); + case tok::minus: + case tok::plus: + if (!getLangOpts().ObjC1) { + Diag(Tok, diag::err_expected_external_declaration); + ConsumeToken(); + return DeclGroupPtrTy(); + } + SingleDecl = ParseObjCMethodDefinition(); + break; + case tok::code_completion: + Actions.CodeCompleteOrdinaryName(getCurScope(), + CurParsedObjCImpl? Sema::PCC_ObjCImplementation + : Sema::PCC_Namespace); + cutOffParsing(); + return DeclGroupPtrTy(); + case tok::kw_using: + case tok::kw_namespace: + case tok::kw_typedef: + case tok::kw_template: + case tok::kw_export: // As in 'export template' + case tok::kw_static_assert: + case tok::kw__Static_assert: + // A function definition cannot start with a these keywords. + { + SourceLocation DeclEnd; + StmtVector Stmts(Actions); + return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs); + } + + case tok::kw_static: + // Parse (then ignore) 'static' prior to a template instantiation. This is + // a GCC extension that we intentionally do not support. + if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_template)) { + Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored) + << 0; + SourceLocation DeclEnd; + StmtVector Stmts(Actions); + return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs); + } + goto dont_know; + + case tok::kw_inline: + if (getLangOpts().CPlusPlus) { + tok::TokenKind NextKind = NextToken().getKind(); + + // Inline namespaces. Allowed as an extension even in C++03. + if (NextKind == tok::kw_namespace) { + SourceLocation DeclEnd; + StmtVector Stmts(Actions); + return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs); + } + + // Parse (then ignore) 'inline' prior to a template instantiation. This is + // a GCC extension that we intentionally do not support. + if (NextKind == tok::kw_template) { + Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored) + << 1; + SourceLocation DeclEnd; + StmtVector Stmts(Actions); + return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs); + } + } + goto dont_know; + + case tok::kw_extern: + if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_template)) { + // Extern templates + SourceLocation ExternLoc = ConsumeToken(); + SourceLocation TemplateLoc = ConsumeToken(); + Diag(ExternLoc, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_extern_template : + diag::ext_extern_template) << SourceRange(ExternLoc, TemplateLoc); + SourceLocation DeclEnd; + return Actions.ConvertDeclToDeclGroup( + ParseExplicitInstantiation(Declarator::FileContext, + ExternLoc, TemplateLoc, DeclEnd)); + } + // FIXME: Detect C++ linkage specifications here? + goto dont_know; + + case tok::kw___if_exists: + case tok::kw___if_not_exists: + ParseMicrosoftIfExistsExternalDeclaration(); + return DeclGroupPtrTy(); + + default: + dont_know: + // We can't tell whether this is a function-definition or declaration yet. + if (DS) { + DS->takeAttributesFrom(attrs); + return ParseDeclarationOrFunctionDefinition(*DS); + } else { + return ParseDeclarationOrFunctionDefinition(attrs); + } + } + + // This routine returns a DeclGroup, if the thing we parsed only contains a + // single decl, convert it now. + return Actions.ConvertDeclToDeclGroup(SingleDecl); +} + +/// \brief Determine whether the current token, if it occurs after a +/// declarator, continues a declaration or declaration list. +bool Parser::isDeclarationAfterDeclarator() { + // Check for '= delete' or '= default' + if (getLangOpts().CPlusPlus && Tok.is(tok::equal)) { + const Token &KW = NextToken(); + if (KW.is(tok::kw_default) || KW.is(tok::kw_delete)) + return false; + } + + return Tok.is(tok::equal) || // int X()= -> not a function def + Tok.is(tok::comma) || // int X(), -> not a function def + Tok.is(tok::semi) || // int X(); -> not a function def + Tok.is(tok::kw_asm) || // int X() __asm__ -> not a function def + Tok.is(tok::kw___attribute) || // int X() __attr__ -> not a function def + (getLangOpts().CPlusPlus && + Tok.is(tok::l_paren)); // int X(0) -> not a function def [C++] +} + +/// \brief Determine whether the current token, if it occurs after a +/// declarator, indicates the start of a function definition. +bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) { + assert(Declarator.isFunctionDeclarator() && "Isn't a function declarator"); + if (Tok.is(tok::l_brace)) // int X() {} + return true; + + // Handle K&R C argument lists: int X(f) int f; {} + if (!getLangOpts().CPlusPlus && + Declarator.getFunctionTypeInfo().isKNRPrototype()) + return isDeclarationSpecifier(); + + if (getLangOpts().CPlusPlus && Tok.is(tok::equal)) { + const Token &KW = NextToken(); + return KW.is(tok::kw_default) || KW.is(tok::kw_delete); + } + + return Tok.is(tok::colon) || // X() : Base() {} (used for ctors) + Tok.is(tok::kw_try); // X() try { ... } +} + +/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or +/// a declaration. We can't tell which we have until we read up to the +/// compound-statement in function-definition. TemplateParams, if +/// non-NULL, provides the template parameters when we're parsing a +/// C++ template-declaration. +/// +/// function-definition: [C99 6.9.1] +/// decl-specs declarator declaration-list[opt] compound-statement +/// [C90] function-definition: [C99 6.7.1] - implicit int result +/// [C90] decl-specs[opt] declarator declaration-list[opt] compound-statement +/// +/// declaration: [C99 6.7] +/// declaration-specifiers init-declarator-list[opt] ';' +/// [!C99] init-declarator-list ';' [TODO: warn in c99 mode] +/// [OMP] threadprivate-directive [TODO] +/// +Parser::DeclGroupPtrTy +Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, + AccessSpecifier AS) { + // Parse the common declaration-specifiers piece. + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level); + + // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" + // declaration-specifiers init-declarator-list[opt] ';' + if (Tok.is(tok::semi)) { + ConsumeToken(); + Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); + DS.complete(TheDecl); + return Actions.ConvertDeclToDeclGroup(TheDecl); + } + + // ObjC2 allows prefix attributes on class interfaces and protocols. + // FIXME: This still needs better diagnostics. We should only accept + // attributes here, no types, etc. + if (getLangOpts().ObjC2 && Tok.is(tok::at)) { + SourceLocation AtLoc = ConsumeToken(); // the "@" + if (!Tok.isObjCAtKeyword(tok::objc_interface) && + !Tok.isObjCAtKeyword(tok::objc_protocol)) { + Diag(Tok, diag::err_objc_unexpected_attr); + SkipUntil(tok::semi); // FIXME: better skip? + return DeclGroupPtrTy(); + } + + DS.abort(); + + const char *PrevSpec = 0; + unsigned DiagID; + if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID)) + Diag(AtLoc, DiagID) << PrevSpec; + + if (Tok.isObjCAtKeyword(tok::objc_protocol)) + return ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes()); + + return Actions.ConvertDeclToDeclGroup( + ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes())); + } + + // If the declspec consisted only of 'extern' and we have a string + // literal following it, this must be a C++ linkage specifier like + // 'extern "C"'. + if (Tok.is(tok::string_literal) && getLangOpts().CPlusPlus && + DS.getStorageClassSpec() == DeclSpec::SCS_extern && + DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { + Decl *TheDecl = ParseLinkage(DS, Declarator::FileContext); + return Actions.ConvertDeclToDeclGroup(TheDecl); + } + + return ParseDeclGroup(DS, Declarator::FileContext, true); +} + +Parser::DeclGroupPtrTy +Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs, + AccessSpecifier AS) { + ParsingDeclSpec DS(*this); + DS.takeAttributesFrom(attrs); + // Must temporarily exit the objective-c container scope for + // parsing c constructs and re-enter objc container scope + // afterwards. + ObjCDeclContextSwitch ObjCDC(*this); + + return ParseDeclarationOrFunctionDefinition(DS, AS); +} + +/// ParseFunctionDefinition - We parsed and verified that the specified +/// Declarator is well formed. If this is a K&R-style function, read the +/// parameters declaration-list, then start the compound-statement. +/// +/// function-definition: [C99 6.9.1] +/// decl-specs declarator declaration-list[opt] compound-statement +/// [C90] function-definition: [C99 6.7.1] - implicit int result +/// [C90] decl-specs[opt] declarator declaration-list[opt] compound-statement +/// [C++] function-definition: [C++ 8.4] +/// decl-specifier-seq[opt] declarator ctor-initializer[opt] +/// function-body +/// [C++] function-definition: [C++ 8.4] +/// decl-specifier-seq[opt] declarator function-try-block +/// +Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, + const ParsedTemplateInfo &TemplateInfo, + LateParsedAttrList *LateParsedAttrs) { + // Poison the SEH identifiers so they are flagged as illegal in function bodies + PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true); + const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); + + // If this is C90 and the declspecs were completely missing, fudge in an + // implicit int. We do this here because this is the only place where + // declaration-specifiers are completely optional in the grammar. + if (getLangOpts().ImplicitInt && D.getDeclSpec().isEmpty()) { + const char *PrevSpec; + unsigned DiagID; + D.getMutableDeclSpec().SetTypeSpecType(DeclSpec::TST_int, + D.getIdentifierLoc(), + PrevSpec, DiagID); + D.SetRangeBegin(D.getDeclSpec().getSourceRange().getBegin()); + } + + // If this declaration was formed with a K&R-style identifier list for the + // arguments, parse declarations for all of the args next. + // int foo(a,b) int a; float b; {} + if (FTI.isKNRPrototype()) + ParseKNRParamDeclarations(D); + + // We should have either an opening brace or, in a C++ constructor, + // we may have a colon. + if (Tok.isNot(tok::l_brace) && + (!getLangOpts().CPlusPlus || + (Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try) && + Tok.isNot(tok::equal)))) { + Diag(Tok, diag::err_expected_fn_body); + + // Skip over garbage, until we get to '{'. Don't eat the '{'. + SkipUntil(tok::l_brace, true, true); + + // If we didn't find the '{', bail out. + if (Tok.isNot(tok::l_brace)) + return 0; + } + + // Check to make sure that any normal attributes are allowed to be on + // a definition. Late parsed attributes are checked at the end. + if (Tok.isNot(tok::equal)) { + AttributeList *DtorAttrs = D.getAttributes(); + while (DtorAttrs) { + if (!IsThreadSafetyAttribute(DtorAttrs->getName()->getName())) { + Diag(DtorAttrs->getLoc(), diag::warn_attribute_on_function_definition) + << DtorAttrs->getName()->getName(); + } + DtorAttrs = DtorAttrs->getNext(); + } + } + + // In delayed template parsing mode, for function template we consume the + // tokens and store them for late parsing at the end of the translation unit. + if (getLangOpts().DelayedTemplateParsing && + TemplateInfo.Kind == ParsedTemplateInfo::Template) { + MultiTemplateParamsArg TemplateParameterLists(Actions, + TemplateInfo.TemplateParams->data(), + TemplateInfo.TemplateParams->size()); + + ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); + Scope *ParentScope = getCurScope()->getParent(); + + D.setFunctionDefinitionKind(FDK_Definition); + Decl *DP = Actions.HandleDeclarator(ParentScope, D, + move(TemplateParameterLists)); + D.complete(DP); + D.getMutableDeclSpec().abort(); + + if (DP) { + LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(DP); + + FunctionDecl *FnD = 0; + if (FunctionTemplateDecl *FunTmpl = dyn_cast(DP)) + FnD = FunTmpl->getTemplatedDecl(); + else + FnD = cast(DP); + Actions.CheckForFunctionRedefinition(FnD); + + LateParsedTemplateMap[FnD] = LPT; + Actions.MarkAsLateParsedTemplate(FnD); + LexTemplateFunctionForLateParsing(LPT->Toks); + } else { + CachedTokens Toks; + LexTemplateFunctionForLateParsing(Toks); + } + return DP; + } + + // Enter a scope for the function body. + ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); + + // Tell the actions module that we have entered a function definition with the + // specified Declarator for the function. + Decl *Res = TemplateInfo.TemplateParams? + Actions.ActOnStartOfFunctionTemplateDef(getCurScope(), + MultiTemplateParamsArg(Actions, + TemplateInfo.TemplateParams->data(), + TemplateInfo.TemplateParams->size()), + D) + : Actions.ActOnStartOfFunctionDef(getCurScope(), D); + + // Break out of the ParsingDeclarator context before we parse the body. + D.complete(Res); + + // Break out of the ParsingDeclSpec context, too. This const_cast is + // safe because we're always the sole owner. + D.getMutableDeclSpec().abort(); + + if (Tok.is(tok::equal)) { + assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='"); + ConsumeToken(); + + Actions.ActOnFinishFunctionBody(Res, 0, false); + + bool Delete = false; + SourceLocation KWLoc; + if (Tok.is(tok::kw_delete)) { + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_deleted_function : + diag::ext_deleted_function); + + KWLoc = ConsumeToken(); + Actions.SetDeclDeleted(Res, KWLoc); + Delete = true; + } else if (Tok.is(tok::kw_default)) { + Diag(Tok, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_defaulted_function : + diag::ext_defaulted_function); + + KWLoc = ConsumeToken(); + Actions.SetDeclDefaulted(Res, KWLoc); + } else { + llvm_unreachable("function definition after = not 'delete' or 'default'"); + } + + if (Tok.is(tok::comma)) { + Diag(KWLoc, diag::err_default_delete_in_multiple_declaration) + << Delete; + SkipUntil(tok::semi); + } else { + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, + Delete ? "delete" : "default", tok::semi); + } + + return Res; + } + + if (Tok.is(tok::kw_try)) + return ParseFunctionTryBlock(Res, BodyScope); + + // If we have a colon, then we're probably parsing a C++ + // ctor-initializer. + if (Tok.is(tok::colon)) { + ParseConstructorInitializer(Res); + + // Recover from error. + if (!Tok.is(tok::l_brace)) { + BodyScope.Exit(); + Actions.ActOnFinishFunctionBody(Res, 0); + return Res; + } + } else + Actions.ActOnDefaultCtorInitializers(Res); + + // Late attributes are parsed in the same scope as the function body. + if (LateParsedAttrs) + ParseLexedAttributeList(*LateParsedAttrs, Res, false, true); + + return ParseFunctionStatementBody(Res, BodyScope); +} + +/// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides +/// types for a function with a K&R-style identifier list for arguments. +void Parser::ParseKNRParamDeclarations(Declarator &D) { + // We know that the top-level of this declarator is a function. + DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); + + // Enter function-declaration scope, limiting any declarators to the + // function prototype scope, including parameter declarators. + ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); + + // Read all the argument declarations. + while (isDeclarationSpecifier()) { + SourceLocation DSStart = Tok.getLocation(); + + // Parse the common declaration-specifiers piece. + DeclSpec DS(AttrFactory); + ParseDeclarationSpecifiers(DS); + + // C99 6.9.1p6: 'each declaration in the declaration list shall have at + // least one declarator'. + // NOTE: GCC just makes this an ext-warn. It's not clear what it does with + // the declarations though. It's trivial to ignore them, really hard to do + // anything else with them. + if (Tok.is(tok::semi)) { + Diag(DSStart, diag::err_declaration_does_not_declare_param); + ConsumeToken(); + continue; + } + + // C99 6.9.1p6: Declarations shall contain no storage-class specifiers other + // than register. + if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && + DS.getStorageClassSpec() != DeclSpec::SCS_register) { + Diag(DS.getStorageClassSpecLoc(), + diag::err_invalid_storage_class_in_func_decl); + DS.ClearStorageClassSpecs(); + } + if (DS.isThreadSpecified()) { + Diag(DS.getThreadSpecLoc(), + diag::err_invalid_storage_class_in_func_decl); + DS.ClearStorageClassSpecs(); + } + + // Parse the first declarator attached to this declspec. + Declarator ParmDeclarator(DS, Declarator::KNRTypeListContext); + ParseDeclarator(ParmDeclarator); + + // Handle the full declarator list. + while (1) { + // If attributes are present, parse them. + MaybeParseGNUAttributes(ParmDeclarator); + + // Ask the actions module to compute the type for this declarator. + Decl *Param = + Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator); + + if (Param && + // A missing identifier has already been diagnosed. + ParmDeclarator.getIdentifier()) { + + // Scan the argument list looking for the correct param to apply this + // type. + for (unsigned i = 0; ; ++i) { + // C99 6.9.1p6: those declarators shall declare only identifiers from + // the identifier list. + if (i == FTI.NumArgs) { + Diag(ParmDeclarator.getIdentifierLoc(), diag::err_no_matching_param) + << ParmDeclarator.getIdentifier(); + break; + } + + if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) { + // Reject redefinitions of parameters. + if (FTI.ArgInfo[i].Param) { + Diag(ParmDeclarator.getIdentifierLoc(), + diag::err_param_redefinition) + << ParmDeclarator.getIdentifier(); + } else { + FTI.ArgInfo[i].Param = Param; + } + break; + } + } + } + + // If we don't have a comma, it is either the end of the list (a ';') or + // an error, bail out. + if (Tok.isNot(tok::comma)) + break; + + ParmDeclarator.clear(); + + // Consume the comma. + ParmDeclarator.setCommaLoc(ConsumeToken()); + + // Parse the next declarator. + ParseDeclarator(ParmDeclarator); + } + + if (Tok.is(tok::semi)) { + ConsumeToken(); + } else { + Diag(Tok, diag::err_expected_semi_declaration); + // Skip to end of block or statement + SkipUntil(tok::semi, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + } + } + + // The actions module must verify that all arguments were declared. + Actions.ActOnFinishKNRParamDeclarations(getCurScope(), D, Tok.getLocation()); +} + + +/// ParseAsmStringLiteral - This is just a normal string-literal, but is not +/// allowed to be a wide string, and is not subject to character translation. +/// +/// [GNU] asm-string-literal: +/// string-literal +/// +Parser::ExprResult Parser::ParseAsmStringLiteral() { + switch (Tok.getKind()) { + case tok::string_literal: + break; + case tok::utf8_string_literal: + case tok::utf16_string_literal: + case tok::utf32_string_literal: + case tok::wide_string_literal: { + SourceLocation L = Tok.getLocation(); + Diag(Tok, diag::err_asm_operand_wide_string_literal) + << (Tok.getKind() == tok::wide_string_literal) + << SourceRange(L, L); + return ExprError(); + } + default: + Diag(Tok, diag::err_expected_string_literal); + return ExprError(); + } + + return ParseStringLiteralExpression(); +} + +/// ParseSimpleAsm +/// +/// [GNU] simple-asm-expr: +/// 'asm' '(' asm-string-literal ')' +/// +Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { + assert(Tok.is(tok::kw_asm) && "Not an asm!"); + SourceLocation Loc = ConsumeToken(); + + if (Tok.is(tok::kw_volatile)) { + // Remove from the end of 'asm' to the end of 'volatile'. + SourceRange RemovalRange(PP.getLocForEndOfToken(Loc), + PP.getLocForEndOfToken(Tok.getLocation())); + + Diag(Tok, diag::warn_file_asm_volatile) + << FixItHint::CreateRemoval(RemovalRange); + ConsumeToken(); + } + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { + Diag(Tok, diag::err_expected_lparen_after) << "asm"; + return ExprError(); + } + + ExprResult Result(ParseAsmStringLiteral()); + + if (Result.isInvalid()) { + SkipUntil(tok::r_paren, true, true); + if (EndLoc) + *EndLoc = Tok.getLocation(); + ConsumeAnyToken(); + } else { + // Close the paren and get the location of the end bracket + T.consumeClose(); + if (EndLoc) + *EndLoc = T.getCloseLocation(); + } + + return move(Result); +} + +/// \brief Get the TemplateIdAnnotation from the token and put it in the +/// cleanup pool so that it gets destroyed when parsing the current top level +/// declaration is finished. +TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) { + assert(tok.is(tok::annot_template_id) && "Expected template-id token"); + TemplateIdAnnotation * + Id = static_cast(tok.getAnnotationValue()); + return Id; +} + +/// TryAnnotateTypeOrScopeToken - If the current token position is on a +/// typename (possibly qualified in C++) or a C++ scope specifier not followed +/// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens +/// with a single annotation token representing the typename or C++ scope +/// respectively. +/// This simplifies handling of C++ scope specifiers and allows efficient +/// backtracking without the need to re-parse and resolve nested-names and +/// typenames. +/// It will mainly be called when we expect to treat identifiers as typenames +/// (if they are typenames). For example, in C we do not expect identifiers +/// inside expressions to be treated as typenames so it will not be called +/// for expressions in C. +/// The benefit for C/ObjC is that a typename will be annotated and +/// Actions.getTypeName will not be needed to be called again (e.g. getTypeName +/// will not be called twice, once to check whether we have a declaration +/// specifier, and another one to get the actual type inside +/// ParseDeclarationSpecifiers). +/// +/// This returns true if an error occurred. +/// +/// Note that this routine emits an error if you call it with ::new or ::delete +/// as the current tokens, so only call it in contexts where these are invalid. +bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { + assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) + || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) + || Tok.is(tok::kw_decltype)) && "Cannot be a type or scope token!"); + + if (Tok.is(tok::kw_typename)) { + // Parse a C++ typename-specifier, e.g., "typename T::type". + // + // typename-specifier: + // 'typename' '::' [opt] nested-name-specifier identifier + // 'typename' '::' [opt] nested-name-specifier template [opt] + // simple-template-id + SourceLocation TypenameLoc = ConsumeToken(); + CXXScopeSpec SS; + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(), + /*EnteringContext=*/false, + 0, /*IsTypename*/true)) + return true; + if (!SS.isSet()) { + if (getLangOpts().MicrosoftExt) + Diag(Tok.getLocation(), diag::warn_expected_qualified_after_typename); + else + Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); + return true; + } + + TypeResult Ty; + if (Tok.is(tok::identifier)) { + // FIXME: check whether the next token is '<', first! + Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS, + *Tok.getIdentifierInfo(), + Tok.getLocation()); + } else if (Tok.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (TemplateId->Kind == TNK_Function_template) { + Diag(Tok, diag::err_typename_refers_to_non_type_template) + << Tok.getAnnotationRange(); + return true; + } + + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + + Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS, + TemplateId->TemplateKWLoc, + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); + } else { + Diag(Tok, diag::err_expected_type_name_after_typename) + << SS.getRange(); + return true; + } + + SourceLocation EndLoc = Tok.getLastLoc(); + Tok.setKind(tok::annot_typename); + setTypeAnnotation(Tok, Ty.isInvalid() ? ParsedType() : Ty.get()); + Tok.setAnnotationEndLoc(EndLoc); + Tok.setLocation(TypenameLoc); + PP.AnnotateCachedTokens(Tok); + return false; + } + + // Remembers whether the token was originally a scope annotation. + bool wasScopeAnnotation = Tok.is(tok::annot_cxxscope); + + CXXScopeSpec SS; + if (getLangOpts().CPlusPlus) + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) + return true; + + if (Tok.is(tok::identifier)) { + IdentifierInfo *CorrectedII = 0; + // Determine whether the identifier is a type name. + if (ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(), + Tok.getLocation(), getCurScope(), + &SS, false, + NextToken().is(tok::period), + ParsedType(), + /*IsCtorOrDtorName=*/false, + /*NonTrivialTypeSourceInfo*/true, + NeedType ? &CorrectedII : NULL)) { + // A FixIt was applied as a result of typo correction + if (CorrectedII) + Tok.setIdentifierInfo(CorrectedII); + // This is a typename. Replace the current token in-place with an + // annotation type token. + Tok.setKind(tok::annot_typename); + setTypeAnnotation(Tok, Ty); + Tok.setAnnotationEndLoc(Tok.getLocation()); + if (SS.isNotEmpty()) // it was a C++ qualified type name. + Tok.setLocation(SS.getBeginLoc()); + + // In case the tokens were cached, have Preprocessor replace + // them with the annotation token. + PP.AnnotateCachedTokens(Tok); + return false; + } + + if (!getLangOpts().CPlusPlus) { + // If we're in C, we can't have :: tokens at all (the lexer won't return + // them). If the identifier is not a type, then it can't be scope either, + // just early exit. + return false; + } + + // If this is a template-id, annotate with a template-id or type token. + if (NextToken().is(tok::less)) { + TemplateTy Template; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + bool MemberOfUnknownSpecialization; + if (TemplateNameKind TNK + = Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, TemplateName, + /*ObjectType=*/ ParsedType(), + EnteringContext, + Template, MemberOfUnknownSpecialization)) { + // Consume the identifier. + ConsumeToken(); + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName)) { + // If an unrecoverable error occurred, we need to return true here, + // because the token stream is in a damaged state. We may not return + // a valid identifier. + return true; + } + } + } + + // The current token, which is either an identifier or a + // template-id, is not part of the annotation. Fall through to + // push that token back into the stream and complete the C++ scope + // specifier annotation. + } + + if (Tok.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (TemplateId->Kind == TNK_Type_template) { + // A template-id that refers to a type was parsed into a + // template-id annotation in a context where we weren't allowed + // to produce a type annotation token. Update the template-id + // annotation token to a type annotation token now. + AnnotateTemplateIdTokenAsType(); + return false; + } + } + + if (SS.isEmpty()) + return false; + + // A C++ scope specifier that isn't followed by a typename. + // Push the current token back into the token stream (or revert it if it is + // cached) and use an annotation scope token for current token. + if (PP.isBacktrackEnabled()) + PP.RevertCachedTokens(1); + else + PP.EnterToken(Tok); + Tok.setKind(tok::annot_cxxscope); + Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS)); + Tok.setAnnotationRange(SS.getRange()); + + // In case the tokens were cached, have Preprocessor replace them + // with the annotation token. We don't need to do this if we've + // just reverted back to the state we were in before being called. + if (!wasScopeAnnotation) + PP.AnnotateCachedTokens(Tok); + return false; +} + +/// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only +/// annotates C++ scope specifiers and template-ids. This returns +/// true if the token was annotated or there was an error that could not be +/// recovered from. +/// +/// Note that this routine emits an error if you call it with ::new or ::delete +/// as the current tokens, so only call it in contexts where these are invalid. +bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { + assert(getLangOpts().CPlusPlus && + "Call sites of this function should be guarded by checking for C++"); + assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) || + Tok.is(tok::kw_decltype)) && "Cannot be a type or scope token!"); + + CXXScopeSpec SS; + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) + return true; + if (SS.isEmpty()) + return false; + + // Push the current token back into the token stream (or revert it if it is + // cached) and use an annotation scope token for current token. + if (PP.isBacktrackEnabled()) + PP.RevertCachedTokens(1); + else + PP.EnterToken(Tok); + Tok.setKind(tok::annot_cxxscope); + Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS)); + Tok.setAnnotationRange(SS.getRange()); + + // In case the tokens were cached, have Preprocessor replace them with the + // annotation token. + PP.AnnotateCachedTokens(Tok); + return false; +} + +bool Parser::isTokenEqualOrEqualTypo() { + tok::TokenKind Kind = Tok.getKind(); + switch (Kind) { + default: + return false; + case tok::ampequal: // &= + case tok::starequal: // *= + case tok::plusequal: // += + case tok::minusequal: // -= + case tok::exclaimequal: // != + case tok::slashequal: // /= + case tok::percentequal: // %= + case tok::lessequal: // <= + case tok::lesslessequal: // <<= + case tok::greaterequal: // >= + case tok::greatergreaterequal: // >>= + case tok::caretequal: // ^= + case tok::pipeequal: // |= + case tok::equalequal: // == + Diag(Tok, diag::err_invalid_token_after_declarator_suggest_equal) + << getTokenSimpleSpelling(Kind) + << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), "="); + case tok::equal: + return true; + } +} + +SourceLocation Parser::handleUnexpectedCodeCompletionToken() { + assert(Tok.is(tok::code_completion)); + PrevTokLocation = Tok.getLocation(); + + for (Scope *S = getCurScope(); S; S = S->getParent()) { + if (S->getFlags() & Scope::FnScope) { + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_RecoveryInFunction); + cutOffParsing(); + return PrevTokLocation; + } + + if (S->getFlags() & Scope::ClassScope) { + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class); + cutOffParsing(); + return PrevTokLocation; + } + } + + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace); + cutOffParsing(); + return PrevTokLocation; +} + +// Anchor the Parser::FieldCallback vtable to this translation unit. +// We use a spurious method instead of the destructor because +// destroying FieldCallbacks can actually be slightly +// performance-sensitive. +void Parser::FieldCallback::_anchor() { +} + +// Code-completion pass-through functions + +void Parser::CodeCompleteDirective(bool InConditional) { + Actions.CodeCompletePreprocessorDirective(InConditional); +} + +void Parser::CodeCompleteInConditionalExclusion() { + Actions.CodeCompleteInPreprocessorConditionalExclusion(getCurScope()); +} + +void Parser::CodeCompleteMacroName(bool IsDefinition) { + Actions.CodeCompletePreprocessorMacroName(IsDefinition); +} + +void Parser::CodeCompletePreprocessorExpression() { + Actions.CodeCompletePreprocessorExpression(); +} + +void Parser::CodeCompleteMacroArgument(IdentifierInfo *Macro, + MacroInfo *MacroInfo, + unsigned ArgumentIndex) { + Actions.CodeCompletePreprocessorMacroArgument(getCurScope(), Macro, MacroInfo, + ArgumentIndex); +} + +void Parser::CodeCompleteNaturalLanguage() { + Actions.CodeCompleteNaturalLanguage(); +} + +bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) { + assert((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists)) && + "Expected '__if_exists' or '__if_not_exists'"); + Result.IsIfExists = Tok.is(tok::kw___if_exists); + Result.KeywordLoc = ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { + Diag(Tok, diag::err_expected_lparen_after) + << (Result.IsIfExists? "__if_exists" : "__if_not_exists"); + return true; + } + + // Parse nested-name-specifier. + ParseOptionalCXXScopeSpecifier(Result.SS, ParsedType(), + /*EnteringContext=*/false); + + // Check nested-name specifier. + if (Result.SS.isInvalid()) { + T.skipToEnd(); + return true; + } + + // Parse the unqualified-id. + SourceLocation TemplateKWLoc; // FIXME: parsed, but unused. + if (ParseUnqualifiedId(Result.SS, false, true, true, ParsedType(), + TemplateKWLoc, Result.Name)) { + T.skipToEnd(); + return true; + } + + if (T.consumeClose()) + return true; + + // Check if the symbol exists. + switch (Actions.CheckMicrosoftIfExistsSymbol(getCurScope(), Result.KeywordLoc, + Result.IsIfExists, Result.SS, + Result.Name)) { + case Sema::IER_Exists: + Result.Behavior = Result.IsIfExists ? IEB_Parse : IEB_Skip; + break; + + case Sema::IER_DoesNotExist: + Result.Behavior = !Result.IsIfExists ? IEB_Parse : IEB_Skip; + break; + + case Sema::IER_Dependent: + Result.Behavior = IEB_Dependent; + break; + + case Sema::IER_Error: + return true; + } + + return false; +} + +void Parser::ParseMicrosoftIfExistsExternalDeclaration() { + IfExistsCondition Result; + if (ParseMicrosoftIfExistsCondition(Result)) + return; + + BalancedDelimiterTracker Braces(*this, tok::l_brace); + if (Braces.consumeOpen()) { + Diag(Tok, diag::err_expected_lbrace); + return; + } + + switch (Result.Behavior) { + case IEB_Parse: + // Parse declarations below. + break; + + case IEB_Dependent: + llvm_unreachable("Cannot have a dependent external declaration"); + + case IEB_Skip: + Braces.skipToEnd(); + return; + } + + // Parse the declarations. + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + DeclGroupPtrTy Result = ParseExternalDeclaration(attrs); + if (Result && !getCurScope()->getParent()) + Actions.getASTConsumer().HandleTopLevelDecl(Result.get()); + } + Braces.consumeClose(); +} + +Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) { + assert(Tok.isObjCAtKeyword(tok::objc___experimental_modules_import) && + "Improper start to module import"); + SourceLocation ImportLoc = ConsumeToken(); + + llvm::SmallVector, 2> Path; + + // Parse the module path. + do { + if (!Tok.is(tok::identifier)) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteModuleImport(ImportLoc, Path); + ConsumeCodeCompletionToken(); + SkipUntil(tok::semi); + return DeclGroupPtrTy(); + } + + Diag(Tok, diag::err_module_expected_ident); + SkipUntil(tok::semi); + return DeclGroupPtrTy(); + } + + // Record this part of the module path. + Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation())); + ConsumeToken(); + + if (Tok.is(tok::period)) { + ConsumeToken(); + continue; + } + + break; + } while (true); + + DeclResult Import = Actions.ActOnModuleImport(AtLoc, ImportLoc, Path); + ExpectAndConsumeSemi(diag::err_module_expected_semi); + if (Import.isInvalid()) + return DeclGroupPtrTy(); + + return Actions.ConvertDeclToDeclGroup(Import.get()); +} + +bool Parser::BalancedDelimiterTracker::diagnoseOverflow() { + P.Diag(P.Tok, diag::err_parser_impl_limit_overflow); + P.SkipUntil(tok::eof); + return true; +} + +bool Parser::BalancedDelimiterTracker::expectAndConsume(unsigned DiagID, + const char *Msg, + tok::TokenKind SkipToToc ) { + LOpen = P.Tok.getLocation(); + if (P.ExpectAndConsume(Kind, DiagID, Msg, SkipToToc)) + return true; + + if (getDepth() < MaxDepth) + return false; + + return diagnoseOverflow(); +} + +bool Parser::BalancedDelimiterTracker::diagnoseMissingClose() { + assert(!P.Tok.is(Close) && "Should have consumed closing delimiter"); + + const char *LHSName = "unknown"; + diag::kind DID; + switch (Close) { + default: llvm_unreachable("Unexpected balanced token"); + case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break; + case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break; + case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break; + } + P.Diag(P.Tok, DID); + P.Diag(LOpen, diag::note_matching) << LHSName; + if (P.SkipUntil(Close)) + LClose = P.Tok.getLocation(); + return true; +} + +void Parser::BalancedDelimiterTracker::skipToEnd() { + P.SkipUntil(Close, false); +} diff --git a/clang/lib/Parse/RAIIObjectsForParser.h b/clang/lib/Parse/RAIIObjectsForParser.h new file mode 100644 index 0000000..ef17aee --- /dev/null +++ b/clang/lib/Parse/RAIIObjectsForParser.h @@ -0,0 +1,142 @@ +//===--- RAIIObjectsForParser.h - RAII helpers for the parser ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines and implements the some simple RAII objects that are used +// by the parser to manage bits in recursion. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H +#define LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H + +#include "clang/Parse/ParseDiagnostic.h" + +namespace clang { + // TODO: move ParsingDeclRAIIObject here. + // TODO: move ParsingClassDefinition here. + // TODO: move TentativeParsingAction here. + + + /// ExtensionRAIIObject - This saves the state of extension warnings when + /// constructed and disables them. When destructed, it restores them back to + /// the way they used to be. This is used to handle __extension__ in the + /// parser. + class ExtensionRAIIObject { + void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT + ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT + DiagnosticsEngine &Diags; + public: + ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) { + Diags.IncrementAllExtensionsSilenced(); + } + + ~ExtensionRAIIObject() { + Diags.DecrementAllExtensionsSilenced(); + } + }; + + /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and + /// restores it when destroyed. This says that "foo:" should not be + /// considered a possible typo for "foo::" for error recovery purposes. + class ColonProtectionRAIIObject { + Parser &P; + bool OldVal; + public: + ColonProtectionRAIIObject(Parser &p, bool Value = true) + : P(p), OldVal(P.ColonIsSacred) { + P.ColonIsSacred = Value; + } + + /// restore - This can be used to restore the state early, before the dtor + /// is run. + void restore() { + P.ColonIsSacred = OldVal; + } + + ~ColonProtectionRAIIObject() { + restore(); + } + }; + + /// \brief RAII object that makes '>' behave either as an operator + /// or as the closing angle bracket for a template argument list. + class GreaterThanIsOperatorScope { + bool &GreaterThanIsOperator; + bool OldGreaterThanIsOperator; + public: + GreaterThanIsOperatorScope(bool >IO, bool Val) + : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { + GreaterThanIsOperator = Val; + } + + ~GreaterThanIsOperatorScope() { + GreaterThanIsOperator = OldGreaterThanIsOperator; + } + }; + + class InMessageExpressionRAIIObject { + bool &InMessageExpression; + bool OldValue; + + public: + InMessageExpressionRAIIObject(Parser &P, bool Value) + : InMessageExpression(P.InMessageExpression), + OldValue(P.InMessageExpression) { + InMessageExpression = Value; + } + + ~InMessageExpressionRAIIObject() { + InMessageExpression = OldValue; + } + }; + + /// \brief RAII object that makes sure paren/bracket/brace count is correct + /// after declaration/statement parsing, even when there's a parsing error. + class ParenBraceBracketBalancer { + Parser &P; + unsigned short ParenCount, BracketCount, BraceCount; + public: + ParenBraceBracketBalancer(Parser &p) + : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount), + BraceCount(p.BraceCount) { } + + ~ParenBraceBracketBalancer() { + P.ParenCount = ParenCount; + P.BracketCount = BracketCount; + P.BraceCount = BraceCount; + } + }; + + class PoisonSEHIdentifiersRAIIObject { + PoisonIdentifierRAIIObject Ident_AbnormalTermination; + PoisonIdentifierRAIIObject Ident_GetExceptionCode; + PoisonIdentifierRAIIObject Ident_GetExceptionInfo; + PoisonIdentifierRAIIObject Ident__abnormal_termination; + PoisonIdentifierRAIIObject Ident__exception_code; + PoisonIdentifierRAIIObject Ident__exception_info; + PoisonIdentifierRAIIObject Ident___abnormal_termination; + PoisonIdentifierRAIIObject Ident___exception_code; + PoisonIdentifierRAIIObject Ident___exception_info; + public: + PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue) + : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue), + Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue), + Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue), + Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue), + Ident__exception_code(Self.Ident__exception_code, NewValue), + Ident__exception_info(Self.Ident__exception_info, NewValue), + Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue), + Ident___exception_code(Self.Ident___exception_code, NewValue), + Ident___exception_info(Self.Ident___exception_info, NewValue) { + } + }; + +} // end namespace clang + +#endif -- cgit v1.2.3