diff options
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/ParseAST.cpp | 23 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 52 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 832 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 440 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 302 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 322 | ||||
-rw-r--r-- | lib/Parse/ParseInit.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 95 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.cpp | 44 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.h | 10 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 438 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 151 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 21 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 144 | ||||
-rw-r--r-- | lib/Parse/RAIIObjectsForParser.h | 26 |
15 files changed, 2299 insertions, 603 deletions
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp index edb1675..21917b2 100644 --- a/lib/Parse/ParseAST.cpp +++ b/lib/Parse/ParseAST.cpp @@ -21,6 +21,8 @@ #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 <cstdio> using namespace clang; @@ -37,8 +39,15 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, ASTContext &Ctx, bool PrintStats, bool CompleteTranslationUnit, CodeCompleteConsumer *CompletionConsumer) { - Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer); - ParseAST(S, PrintStats); + + llvm::OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer, + CompleteTranslationUnit, + CompletionConsumer)); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleaupSema(S.get()); + + ParseAST(*S.get(), PrintStats); } void clang::ParseAST(Sema &S, bool PrintStats) { @@ -50,7 +59,15 @@ void clang::ParseAST(Sema &S, bool PrintStats) { ASTConsumer *Consumer = &S.getASTConsumer(); - Parser P(S.getPreprocessor(), S); + llvm::OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S)); + Parser &P = *ParseOP.get(); + + PrettyStackTraceParserEntry CrashInfo(P); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<Parser> + CleaupParser(ParseOP.get()); + S.getPreprocessor().EnterMainSourceFile(); P.Initialize(); S.Initialize(); diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 3994738..87e2f34 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -15,6 +15,7 @@ #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 @@ -37,13 +38,6 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, true, move(TemplateParams)); else { // FIXME: pass template information through - if (VS.isOverrideSpecified()) - Diag(VS.getOverrideLoc(), diag::ext_override_inline) << "override"; - if (VS.isFinalSpecified()) - Diag(VS.getFinalLoc(), diag::ext_override_inline) << "final"; - if (VS.isNewSpecified()) - Diag(VS.getNewLoc(), diag::ext_override_inline) << "new"; - FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D, move(TemplateParams), 0, VS, 0, /*IsDefinition*/true); @@ -53,6 +47,37 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, D.complete(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 (getLang().DelayedTemplateParsing && + ((Actions.CurContext->isDependentContext() || + TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) && + !Actions.IsInsideALocalClassWithinATemplateFunction()) && + !D.getDeclSpec().isFriendSpecified()) { + + if (FnD) { + LateParsedTemplatedFunction *LPT = + new LateParsedTemplatedFunction(this, FnD); + + FunctionDecl *FD = 0; + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(FnD)) + FD = FunTmpl->getTemplatedDecl(); + else + FD = cast<FunctionDecl>(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); @@ -94,6 +119,14 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, } } + + 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; } @@ -261,7 +294,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D); if (Tok.is(tok::kw_try)) { - ParseFunctionTryBlock(LM.D); + ParseFunctionTryBlock(LM.D, FnScope); assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, Tok.getLocation()) && "ParseFunctionTryBlock went over the cached tokens!"); @@ -276,13 +309,14 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { // Error recovery. if (!Tok.is(tok::l_brace)) { + FnScope.Exit(); Actions.ActOnFinishFunctionBody(LM.D, 0); return; } } else Actions.ActOnDefaultCtorInitializers(LM.D); - ParseFunctionStatementBody(LM.D); + ParseFunctionStatementBody(LM.D, FnScope); if (Tok.getLocation() != origLoc) { // Due to parsing error, we either went over the cached tokens or diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 077edd7..a20e90b 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -13,6 +13,7 @@ #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" @@ -32,7 +33,7 @@ using namespace clang; TypeResult Parser::ParseTypeName(SourceRange *Range, Declarator::TheContext Context) { // Parse the common declaration-specifiers piece. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); // Parse the abstract-declarator, if present. @@ -111,8 +112,11 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); + // Availability attributes have their own grammar. + if (AttrName->isStr("availability")) + ParseAvailabilityAttribute(*AttrName, AttrNameLoc, attrs, endLoc); // check if we have a "parameterized" attribute - if (Tok.is(tok::l_paren)) { + else if (Tok.is(tok::l_paren)) { ConsumeParen(); // ignore the left paren loc for now if (Tok.is(tok::identifier)) { @@ -122,8 +126,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, if (Tok.is(tok::r_paren)) { // __attribute__(( mode(byte) )) ConsumeParen(); // ignore the right paren loc for now - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, - ParmName, ParmLoc, 0, 0)); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + ParmName, ParmLoc, 0, 0); } else if (Tok.is(tok::comma)) { ConsumeToken(); // __attribute__(( format(printf, 1, 2) )) @@ -146,9 +150,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, } if (ArgExprsOk && Tok.is(tok::r_paren)) { ConsumeParen(); // ignore the right paren loc for now - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, - AttrNameLoc, ParmName, ParmLoc, - ArgExprs.take(), ArgExprs.size())); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size()); } } } else { // not an identifier @@ -157,8 +160,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, // parse a possibly empty comma separated list of expressions // __attribute__(( nonnull() )) ConsumeParen(); // ignore the right paren loc for now - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0)); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0); break; case tok::kw_char: case tok::kw_wchar_t: @@ -168,6 +171,7 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, case tok::kw_short: case tok::kw_int: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_float: @@ -175,9 +179,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, case tok::kw_void: case tok::kw_typeof: { AttributeList *attr - = AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0); - attrs.add(attr); + = attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0); if (attr->getKind() == AttributeList::AT_IBOutletCollection) Diag(Tok, diag::err_iboutletcollection_builtintype); // If it's a builtin type name, eat it and expect a rparen @@ -209,16 +212,16 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, // Match the ')'. if (ArgExprsOk && Tok.is(tok::r_paren)) { ConsumeParen(); // ignore the right paren loc for now - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, - AttrNameLoc, 0, SourceLocation(), - ArgExprs.take(), ArgExprs.size())); + attrs.addNew(AttrName, AttrNameLoc, 0, + AttrNameLoc, 0, SourceLocation(), + ArgExprs.take(), ArgExprs.size()); } break; } } } else { - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0)); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) @@ -260,14 +263,14 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) { ExprResult ArgExpr(ParseAssignmentExpression()); if (!ArgExpr.isInvalid()) { Expr *ExprList = ArgExpr.take(); - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), &ExprList, 1, true)); + 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.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0, true)); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0, true); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) @@ -286,8 +289,8 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64)) // FIXME: Support these properly! continue; - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, true)); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, true); } } @@ -296,8 +299,8 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___pascal)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, true)); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, true); } } @@ -305,12 +308,334 @@ void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) { // Treat these like attributes while (Tok.is(tok::kw___kernel)) { SourceLocation AttrNameLoc = ConsumeToken(); - attrs.add(AttrFactory.Create(PP.getIdentifierInfo("opencl_kernel_function"), - AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, false)); + 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. + llvm::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 ')' +/// +/// platform: +/// identifier +/// +/// version-arg-list: +/// version-arg +/// version-arg ',' version-arg-list +/// +/// version-arg: +/// 'introduced' '=' version +/// 'deprecated' '=' version +/// 'removed' = version +/// 'unavailable' +void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, + SourceLocation AvailabilityLoc, + ParsedAttributes &attrs, + SourceLocation *endLoc) { + SourceLocation PlatformLoc; + IdentifierInfo *Platform = 0; + + enum { Introduced, Deprecated, Obsoleted, Unknown }; + AvailabilityChange Changes[Unknown]; + + // Opening '('. + SourceLocation LParenLoc; + if (!Tok.is(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen); + return; + } + LParenLoc = ConsumeParen(); + + // 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"); + } + + // 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(); + + 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 ')'. + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + if (RParenLoc.isInvalid()) + return; + + if (endLoc) + *endLoc = RParenLoc; + + // 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, AvailabilityLoc, + 0, SourceLocation(), + Platform, PlatformLoc, + Changes[Introduced], + Changes[Deprecated], + Changes[Obsoleted], + UnavailableLoc, false, false); +} + void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) << attrs.Range; @@ -329,7 +654,7 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { /// [C++] namespace-definition /// [C++] using-directive /// [C++] using-declaration -/// [C++0x] static_assert-declaration +/// [C++0x/C1X] static_assert-declaration /// others... [FIXME] /// Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, @@ -364,6 +689,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, DeclEnd, attrs); break; case tok::kw_static_assert: + case tok::kw__Static_assert: ProhibitAttributes(attrs); SingleDecl = ParseStaticAssertDeclaration(DeclEnd); break; @@ -381,33 +707,42 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, ///[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) { + bool RequireSemi, + ForRangeInit *FRI) { // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); DS.takeAttributesFrom(attrs); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, getDeclSpecContextFromDeclaratorContext(Context)); StmtResult R = Actions.ActOnVlaStmt(DS); if (R.isUsable()) Stmts.push_back(R.release()); - + // 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); DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } - - return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd); + + return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI); } /// ParseDeclGroup - Having concluded that this is either a function @@ -416,7 +751,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts, Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, bool AllowFunctionDefinitions, - SourceLocation *DeclEnd) { + SourceLocation *DeclEnd, + ForRangeInit *FRI) { // Parse the first declarator. ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Context)); ParseDeclarator(D); @@ -462,8 +798,24 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } } + if (ParseAttributesAfterDeclarator(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(); + // FIXME: handle braced-init-list here. + FRI->RangeExpr = ParseExpression(); + Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); + Actions.ActOnCXXForRangeDecl(ThisDecl); + Actions.FinalizeDeclaration(ThisDecl); + return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1); + } + llvm::SmallVector<Decl *, 8> DeclsInGroup; - Decl *FirstDecl = ParseDeclarationAfterDeclarator(D); + Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D); D.complete(FirstDecl); if (FirstDecl) DeclsInGroup.push_back(FirstDecl); @@ -517,6 +869,26 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, DeclsInGroup.size()); } +/// Parse an optional simple-asm-expr and attributes, and attach them to a +/// declarator. Returns true on an error. +bool Parser::ParseAttributesAfterDeclarator(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 @@ -540,21 +912,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, /// Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, const ParsedTemplateInfo &TemplateInfo) { - // 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 0; - } - - D.setAsmLabel(AsmLabel.release()); - D.SetRangeEnd(Loc); - } + if (ParseAttributesAfterDeclarator(D)) + return 0; - MaybeParseGNUAttributes(D); + 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) { @@ -780,21 +1145,25 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // // C++ doesn't need this, and isTagName doesn't take SS. if (SS == 0) { - const char *TagName = 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" ;TagKind=tok::kw_enum ;break; - case DeclSpec::TST_union: TagName="union" ;TagKind=tok::kw_union ;break; - case DeclSpec::TST_struct:TagName="struct";TagKind=tok::kw_struct;break; - case DeclSpec::TST_class: TagName="class" ;TagKind=tok::kw_class ;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 << getLang().CPlusPlus - << FixItHint::CreateInsertion(Tok.getLocation(),TagName); + << FixItHint::CreateInsertion(Tok.getLocation(),FixitTagName); // Parse this as a tag as if the missing tag were present. if (TagKind == tok::kw_enum) @@ -887,9 +1256,12 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, - DeclSpecContext DSContext) { - DS.SetRangeStart(Tok.getLocation()); - DS.SetRangeEnd(Tok.getLocation()); + DeclSpecContext DSContext) { + if (DS.getSourceRange().isInvalid()) { + DS.SetRangeStart(Tok.getLocation()); + DS.SetRangeEnd(Tok.getLocation()); + } + while (1) { bool isInvalid = false; const char *PrevSpec = 0; @@ -1013,7 +1385,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ConsumeToken(); // The C++ scope. assert(Tok.is(tok::annot_template_id) && "ParseOptionalCXXScopeSpecifier not working"); - AnnotateTemplateIdTokenAsType(&SS); + AnnotateTemplateIdTokenAsType(); continue; } @@ -1056,7 +1428,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParsedType TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(), - getCurScope(), &SS); + getCurScope(), &SS, + false, false, ParsedType(), + /*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 @@ -1105,6 +1479,24 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &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::identifier: { // In C++, check to see if this is a scope specifier like foo::bar::, if @@ -1247,7 +1639,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DiagID, getLang()); break; case tok::kw_auto: - if (getLang().CPlusPlus0x || getLang().ObjC2) { + if (getLang().CPlusPlus0x) { if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec, DiagID, getLang()); @@ -1315,6 +1707,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, 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); @@ -1370,6 +1766,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, 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, @@ -1394,6 +1792,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, 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: @@ -1444,6 +1846,20 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParseDecltypeSpecifier(DS); continue; + // OpenCL qualifiers: + case tok::kw_private: + if (!getLang().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 "<SomeProtocol>" as a synonym for // "id<SomeProtocol>". This is hopelessly old fashioned and dangerous, @@ -1473,7 +1889,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } DS.SetRangeEnd(Tok.getLocation()); - ConsumeToken(); + if (DiagID != diag::err_bool_redeclaration) + ConsumeToken(); } } @@ -1592,6 +2009,10 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, 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; @@ -1695,6 +2116,20 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, ParseDecltypeSpecifier(DS); return true; + // OpenCL qualifiers: + case tok::kw_private: + if (!getLang().OpenCL) + return false; + 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; + // C++0x auto support. case tok::kw_auto: if (!getLang().CPlusPlus0x) @@ -1856,7 +2291,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, } // Parse all the comma separated declarators. - DeclSpec DS; + DeclSpec DS(AttrFactory); if (!Tok.is(tok::at)) { struct CFieldCallback : FieldCallback { @@ -1917,7 +2352,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); // If attributes exist after struct contents, parse them. MaybeParseGNUAttributes(attrs); @@ -1967,7 +2402,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, } // If attributes exist after tag, parse them. - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); CXXScopeSpec &SS = DS.getTypeSpecScope(); @@ -2121,7 +2556,6 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, bool Owned = false; bool IsDependent = false; - SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; const char *PrevSpec = 0; unsigned DiagID; Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, @@ -2148,8 +2582,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } - if (DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, PrevSpec, DiagID, - Type.get())) + if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, + PrevSpec, DiagID, Type.get())) Diag(StartLoc, DiagID) << PrevSpec; return; @@ -2170,10 +2605,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (Tok.is(tok::l_brace)) ParseEnumBody(StartLoc, TagDecl); - // FIXME: The DeclSpec should keep the locations of both the keyword - // and the name (if there is one). - if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID, - TagDecl, Owned)) + if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, + PrevSpec, DiagID, TagDecl, Owned)) Diag(StartLoc, DiagID) << PrevSpec; } @@ -2208,7 +2642,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { SourceLocation IdentLoc = ConsumeToken(); // If attributes exist after the enumerator, parse them. - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); SourceLocation EqualLoc; @@ -2252,7 +2686,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); // If attributes exist after the identifier list, parse them. - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl, @@ -2268,10 +2702,22 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { bool Parser::isTypeQualifier() const { switch (Tok.getKind()) { default: return false; + + // type-qualifier only in OpenCL + case tok::kw_private: + return getLang().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; } } @@ -2285,6 +2731,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { // type-specifiers case tok::kw_short: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw__Complex: @@ -2353,6 +2800,7 @@ bool Parser::isTypeSpecifierQualifier() { // type-specifiers case tok::kw_short: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw__Complex: @@ -2399,7 +2847,19 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw___w64: case tok::kw___ptr64: case tok::kw___pascal: + + 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 getLang().OpenCL; } } @@ -2412,6 +2872,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { switch (Tok.getKind()) { default: return false; + case tok::kw_private: + return getLang().OpenCL; + case tok::identifier: // foo::bar // Unfortunate hack to support "Class.factoryMethod" notation. if (getLang().ObjC1 && NextToken().is(tok::period)) @@ -2461,6 +2924,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { // type-specifiers case tok::kw_short: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw__Complex: @@ -2498,8 +2962,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_virtual: case tok::kw_explicit: - // typedef-name - case tok::annot_typename: + // static_assert-declaration + case tok::kw__Static_assert: // GNU typeof support. case tok::kw_typeof: @@ -2512,6 +2976,11 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::less: return getLang().ObjC1; + // typedef-name + case tok::annot_typename: + return !DisambiguatingWithExpression || + !isStartOfObjCClassMessageMissingOpenBracket(); + case tok::kw___declspec: case tok::kw___cdecl: case tok::kw___stdcall: @@ -2521,6 +2990,15 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw___ptr64: case tok::kw___forceinline: case tok::kw___pascal: + + 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; } } @@ -2564,7 +3042,7 @@ bool Parser::isConstructorDeclarator() { DeclScopeObj.EnterDeclaratorScope(); // Optionally skip Microsoft attributes. - ParsedAttributes Attrs; + ParsedAttributes Attrs(AttrFactory); MaybeParseMicrosoftAttributes(Attrs); // Check whether the next token(s) are part of a declaration @@ -2592,14 +3070,16 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool CXX0XAttributesAllowed) { if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { SourceLocation Loc = Tok.getLocation(); - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); ParseCXX0XAttributes(attrs); if (CXX0XAttributesAllowed) DS.takeAttributesFrom(attrs); else Diag(Loc, diag::err_attributes_not_allowed); } - + + SourceLocation EndLoc; + while (1) { bool isInvalid = false; const char *PrevSpec = 0; @@ -2624,6 +3104,21 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, getLang()); break; + + // OpenCL qualifiers: + case tok::kw_private: + if (!getLang().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___cdecl: @@ -2652,6 +3147,8 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, // 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; } @@ -2660,7 +3157,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, assert(PrevSpec && "Method did not return previous specifier!"); Diag(Tok, DiagID) << PrevSpec; } - ConsumeToken(); + EndLoc = ConsumeToken(); } } @@ -2719,7 +3216,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, SourceLocation Loc = ConsumeToken(); D.SetRangeEnd(Loc); - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseTypeQualifierListOpt(DS); D.ExtendWithDeclSpec(DS); @@ -2729,7 +3226,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // 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.takeAttributes()), + Loc), + DS.getAttributes(), /* Don't replace range end. */SourceLocation()); return; } @@ -2753,7 +3251,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, if (Kind == tok::star || Kind == tok::caret) { // Is a pointer. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseTypeQualifierListOpt(DS); D.ExtendWithDeclSpec(DS); @@ -2765,17 +3263,18 @@ void Parser::ParseDeclaratorInternal(Declarator &D, D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc, DS.getConstSpecLoc(), DS.getVolatileSpecLoc(), - DS.getRestrictSpecLoc(), - DS.takeAttributes()), + 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.takeAttributes()), + Loc), + DS.getAttributes(), SourceLocation()); } else { // Is a reference - DeclSpec DS; + DeclSpec DS(AttrFactory); // Complain about rvalue references in C++03, but then go on and build // the declarator. @@ -2823,8 +3322,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // Remember that we parsed a reference type. It doesn't have type-quals. D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc, - DS.takeAttributes(), Kind == tok::amp), + DS.getAttributes(), SourceLocation()); } } @@ -2989,7 +3488,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (!isCXXFunctionDeclarator(warnIfAmbiguous)) break; } - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); ParseFunctionDeclarator(ConsumeParen(), D, attrs); } else if (Tok.is(tok::l_square)) { ParseBracketDeclarator(D); @@ -3026,7 +3525,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { // In either case, we need to eat any attributes to be able to determine what // sort of paren this is. // - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); bool RequiresArg = false; if (Tok.is(tok::kw___attribute)) { ParseGNUAttributes(attrs); @@ -3072,13 +3571,12 @@ void Parser::ParseParenDeclarator(Declarator &D) { if (isGrouping) { bool hadGroupingParens = D.hasGroupingParens(); D.setGroupingParens(true); - if (!attrs.empty()) - D.addAttributes(attrs.getList(), SourceLocation()); ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); // Match the ')'. SourceLocation EndLoc = MatchRHSPunctuation(tok::r_paren, StartLoc); - D.AddTypeInfo(DeclaratorChunk::getParen(StartLoc, EndLoc), EndLoc); + D.AddTypeInfo(DeclaratorChunk::getParen(StartLoc, EndLoc), + attrs, EndLoc); D.setGroupingParens(hadGroupingParens); return; @@ -3125,6 +3623,10 @@ void Parser::ParseParenDeclarator(Declarator &D) { /// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]", /// C++0x "ref-qualifier[opt]" and "exception-specification[opt]". /// +/// [C++0x] exception-specification: +/// dynamic-exception-specification +/// noexcept-specification +/// void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, ParsedAttributes &attrs, bool RequiresArg) { @@ -3138,18 +3640,17 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); - SourceLocation RParenLoc = ConsumeParen(); // Eat the closing ')'. - SourceLocation EndLoc = RParenLoc; + SourceLocation EndLoc = ConsumeParen(); // Eat the closing ')'. // cv-qualifier-seq[opt]. - DeclSpec DS; + DeclSpec DS(AttrFactory); SourceLocation RefQualifierLoc; bool RefQualifierIsLValueRef = true; - bool hasExceptionSpec = false; - SourceLocation ThrowLoc; - bool hasAnyExceptionSpec = false; - llvm::SmallVector<ParsedType, 2> Exceptions; - llvm::SmallVector<SourceRange, 2> ExceptionRanges; + ExceptionSpecificationType ESpecType = EST_None; + SourceRange ESpecRange; + llvm::SmallVector<ParsedType, 2> DynamicExceptions; + llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges; + ExprResult NoexceptExpr; if (getLang().CPlusPlus) { MaybeParseCXX0XAttributes(attrs); @@ -3161,21 +3662,19 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { if (!getLang().CPlusPlus0x) Diag(Tok, diag::ext_ref_qualifier); - + RefQualifierIsLValueRef = Tok.is(tok::amp); RefQualifierLoc = ConsumeToken(); EndLoc = RefQualifierLoc; } - + // Parse exception-specification[opt]. - if (Tok.is(tok::kw_throw)) { - hasExceptionSpec = true; - ThrowLoc = Tok.getLocation(); - ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges, - hasAnyExceptionSpec); - assert(Exceptions.size() == ExceptionRanges.size() && - "Produced different number of exception types and ranges."); - } + ESpecType = MaybeParseExceptionSpecification(ESpecRange, + DynamicExceptions, + DynamicExceptionRanges, + NoexceptExpr); + if (ESpecType != EST_None) + EndLoc = ESpecRange.getEnd(); // Parse trailing-return-type. if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) { @@ -3185,22 +3684,22 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Remember that we parsed a function type, and remember the attributes. // int() -> no prototype, no '...'. - D.AddTypeInfo(DeclaratorChunk::getFunction(attrs, - /*prototype*/getLang().CPlusPlus, + D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/getLang().CPlusPlus, /*variadic*/ false, SourceLocation(), /*arglist*/ 0, 0, DS.getTypeQualifiers(), RefQualifierIsLValueRef, RefQualifierLoc, - hasExceptionSpec, ThrowLoc, - hasAnyExceptionSpec, - Exceptions.data(), - ExceptionRanges.data(), - Exceptions.size(), - LParenLoc, RParenLoc, D, + ESpecType, ESpecRange.getBegin(), + DynamicExceptions.data(), + DynamicExceptionRanges.data(), + DynamicExceptions.size(), + NoexceptExpr.isUsable() ? + NoexceptExpr.get() : 0, + LParenLoc, EndLoc, D, TrailingReturnType), - EndLoc); + attrs, EndLoc); return; } @@ -3264,7 +3763,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Parse the declaration-specifiers. // Just use the ParsingDeclaration "scope" of the declarator. - DeclSpec DS; + DeclSpec DS(AttrFactory); // Skip any Microsoft attributes before a param. if (getLang().Microsoft && Tok.is(tok::l_square)) @@ -3388,17 +3887,16 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, } // If we have the closing ')', eat it. - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - SourceLocation EndLoc = RParenLoc; + SourceLocation EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - DeclSpec DS; + DeclSpec DS(AttrFactory); SourceLocation RefQualifierLoc; bool RefQualifierIsLValueRef = true; - bool hasExceptionSpec = false; - SourceLocation ThrowLoc; - bool hasAnyExceptionSpec = false; - llvm::SmallVector<ParsedType, 2> Exceptions; - llvm::SmallVector<SourceRange, 2> ExceptionRanges; + ExceptionSpecificationType ESpecType = EST_None; + SourceRange ESpecRange; + llvm::SmallVector<ParsedType, 2> DynamicExceptions; + llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges; + ExprResult NoexceptExpr; if (getLang().CPlusPlus) { MaybeParseCXX0XAttributes(attrs); @@ -3418,15 +3916,17 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, EndLoc = RefQualifierLoc; } + // FIXME: We should leave the prototype scope before parsing the exception + // specification, and then reenter it when parsing the trailing return type. + // FIXMEFIXME: Why? That wouldn't be right for the noexcept clause. + // Parse exception-specification[opt]. - if (Tok.is(tok::kw_throw)) { - hasExceptionSpec = true; - ThrowLoc = Tok.getLocation(); - ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges, - hasAnyExceptionSpec); - assert(Exceptions.size() == ExceptionRanges.size() && - "Produced different number of exception types and ranges."); - } + ESpecType = MaybeParseExceptionSpecification(ESpecRange, + DynamicExceptions, + DynamicExceptionRanges, + NoexceptExpr); + if (ESpecType != EST_None) + EndLoc = ESpecRange.getEnd(); // Parse trailing-return-type. if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) { @@ -3434,28 +3934,25 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, } } - // FIXME: We should leave the prototype scope before parsing the exception - // specification, and then reenter it when parsing the trailing return type. - // Leave prototype scope. PrototypeScope.Exit(); // Remember that we parsed a function type, and remember the attributes. - D.AddTypeInfo(DeclaratorChunk::getFunction(attrs, - /*proto*/true, IsVariadic, + D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic, EllipsisLoc, ParamInfo.data(), ParamInfo.size(), DS.getTypeQualifiers(), RefQualifierIsLValueRef, RefQualifierLoc, - hasExceptionSpec, ThrowLoc, - hasAnyExceptionSpec, - Exceptions.data(), - ExceptionRanges.data(), - Exceptions.size(), - LParenLoc, RParenLoc, D, + ESpecType, ESpecRange.getBegin(), + DynamicExceptions.data(), + DynamicExceptionRanges.data(), + DynamicExceptions.size(), + NoexceptExpr.isUsable() ? + NoexceptExpr.get() : 0, + LParenLoc, EndLoc, D, TrailingReturnType), - EndLoc); + attrs, EndLoc); } /// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator @@ -3524,16 +4021,15 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, // Remember that we parsed a function type, and remember the attributes. This // function type is always a K&R style function type, which is not varargs and // has no prototype. - D.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(), - /*proto*/false, /*varargs*/false, + ParsedAttributes attrs(AttrFactory); + D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false, SourceLocation(), &ParamInfo[0], ParamInfo.size(), /*TypeQuals*/0, true, SourceLocation(), - /*exception*/false, - SourceLocation(), false, 0, 0, 0, - LParenLoc, RLoc, D), - RLoc); + EST_None, SourceLocation(), 0, 0, + 0, 0, LParenLoc, RLoc, D), + attrs, RLoc); } /// [C90] direct-declarator '[' constant-expression[opt] ']' @@ -3548,14 +4044,14 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // This code does a fast path to handle some of the most obvious cases. if (Tok.getKind() == tok::r_square) { SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // Remember that we parsed the empty array type. ExprResult NumElements; - D.AddTypeInfo(DeclaratorChunk::getArray(0, attrs, false, false, 0, + D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, StartLoc, EndLoc), - EndLoc); + attrs, EndLoc); return; } else if (Tok.getKind() == tok::numeric_constant && GetLookAheadToken(1).is(tok::r_square)) { @@ -3564,14 +4060,14 @@ void Parser::ParseBracketDeclarator(Declarator &D) { ConsumeToken(); SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // Remember that we parsed a array type, and remember its features. - D.AddTypeInfo(DeclaratorChunk::getArray(0, attrs, false, 0, + D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0, ExprRes.release(), StartLoc, EndLoc), - EndLoc); + attrs, EndLoc); return; } @@ -3582,7 +4078,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // If there is a type-qualifier-list, read it now. // Type qualifiers in an array subscript are a C99 feature. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseTypeQualifierListOpt(DS, false /*no attributes*/); // If we haven't already read 'static', check to see if there is one after the @@ -3630,15 +4126,15 @@ void Parser::ParseBracketDeclarator(Declarator &D) { SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // Remember that we parsed a array type, and remember its features. - D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), attrs, + D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), StaticLoc.isValid(), isStar, NumElements.release(), StartLoc, EndLoc), - EndLoc); + attrs, EndLoc); } /// [GNU] typeof-specifier: @@ -3656,10 +4152,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { bool isCastExpr; ParsedType CastTy; SourceRange CastRange; - ExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok, - isCastExpr, - CastTy, - CastRange); + ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, + CastTy, CastRange); if (hasParens) DS.setTypeofParensRange(CastRange); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index b3ad25b..8c0aa1b 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -69,11 +69,9 @@ Decl *Parser::ParseNamespace(unsigned Context, } // Read label attributes, if present. - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); if (Tok.is(tok::kw___attribute)) { attrTok = Tok; - - // FIXME: save these somewhere. ParseGNUAttributes(attrs); } @@ -111,14 +109,14 @@ Decl *Parser::ParseNamespace(unsigned Context, ParseScope NamespaceScope(this, Scope::DeclScope); Decl *NamespcDecl = - Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, IdentLoc, Ident, - LBrace, attrs.getList()); + Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, NamespaceLoc, + IdentLoc, Ident, LBrace, attrs.getList()); PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc, "parsing namespace"); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); ParseExternalDeclaration(attrs); @@ -138,9 +136,9 @@ Decl *Parser::ParseNamespace(unsigned Context, /// alias definition. /// Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, - SourceLocation AliasLoc, - IdentifierInfo *Alias, - SourceLocation &DeclEnd) { + SourceLocation AliasLoc, + IdentifierInfo *Alias, + SourceLocation &DeclEnd) { assert(Tok.is(tok::equal) && "Not equal token"); ConsumeToken(); // eat the '='. @@ -194,16 +192,21 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { ParseScope LinkageScope(this, Scope::DeclScope); Decl *LinkageSpec = Actions.ActOnStartLinkageSpecification(getCurScope(), - /*FIXME: */SourceLocation(), + DS.getSourceRange().getBegin(), Loc, Lang, - Tok.is(tok::l_brace)? Tok.getLocation() + Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation()); - ParsedAttributesWithRange attrs; + 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, @@ -216,7 +219,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { SourceLocation LBrace = ConsumeBrace(); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); ParseExternalDeclaration(attrs); @@ -255,7 +258,7 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, return ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs); } - // Otherwise, it must be a using-declaration. + // Otherwise, it must be a using-declaration or an alias-declaration. // Using declarations can't have attributes. ProhibitAttributes(attrs); @@ -325,14 +328,17 @@ Decl *Parser::ParseUsingDirective(unsigned Context, IdentLoc, NamespcName, attrs.getList()); } -/// ParseUsingDeclaration - Parse C++ using-declaration. Assumes that -/// 'using' was already seen. +/// 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, @@ -342,10 +348,6 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, SourceLocation TypenameLoc; bool IsTypeName; - // TODO: in C++0x, if we have template parameters this must be a - // template alias: - // template <...> using id = type; - // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. if (Tok.is(tok::kw_typename)) { @@ -379,17 +381,48 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } - // Parse (optional) attributes (most likely GNU strong-using extension). - ParsedAttributes attrs; - MaybeParseGNUAttributes(attrs); + ParsedAttributes attrs(AttrFactory); + + // Maybe this is an alias-declaration. + bool IsAliasDecl = Tok.is(tok::equal); + TypeResult TypeAlias; + if (IsAliasDecl) { + // TODO: Do we want to support attributes somewhere in an alias declaration? + // Can't follow GCC since it doesn't support them yet! + ConsumeToken(); + + if (!getLang().CPlusPlus0x) + Diag(Tok.getLocation(), diag::ext_alias_declaration); + + // 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, Declarator::AliasDeclContext); + } 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" : "using declaration", + !attrs.empty() ? "attributes list" : + IsAliasDecl ? "alias declaration" : "using declaration", tok::semi); // Diagnose an attempt to declare a templated using-declaration. + // TODO: in C++0x, alias-declarations can be templates: + // template <...> using id = type; if (TemplateInfo.Kind) { SourceRange R = TemplateInfo.getSourceRange(); Diag(UsingLoc, diag::err_templated_using_declaration) @@ -401,18 +434,30 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } + if (IsAliasDecl) + return Actions.ActOnAliasDeclaration(getCurScope(), AS, UsingLoc, Name, + TypeAlias); + return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, Name, attrs.getList(), IsTypeName, TypenameLoc); } -/// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion. +/// ParseStaticAssertDeclaration - Parse C++0x or C1X static_assert-declaration. +/// +/// [C++0x] static_assert-declaration: +/// static_assert ( constant-expression , string-literal ) ; /// -/// static_assert-declaration: -/// static_assert ( constant-expression , string-literal ) ; +/// [C1X] static_assert-declaration: +/// _Static_assert ( constant-expression , string-literal ) ; /// Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ - assert(Tok.is(tok::kw_static_assert) && "Not a static_assert declaration"); + 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) && !getLang().C1X) + Diag(Tok, diag::ext_c1x_static_assert); + SourceLocation StaticAssertLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) { @@ -441,14 +486,15 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ if (AssertMessage.isInvalid()) return 0; - MatchRHSPunctuation(tok::r_paren, LParenLoc); + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); DeclEnd = Tok.getLocation(); ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert); return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, AssertExpr.take(), - AssertMessage.take()); + AssertMessage.take(), + RParenLoc); } /// ParseDecltypeSpecifier - Parse a C++0x decltype specifier. @@ -508,14 +554,14 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { /// simple-template-id /// Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, - CXXScopeSpec *SS) { + CXXScopeSpec &SS) { // Check whether we have a template-id that names a type. if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); if (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) { - AnnotateTemplateIdTokenAsType(SS); + AnnotateTemplateIdTokenAsType(); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); ParsedType Type = getTypeAnnotation(Tok); @@ -544,7 +590,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, TemplateNameKind TNK = TNK_Type_template; TemplateTy Template; if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, getCurScope(), - SS, Template, TNK)) { + &SS, Template, TNK)) { Diag(IdLoc, diag::err_unknown_template_name) << Id; } @@ -561,7 +607,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, SourceLocation(), true)) return true; if (TNK == TNK_Dependent_template_name) - AnnotateTemplateIdTokenAsType(SS); + AnnotateTemplateIdTokenAsType(); // If we didn't end up with a typename token, there's nothing more we // can do. @@ -577,7 +623,9 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, } // We have an identifier; check whether it is actually a type. - ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), SS, true); + ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true, + false, ParsedType(), + /*NonTrivialTypeSourceInfo=*/true); if (!Type) { Diag(IdLoc, diag::err_expected_class_name); return true; @@ -587,10 +635,10 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, EndLocation = IdLoc; // Fake up a Declarator to use with ActOnTypeName. - DeclSpec DS; + DeclSpec DS(AttrFactory); DS.SetRangeStart(IdLoc); DS.SetRangeEnd(EndLocation); - DS.getTypeSpecScope() = *SS; + DS.getTypeSpecScope() = SS; const char *PrevSpec = 0; unsigned DiagID; @@ -674,7 +722,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SuppressingAccessChecks = true; } - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) ParseGNUAttributes(attrs); @@ -688,22 +736,30 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // styles of attributes? MaybeParseCXX0XAttributes(attrs); - if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_pod)) { - // GNU libstdc++ 4.2 uses __is_pod as the name of a struct template, but - // __is_pod is a keyword in GCC >= 4.3. Therefore, when we see the - // token sequence "struct __is_pod", make __is_pod into a normal - // identifier rather than a keyword, to allow libstdc++ 4.2 to work - // properly. - Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); - Tok.setKind(tok::identifier); - } - - if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_empty)) { - // GNU libstdc++ 4.2 uses __is_empty as the name of a struct template, but - // __is_empty is a keyword in GCC >= 4.3. Therefore, when we see the - // token sequence "struct __is_empty", make __is_empty into a normal - // identifier rather than a keyword, to allow libstdc++ 4.2 to work - // properly. + 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++ uaw 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); } @@ -737,7 +793,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // a class (or template thereof). TemplateArgList TemplateArgs; SourceLocation LAngleLoc, RAngleLoc; - if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS, + if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) { // We couldn't parse the template argument list at all, so don't @@ -779,7 +835,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); NameLoc = ConsumeToken(); - if (TemplateId->Kind != TNK_Type_template) { + 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 ';'. @@ -808,7 +865,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // There are four options here. If we have 'struct foo;', then this // is either a forward declaration or a friend declaration, which // have to be treated differently. If we have 'struct foo {...', - // 'struct foo :...' or 'struct foo <class-virt-specifier>' then this is a + // 'struct foo :...' or 'struct foo final[opt]' then this is a // definition. Otherwise we have something like 'struct foo xyz', a reference. // However, in some contexts, things look like declarations but are just // references, e.g. @@ -821,7 +878,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TUK = Sema::TUK_Reference; else if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon)) || - isCXX0XClassVirtSpecifier() != ClassVirtSpecifiers::CVS_None) { + isCXX0XFinalKeyword()) { if (DS.isFriendSpecified()) { // C++ [class.friend]p2: // A class shall not be defined in a friend declaration. @@ -891,15 +948,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } else if (TUK == Sema::TUK_Reference || (TUK == Sema::TUK_Friend && TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { - TypeResult - = Actions.ActOnTemplateIdType(TemplateId->Template, - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, - TemplateArgsPtr, - TemplateId->RAngleLoc); - - TypeResult = Actions.ActOnTagTemplateIdType(SS, TypeResult, TUK, - TagType, StartLoc); + TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, + StartLoc, + TemplateId->SS, + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); } else { // This is an explicit specialization or a class template // partial specialization. @@ -1007,26 +1063,24 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (TUK == Sema::TUK_Definition) { assert(Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon)) || - isCXX0XClassVirtSpecifier() != ClassVirtSpecifiers::CVS_None); + isCXX0XFinalKeyword()); if (getLang().CPlusPlus) ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get()); else ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get()); } - // FIXME: The DeclSpec should keep the locations of both the keyword and the - // name (if there is one). - SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; - const char *PrevSpec = 0; unsigned DiagID; bool Result; if (!TypeResult.isInvalid()) { - Result = DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, + Result = DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec, DiagID, TypeResult.get()); } else if (!TagOrTempResult.isInvalid()) { - Result = DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID, - TagOrTempResult.get(), Owned); + Result = DS.SetTypeSpecType(TagType, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, + PrevSpec, DiagID, TagOrTempResult.get(), Owned); } else { DS.SetTypeSpecError(); return; @@ -1072,7 +1126,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, case tok::kw_mutable: // struct foo {...} mutable x; // As shown above, type qualifiers and storage class specifiers absolutely // can occur after class specifiers according to the grammar. However, - // almost noone actually writes code like this. If we see one of these, + // 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: @@ -1195,7 +1249,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { // Parse the class-name. SourceLocation EndLocation; - TypeResult BaseType = ParseClassName(EndLocation, &SS); + TypeResult BaseType = ParseClassName(EndLocation, SS); if (BaseType.isInvalid()) return true; @@ -1270,14 +1324,10 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, /// virt-specifier: /// override /// final -/// new VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier() const { if (!getLang().CPlusPlus) return VirtSpecifiers::VS_None; - if (Tok.is(tok::kw_new)) - return VirtSpecifiers::VS_New; - if (Tok.is(tok::identifier)) { IdentifierInfo *II = Tok.getIdentifierInfo(); @@ -1323,61 +1373,22 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) { } } -/// isCXX0XClassVirtSpecifier - Determine whether the next token is a C++0x -/// class-virt-specifier. -/// -/// class-virt-specifier: -/// final -/// explicit -ClassVirtSpecifiers::Specifier Parser::isCXX0XClassVirtSpecifier() const { +/// isCXX0XFinalKeyword - Determine whether the next token is a C++0x +/// contextual 'final' keyword. +bool Parser::isCXX0XFinalKeyword() const { if (!getLang().CPlusPlus) - return ClassVirtSpecifiers::CVS_None; - - if (Tok.is(tok::kw_explicit)) - return ClassVirtSpecifiers::CVS_Explicit; - - 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_final) - return ClassVirtSpecifiers::CVS_Final; - } - - return ClassVirtSpecifiers::CVS_None; -} - -/// ParseOptionalCXX0XClassVirtSpecifierSeq - Parse a class-virt-specifier-seq. -/// -/// class-virt-specifier-seq: -/// class-virt-specifier -/// class-virt-specifier-seq class-virt-specifier -void Parser::ParseOptionalCXX0XClassVirtSpecifierSeq(ClassVirtSpecifiers &CVS) { - while (true) { - ClassVirtSpecifiers::Specifier Specifier = isCXX0XClassVirtSpecifier(); - if (Specifier == ClassVirtSpecifiers::CVS_None) - return; - - // C++ [class]p1: - // A class-virt-specifier-seq shall contain at most one of each - // class-virt-specifier. - const char *PrevSpec = 0; - if (CVS.SetSpecifier(Specifier, Tok.getLocation(), PrevSpec)) - Diag(Tok.getLocation(), diag::err_duplicate_class_virt_specifier) - << PrevSpec - << FixItHint::CreateRemoval(Tok.getLocation()); + return false; - if (!getLang().CPlusPlus0x) - Diag(Tok.getLocation(), diag::ext_override_control_keyword) - << ClassVirtSpecifiers::getSpecifierName(Specifier); + if (!Tok.is(tok::identifier)) + return false; - ConsumeToken(); + // 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. @@ -1418,6 +1429,17 @@ void Parser::ParseOptionalCXX0XClassVirtSpecifierSeq(ClassVirtSpecifiers &CVS) { void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject *TemplateDiags) { + if (Tok.is(tok::at)) { + if (getLang().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)) && @@ -1459,7 +1481,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } // static_assert-declaration - if (Tok.is(tok::kw_static_assert)) { + if (Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) { // FIXME: Check for templates SourceLocation DeclEnd; ParseStaticAssertDeclaration(DeclEnd); @@ -1487,7 +1509,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // is a bitfield. ColonProtectionRAIIObject X(*this); - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); // Optional C++0x attribute-specifier MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); @@ -1542,7 +1564,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { // If so, skip until the semi-colon or a }. - SkipUntil(tok::r_brace, true); + SkipUntil(tok::r_brace, true, true); if (Tok.is(tok::semi)) ConsumeToken(); return; @@ -1763,8 +1785,24 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (TagDecl) Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); - ClassVirtSpecifiers CVS; - ParseOptionalCXX0XClassVirtSpecifierSeq(CVS); + SourceLocation FinalLoc; + + // Parse the optional 'final' keyword. + if (getLang().CPlusPlus && 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_final) + FinalLoc = ConsumeToken(); + + if (!getLang().CPlusPlus0x) + Diag(FinalLoc, diag::ext_override_control_keyword) << "final"; + } if (Tok.is(tok::colon)) { ParseBaseClause(TagDecl); @@ -1783,7 +1821,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, SourceLocation LBraceLoc = ConsumeBrace(); if (TagDecl) - Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, CVS, + Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc, LBraceLoc); // C++ 11p3: Members of a class defined with the keyword class are private @@ -1836,7 +1874,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, } // If attributes exist after class contents, parse them. - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); if (TagDecl) @@ -1893,6 +1931,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, 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(); llvm::SmallVector<CXXCtorInitializer*, 4> MemInitializers; @@ -1956,7 +1996,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); if (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) { - AnnotateTemplateIdTokenAsType(&SS); + AnnotateTemplateIdTokenAsType(); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); TemplateTypeTy = getTypeAnnotation(Tok); } @@ -1999,10 +2039,81 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { EllipsisLoc); } -/// ParseExceptionSpecification - Parse a C++ exception-specification -/// (C++ [except.spec]). +/// \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::MaybeParseExceptionSpecification(SourceRange &SpecificationRange, + llvm::SmallVectorImpl<ParsedType> &DynamicExceptions, + llvm::SmallVectorImpl<SourceRange> &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; + + // 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. + SourceLocation LParenLoc = ConsumeParen(); + 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()); + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + NoexceptRange = SourceRange(KeywordLoc, RParenLoc); + } 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' '(' '...' ')' /// @@ -2010,46 +2121,47 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { /// type-id ... [opt] /// type-id-list ',' type-id ... [opt] /// -bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, - llvm::SmallVectorImpl<ParsedType> - &Exceptions, - llvm::SmallVectorImpl<SourceRange> - &Ranges, - bool &hasAnyExceptionSpec) { +ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( + SourceRange &SpecificationRange, + llvm::SmallVectorImpl<ParsedType> &Exceptions, + llvm::SmallVectorImpl<SourceRange> &Ranges) { assert(Tok.is(tok::kw_throw) && "expected throw"); - ConsumeToken(); + SpecificationRange.setBegin(ConsumeToken()); if (!Tok.is(tok::l_paren)) { - return Diag(Tok, diag::err_expected_lparen_after) << "throw"; + Diag(Tok, diag::err_expected_lparen_after) << "throw"; + SpecificationRange.setEnd(SpecificationRange.getBegin()); + return EST_DynamicNone; } SourceLocation LParenLoc = ConsumeParen(); // Parse throw(...), a Microsoft extension that means "this function // can throw anything". if (Tok.is(tok::ellipsis)) { - hasAnyExceptionSpec = true; SourceLocation EllipsisLoc = ConsumeToken(); if (!getLang().Microsoft) Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec); - EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - return false; + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + SpecificationRange.setEnd(RParenLoc); + 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); @@ -2061,8 +2173,8 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, break; } - EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - return false; + SpecificationRange.setEnd(MatchRHSPunctuation(tok::r_paren, LParenLoc)); + return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic; } /// ParseTrailingReturnType - Parse a trailing return type on a new-style @@ -2236,8 +2348,8 @@ void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, break; } - attrs.add(AttrFactory.Create(AttrName, AttrLoc, 0, AttrLoc, 0, - SourceLocation(), 0, 0, false, true)); + attrs.addNew(AttrName, AttrLoc, 0, AttrLoc, 0, + SourceLocation(), 0, 0, false, true); AttrParsed = true; break; } @@ -2257,9 +2369,9 @@ void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, ExprVector ArgExprs(Actions); ArgExprs.push_back(ArgExpr.release()); - attrs.add(AttrFactory.Create(AttrName, AttrLoc, 0, AttrLoc, - 0, ParamLoc, ArgExprs.take(), 1, - false, true)); + attrs.addNew(AttrName, AttrLoc, 0, AttrLoc, + 0, ParamLoc, ArgExprs.take(), 1, + false, true); AttrParsed = true; break; @@ -2301,8 +2413,8 @@ ExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) { SourceLocation TypeLoc = Tok.getLocation(); ParsedType Ty = ParseTypeName().get(); SourceRange TypeRange(Start, Tok.getLocation()); - return Actions.ActOnSizeOfAlignOfExpr(TypeLoc, false, true, - Ty.getAsOpaquePtr(), TypeRange); + return Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true, + Ty.getAsOpaquePtr(), TypeRange); } else return ParseConstantExpression(); } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 616c251..91fe1e1 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -174,7 +174,6 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, /// expression: [C99 6.5.17] /// assignment-expression ...[opt] /// expression ',' assignment-expression ...[opt] -/// ExprResult Parser::ParseExpression() { ExprResult LHS(ParseAssignmentExpression()); return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); @@ -212,7 +211,6 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { } /// ParseAssignmentExpression - Parse an expr that doesn't include commas. -/// ExprResult Parser::ParseAssignmentExpression() { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); @@ -222,7 +220,7 @@ ExprResult Parser::ParseAssignmentExpression() { if (Tok.is(tok::kw_throw)) return ParseThrowExpression(); - ExprResult LHS(ParseCastExpression(false)); + ExprResult LHS = ParseCastExpression(false, false, ParsedType()); return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment); } @@ -415,8 +413,8 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { /// due to member pointers. /// ExprResult Parser::ParseCastExpression(bool isUnaryExpression, - bool isAddressOfOperand, - ParsedType TypeOfCast) { + bool isAddressOfOperand, + ParsedType TypeOfCast) { bool NotCastExpr; ExprResult Res = ParseCastExpression(isUnaryExpression, isAddressOfOperand, @@ -465,6 +463,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// [C++] boolean-literal [C++ 2.13.5] /// [C++0x] 'nullptr' [C++0x 2.14.7] /// '(' expression ')' +/// [C1X] generic-selection /// '__func__' [C99 6.4.2.2] /// [GNU] '__FUNCTION__' /// [GNU] '__PRETTY_FUNCTION__' @@ -491,6 +490,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// [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] @@ -520,6 +520,34 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// '::'[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' @@ -535,11 +563,22 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// '__is_enum' /// '__is_pod' /// '__is_polymorphic' +/// '__is_trivial' /// '__is_union' /// /// 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, @@ -610,6 +649,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_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::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant @@ -683,7 +728,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, if (ParsedType Typ = Actions.getTypeName(II, ILoc, getCurScope())) if (Typ.get()->isObjCObjectOrInterfaceType()) { // Fake up a Declarator to use with ActOnTypeName. - DeclSpec DS; + DeclSpec DS(AttrFactory); DS.SetRangeStart(ILoc); DS.SetRangeEnd(ILoc); const char *PrevSpec = 0; @@ -731,6 +776,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::wide_string_literal: Res = ParseStringLiteralExpression(); break; + case tok::kw__Generic: // primary-expression: generic-selection [C1X 6.5.1] + Res = ParseGenericSelectionExpression(); + break; case tok::kw___builtin_va_arg: case tok::kw___builtin_offsetof: case tok::kw___builtin_choose_expr: @@ -788,7 +836,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___alignof: // unary-expression: '__alignof' unary-expression // unary-expression: '__alignof' '(' type-name ')' // unary-expression: 'alignof' '(' type-id ')' - return ParseSizeofAlignofExpression(); + 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)) @@ -825,7 +874,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ParsedType Type = getTypeAnnotation(Tok); // Fake up a Declarator to use with ActOnTypeName. - DeclSpec DS; + DeclSpec DS(AttrFactory); DS.SetRangeStart(Tok.getLocation()); DS.SetRangeEnd(Tok.getLastLoc()); @@ -854,6 +903,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_short: case tok::kw_int: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_float: @@ -875,7 +925,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // postfix-expression: simple-type-specifier '(' expression-list[opt] ')' // - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseCXXSimpleTypeSpecifier(DS); if (Tok.isNot(tok::l_paren)) return ExprError(Diag(Tok, diag::err_expected_lparen_after_type) @@ -904,7 +954,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // cast expression. CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); - AnnotateTemplateIdTokenAsType(&SS); + AnnotateTemplateIdTokenAsType(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, TypeOfCast); } @@ -978,14 +1028,39 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, return move(Result); } - case tok::kw___is_pod: // [GNU] unary-type-trait + case tok::kw___is_abstract: // [GNU] unary-type-trait case tok::kw___is_class: - case tok::kw___is_enum: - case tok::kw___is_union: case tok::kw___is_empty: - case tok::kw___is_polymorphic: - case tok::kw___is_abstract: + 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_union: case tok::kw___has_trivial_constructor: case tok::kw___has_trivial_copy: case tok::kw___has_trivial_assign: @@ -998,9 +1073,19 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, 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: return ParseBinaryTypeTrait(); + 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); @@ -1256,10 +1341,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } } -/// ParseExprAfterTypeofSizeofAlignof - We parsed a typeof/sizeof/alignof 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). +/// 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 @@ -1273,15 +1358,20 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /// 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::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, - bool &isCastExpr, - ParsedType &CastTy, - SourceRange &CastRange) { +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)) && - "Not a typeof/sizeof/alignof expression!"); + 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; @@ -1345,7 +1435,7 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, } -/// ParseSizeofAlignofExpression - Parse a sizeof or alignof expression. +/// ParseUnaryExprOrTypeTraitExpression - Parse a sizeof or alignof expression. /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' @@ -1353,10 +1443,10 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' -ExprResult Parser::ParseSizeofAlignofExpression() { +ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof) - || Tok.is(tok::kw_alignof)) && - "Not a sizeof/alignof expression!"); + || Tok.is(tok::kw_alignof) || Tok.is(tok::kw_vec_step)) && + "Not a sizeof/alignof/vec_step expression!"); Token OpTok = Tok; ConsumeToken(); @@ -1403,24 +1493,31 @@ ExprResult Parser::ParseSizeofAlignofExpression() { bool isCastExpr; ParsedType CastTy; SourceRange CastRange; - ExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok, - isCastExpr, - CastTy, - 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.ActOnSizeOfAlignOfExpr(OpTok.getLocation(), - OpTok.is(tok::kw_sizeof), - /*isType=*/true, - CastTy.getAsOpaquePtr(), - CastRange); + 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.ActOnSizeOfAlignOfExpr(OpTok.getLocation(), - OpTok.is(tok::kw_sizeof), - /*isType=*/false, - Operand.release(), CastRange); + Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), + ExprKind, + /*isType=*/false, + Operand.release(), + CastRange); return move(Operand); } @@ -1618,15 +1715,18 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, ConsumeCodeCompletionToken(); return ExprError(); } + + // 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); - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); StmtResult Stmt(ParseCompoundStatement(attrs, true)); ExprType = CompoundStmt; // If the substmt parsed correctly, build the AST node. - if (!Stmt.isInvalid() && Tok.is(tok::r_paren)) + if (!Stmt.isInvalid()) Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.take(), Tok.getLocation()); } else if (ExprType >= CompoundLiteral && @@ -1724,6 +1824,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Result = ParseExpression(); 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()); } @@ -1784,6 +1886,100 @@ ExprResult Parser::ParseStringLiteralExpression() { return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size()); } +/// ParseGenericSelectionExpression - Parse a C1X generic-selection +/// [C1X 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 (!getLang().C1X) + Diag(KeyLoc, diag::ext_c1x_generic_selection); + + SourceLocation LParenLoc = Tok.getLocation(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen, "")) + return ExprError(); + + ExprResult ControllingExpr; + { + // C1X 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)) { + // C1X 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(); + } + + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + if (RParenLoc.isInvalid()) + return ExprError(); + + return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, + ControllingExpr.release(), + move_arg(Types), move_arg(Exprs)); +} + /// ParseExpressionList - Used for C/C++ (argument-)expression-list. /// /// argument-expression-list: @@ -1837,7 +2033,7 @@ void Parser::ParseBlockId() { } // Parse the specifier-qualifier-list piece. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); // Parse the block-declarator. @@ -1845,7 +2041,7 @@ void Parser::ParseBlockId() { ParseDeclarator(DeclaratorInfo); // We do this for: ^ __attribute__((noreturn)) {, as DS has the attributes. - DeclaratorInfo.addAttributes(DS.takeAttributes()); + DeclaratorInfo.takeAttributes(DS.getAttributes(), SourceLocation()); MaybeParseGNUAttributes(DeclaratorInfo); @@ -1881,7 +2077,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { Actions.ActOnBlockStart(CaretLoc, getCurScope()); // Parse the return type if present. - DeclSpec DS; + 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. @@ -1913,16 +2109,17 @@ ExprResult Parser::ParseBlockLiteralExpression() { ParseBlockId(); } else { // Otherwise, pretend we saw (void). - ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(), - true, false, + ParsedAttributes attrs(AttrFactory); + ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, SourceLocation(), 0, 0, 0, true, SourceLocation(), - false, SourceLocation(), - false, 0, 0, 0, + EST_None, + SourceLocation(), + 0, 0, 0, 0, CaretLoc, CaretLoc, ParamInfo), - CaretLoc); + attrs, CaretLoc); MaybeParseGNUAttributes(ParamInfo); @@ -1940,6 +2137,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { } StmtResult Stmt(ParseCompoundStatementBody()); + BlockScope.Exit(); if (!Stmt.isInvalid()) Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.take(), getCurScope()); else diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index d8db711..8bf6f63 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -20,6 +20,55 @@ 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: + assert(0 && "Unknown type for digraph error message."); + return -1; + } +} + +// 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.getFileLocWithOffset(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().getFileLocWithOffset(-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); +} + /// \brief Parse global scope or nested-name-specifier if present. /// /// Parses a C++ global scope specifier ('::') or nested-name-specifier (which @@ -60,7 +109,8 @@ using namespace clang; bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext, - bool *MayBePseudoDestructor) { + bool *MayBePseudoDestructor, + bool IsTypename) { assert(getLang().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); @@ -111,7 +161,12 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // Code completion for a nested-name-specifier, where the code // code completion token follows the '::'. Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext); - ConsumeCodeCompletionToken(); + SourceLocation ccLoc = ConsumeCodeCompletionToken(); + // 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(ccLoc); } } @@ -173,7 +228,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ObjectType, EnteringContext, Template)) { - if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName, + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName, TemplateKWLoc, false)) return true; } else @@ -197,35 +252,37 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, return false; } - if (TemplateId->Kind == TNK_Type_template || - TemplateId->Kind == TNK_Dependent_template_name) { - AnnotateTemplateIdTokenAsType(&SS); + // Consume the template-id token. + ConsumeToken(); + + assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); + SourceLocation CCLoc = ConsumeToken(); - assert(Tok.is(tok::annot_typename) && - "AnnotateTemplateIdTokenAsType isn't working"); - Token TypeToken = Tok; - ConsumeToken(); - assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); - SourceLocation CCLoc = ConsumeToken(); - - if (!HasScopeSpecifier) - HasScopeSpecifier = true; - - if (ParsedType T = getTypeAnnotation(TypeToken)) { - if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), T, CCLoc, SS)) - SS.SetInvalid(SourceRange(SS.getBeginLoc(), CCLoc)); - - continue; - } else { - SourceLocation Start = SS.getBeginLoc().isValid()? SS.getBeginLoc() - : CCLoc; - SS.SetInvalid(SourceRange(Start, CCLoc)); - } - - continue; + if (!HasScopeSpecifier) + HasScopeSpecifier = true; + + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + + if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), + /*FIXME:*/SourceLocation(), + SS, + 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)); } - - assert(false && "FIXME: Only type template names supported here"); + + TemplateId->Destroy(); + continue; } @@ -284,6 +341,29 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, continue; } + // Check for '<::' which should be '< ::' instead of '[:' when following + // a template name. + if (Next.is(tok::l_square) && Next.getLength() == 2) { + Token SecondToken = GetLookAheadToken(2); + if (SecondToken.is(tok::colon) && + AreTokensAdjacent(PP, Next, SecondToken)) { + TemplateTy Template; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(&II, Tok.getLocation()); + bool MemberOfUnknownSpecialization; + if (Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, + TemplateName, + ObjectType, + EnteringContext, + Template, + MemberOfUnknownSpecialization)) { + FixDigraph(*this, PP, Next, SecondToken, tok::kw_template, + /*AtDigraph*/false); + } + } + } + // nested-name-specifier: // type-name '<' if (Next.is(tok::less)) { @@ -305,19 +385,23 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // specializations) still want to see the original template-id // token. ConsumeToken(); - if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName, + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName, SourceLocation(), false)) return true; continue; } if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && - IsTemplateArgumentList(1)) { + (IsTypename || IsTemplateArgumentList(1))) { // We have something like t::getAs<T>, 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. - Diag(Tok.getLocation(), diag::err_missing_dependent_template_keyword) + unsigned DiagID = diag::err_missing_dependent_template_keyword; + if (getLang().Microsoft) + DiagID = diag::warn_missing_dependent_template_keyword; + + Diag(Tok.getLocation(), DiagID) << II.getName() << FixItHint::CreateInsertion(Tok.getLocation(), "template "); @@ -328,7 +412,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, EnteringContext, Template)) { // Consume the identifier. ConsumeToken(); - if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName, + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName, SourceLocation(), false)) return true; } @@ -446,6 +530,13 @@ ExprResult Parser::ParseCXXCasts() { 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(); @@ -525,7 +616,15 @@ ExprResult Parser::ParseCXXTypeid() { RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); if (RParenLoc.isInvalid()) return ExprError(); - + + // If we are a foo<int> that identifies a single function, resolve it now... + Expr* e = Result.get(); + if (e->getType() == Actions.Context.OverloadTy) { + ExprResult er = + Actions.ResolveAndFixSingleFunctionTemplateSpecialization(e); + if (er.isUsable()) + Result = er.release(); + } Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false, Result.release(), RParenLoc); } @@ -790,7 +889,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, } // type-specifier-seq - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); // declarator @@ -846,6 +945,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const { case tok::annot_typename: case tok::kw_short: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_void: @@ -857,8 +957,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const { case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_bool: - // FIXME: C++0x decltype support. - // GNU typeof support. + case tok::kw_decltype: case tok::kw_typeof: return true; @@ -938,6 +1037,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { 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; @@ -1157,7 +1259,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, TemplateArgList TemplateArgs; if (Tok.is(tok::less) && ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, - &SS, true, LAngleLoc, + SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) return true; @@ -1180,6 +1282,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, TemplateId->TemplateNameLoc = Id.StartLocation; } + TemplateId->SS = SS; TemplateId->Template = Template; TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; @@ -1199,7 +1302,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, // Constructor and destructor names. TypeResult Type - = Actions.ActOnTemplateIdType(Template, NameLoc, + = Actions.ActOnTemplateIdType(SS, Template, NameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc); if (Type.isInvalid()) @@ -1380,7 +1483,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, // ptr-operator conversion-declarator[opt] // Parse the type-specifier-seq. - DeclSpec DS; + DeclSpec DS(AttrFactory); if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType? return true; @@ -1465,7 +1568,9 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, Actions.isCurrentClassName(*Id, getCurScope(), &SS)) { // We have parsed a constructor name. Result.setConstructorName(Actions.getTypeName(*Id, IdLoc, getCurScope(), - &SS, false), + &SS, false, false, + ParsedType(), + /*NonTrivialTypeSourceInfo=*/true), IdLoc, IdLoc); } else { // We have parsed an identifier. @@ -1503,7 +1608,9 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, Result.setConstructorName(Actions.getTypeName(*TemplateId->Name, TemplateId->TemplateNameLoc, getCurScope(), - &SS, false), + &SS, false, false, + ParsedType(), + /*NontrivialTypeSourceInfo=*/true), TemplateId->TemplateNameLoc, TemplateId->RAngleLoc); TemplateId->Destroy(); @@ -1608,6 +1715,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, /// /// new-type-id: /// type-specifier-seq new-declarator[opt] +/// [GNU] attributes type-specifier-seq new-declarator[opt] /// /// new-declarator: /// ptr-operator new-declarator[opt] @@ -1629,7 +1737,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { SourceLocation PlacementLParen, PlacementRParen; SourceRange TypeIdParens; - DeclSpec DS; + DeclSpec DS(AttrFactory); Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); if (Tok.is(tok::l_paren)) { // If it turns out to be a placement, we change the type location. @@ -1653,12 +1761,14 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { // We still need the type. if (Tok.is(tok::l_paren)) { TypeIdParens.setBegin(ConsumeParen()); + MaybeParseGNUAttributes(DeclaratorInfo); ParseSpecifierQualifierList(DS); DeclaratorInfo.SetSourceRange(DS.getSourceRange()); ParseDeclarator(DeclaratorInfo); TypeIdParens.setEnd(MatchRHSPunctuation(tok::r_paren, TypeIdParens.getBegin())); } else { + MaybeParseGNUAttributes(DeclaratorInfo); if (ParseCXXTypeSpecifierSeq(DS)) DeclaratorInfo.setInvalidType(true); else { @@ -1671,6 +1781,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { } 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 { @@ -1731,10 +1842,12 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { first = false; SourceLocation RLoc = MatchRHSPunctuation(tok::r_square, LLoc); - D.AddTypeInfo(DeclaratorChunk::getArray(0, ParsedAttributes(), + + ParsedAttributes attrs(AttrFactory); + D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false, Size.release(), LLoc, RLoc), - RLoc); + attrs, RLoc); if (RLoc.isInvalid()) return; @@ -1803,23 +1916,48 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { switch(kind) { - default: llvm_unreachable("Not a known unary type trait"); + default: assert(false && "Not a known unary type trait."); case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign; - case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy; 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_copy: return UTT_HasTrivialCopy; case tok::kw___has_trivial_constructor: return UTT_HasTrivialConstructor; + 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_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_union: return UTT_IsUnion; - case tok::kw___is_literal: return UTT_IsLiteral; + case tok::kw___is_unsigned: return UTT_IsUnsigned; + case tok::kw___is_void: return UTT_IsVoid; + case tok::kw___is_volatile: return UTT_IsVolatile; } } @@ -1827,11 +1965,29 @@ 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; } } +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: assert(false && "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. @@ -1897,6 +2053,72 @@ ExprResult Parser::ParseBinaryTypeTrait() { return Actions.ActOnBinaryTypeTrait(BTT, Loc, LhsTy.get(), RhsTy.get(), RParen); } +/// 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(); + + SourceLocation LParen = Tok.getLocation(); + if (ExpectAndConsume(tok::l_paren, 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: { + SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); + return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), NULL, RParen); + } + case ATT_ArrayExtent: { + if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + ExprResult DimExpr = ParseExpression(); + SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); + + return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(), RParen); + } + default: + break; + } + return ExprError(); +} + +/// 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(); + + SourceLocation LParen = Tok.getLocation(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen)) + return ExprError(); + + ExprResult Expr = ParseExpression(); + + SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); + + return Actions.ActOnExpressionTrait(ET, Loc, Expr.get(), RParen); +} + + /// 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. diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 82dda2b..2c9278a 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -354,7 +354,7 @@ ExprResult Parser::ParseBraceInitializer() { InitExprsOk = false; // We have two ways to try to recover from this error: if the code looks - // gramatically ok (i.e. we have a comma coming up) try to continue + // 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. diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index f32a322..fdbedc5 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -41,11 +41,11 @@ Decl *Parser::ParseObjCAtDirectives() { case tok::objc_class: return ParseObjCAtClassDeclaration(AtLoc); case tok::objc_interface: { - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); return ParseObjCAtInterfaceDeclaration(AtLoc, attrs); } case tok::objc_protocol: { - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); return ParseObjCAtProtocolDeclaration(AtLoc, attrs); } case tok::objc_implementation: @@ -327,7 +327,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, // If this is a method prototype, parse it. if (Tok.is(tok::minus) || Tok.is(tok::plus)) { Decl *methodPrototype = - ParseObjCMethodPrototype(interfaceDecl, MethodImplKind); + ParseObjCMethodPrototype(interfaceDecl, MethodImplKind, false); allMethods.push_back(methodPrototype); // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for // method definitions. @@ -340,7 +340,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, ParseObjCMethodDecl(Tok.getLocation(), tok::minus, interfaceDecl, - MethodImplKind); + MethodImplKind, false); continue; } // Ignore excess semicolons. @@ -371,7 +371,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, // FIXME: as the name implies, this rule allows function definitions. // We could pass a flag or check for functions during semantic analysis. - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs)); continue; } @@ -439,11 +439,10 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, OCDS, AtLoc, MethodImplKind); // Parse all the comma separated declarators. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseStructDeclaration(DS, Callback); - ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list, "", - tok::at); + ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list); break; } } @@ -582,12 +581,14 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) { /// __attribute__((deprecated)) /// Decl *Parser::ParseObjCMethodPrototype(Decl *IDecl, - tok::ObjCKeywordKind MethodImplKind) { + 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, IDecl,MethodImplKind); + Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl,MethodImplKind, + MethodDefinition); // Since this rule is used for both method declarations and definitions, // the caller is (optionally) responsible for consuming the ';'. return MDecl; @@ -720,10 +721,12 @@ bool Parser::isTokIdentifier_in() const { /// objc-type-qualifier /// objc-type-qualifiers objc-type-qualifier /// -void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, bool IsParameter) { +void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, + ObjCTypeNameContext Context) { while (1) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCPassingType(getCurScope(), DS, IsParameter); + Actions.CodeCompleteObjCPassingType(getCurScope(), DS, + Context == OTN_ParameterType); ConsumeCodeCompletionToken(); } @@ -760,18 +763,19 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, bool IsParameter) { /// '(' objc-type-qualifiers[opt] type-name ')' /// '(' objc-type-qualifiers[opt] ')' /// -ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, bool IsParameter) { +ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, + ObjCTypeNameContext Context) { assert(Tok.is(tok::l_paren) && "expected ("); SourceLocation LParenLoc = ConsumeParen(); SourceLocation TypeStartLoc = Tok.getLocation(); // Parse type qualifiers, in, inout, etc. - ParseObjCTypeQualifierList(DS, IsParameter); + ParseObjCTypeQualifierList(DS, Context); ParsedType Ty; if (isTypeSpecifierQualifier()) { - TypeResult TypeSpec = ParseTypeName(); + TypeResult TypeSpec = ParseTypeName(0, Declarator::ObjCPrototypeContext); if (!TypeSpec.isInvalid()) Ty = TypeSpec.get(); } @@ -821,7 +825,8 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, bool IsParameter) { Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType, Decl *IDecl, - tok::ObjCKeywordKind MethodImplKind) { + tok::ObjCKeywordKind MethodImplKind, + bool MethodDefinition) { ParsingDeclRAIIObject PD(*this); if (Tok.is(tok::code_completion)) { @@ -834,12 +839,12 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ParsedType ReturnType; ObjCDeclSpec DSRet; if (Tok.is(tok::l_paren)) - ReturnType = ParseObjCTypeName(DSRet, false); + ReturnType = ParseObjCTypeName(DSRet, OTN_ResultType); // If attributes exist before the method, parse them. - ParsedAttributes attrs; + ParsedAttributes methodAttrs(AttrFactory); if (getLang().ObjC2) - MaybeParseGNUAttributes(attrs); + MaybeParseGNUAttributes(methodAttrs); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, @@ -864,7 +869,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, if (Tok.isNot(tok::colon)) { // If attributes exist after the method, parse them. if (getLang().ObjC2) - MaybeParseGNUAttributes(attrs); + MaybeParseGNUAttributes(methodAttrs); Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); Decl *Result @@ -872,7 +877,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, mType, IDecl, DSRet, ReturnType, Sel, 0, CParamInfo.data(), CParamInfo.size(), - attrs.getList(), MethodImplKind); + methodAttrs.getList(), MethodImplKind, + false, MethodDefinition); PD.complete(Result); return Result; } @@ -881,8 +887,11 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, llvm::SmallVector<Sema::ObjCArgInfo, 12> 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. @@ -894,14 +903,13 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ArgInfo.Type = ParsedType(); if (Tok.is(tok::l_paren)) // Parse the argument type if present. - ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, true); + ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, OTN_ParameterType); // If attributes exist before the argument name, parse them. ArgInfo.ArgAttrs = 0; if (getLang().ObjC2) { - ParsedAttributes attrs; - MaybeParseGNUAttributes(attrs); - ArgInfo.ArgAttrs = attrs.getList(); + MaybeParseGNUAttributes(paramAttrs); + ArgInfo.ArgAttrs = paramAttrs.getList(); } // Code completion for the next piece of the selector. @@ -930,6 +938,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ArgInfos.push_back(ArgInfo); KeyIdents.push_back(SelIdent); + // Make sure the attributes persist. + allParamAttrs.takeAllFrom(paramAttrs.getPool()); + // Code completion for the next piece of the selector. if (Tok.is(tok::code_completion)) { ConsumeCodeCompletionToken(); @@ -960,7 +971,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ConsumeToken(); break; } - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS); // Parse the declarator. Declarator ParmDecl(DS, Declarator::PrototypeContext); @@ -977,7 +988,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, // FIXME: Add support for optional parameter list... // If attributes exist after the method, parse them. if (getLang().ObjC2) - MaybeParseGNUAttributes(attrs); + MaybeParseGNUAttributes(methodAttrs); if (KeyIdents.size() == 0) { // Leave prototype scope. @@ -992,8 +1003,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, mType, IDecl, DSRet, ReturnType, Sel, &ArgInfos[0], CParamInfo.data(), CParamInfo.size(), - attrs.getList(), - MethodImplKind, isVariadic); + methodAttrs.getList(), + MethodImplKind, isVariadic, MethodDefinition); // Leave prototype scope. PrototypeScope.Exit(); @@ -1165,7 +1176,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, } Callback(*this, interfaceDecl, visibility, AllIvarDecls); // Parse all the comma separated declarators. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseStructDeclaration(DS, Callback); if (Tok.is(tok::semi)) { @@ -1376,7 +1387,7 @@ Decl *Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { } else { // missing @implementation - Diag(atEnd.getBegin(), diag::warn_expected_implementation); + Diag(atEnd.getBegin(), diag::err_expected_implementation); } return Result; } @@ -1609,7 +1620,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { ConsumeParen(); ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope); if (Tok.isNot(tok::ellipsis)) { - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS); // For some odd reason, the name of the exception variable is // optional. As a result, we need to use "PrototypeContext", because @@ -1717,9 +1728,12 @@ Decl *Parser::ParseObjCMethodDefinition() { // specified Declarator for the method. Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl); - if (PP.isCodeCompletionEnabled()) - if (trySkippingFunctionBodyForCodeCompletion()) + if (PP.isCodeCompletionEnabled()) { + if (trySkippingFunctionBodyForCodeCompletion()) { + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(MDecl, 0); + } + } StmtResult FnBody(ParseCompoundStatementBody()); @@ -1728,12 +1742,11 @@ Decl *Parser::ParseObjCMethodDefinition() { FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc, MultiStmtArg(Actions), false); - // TODO: Pass argument information. - Actions.ActOnFinishFunctionBody(MDecl, FnBody.take()); - // Leave the function body scope. BodyScope.Exit(); - + + // TODO: Pass argument information. + Actions.ActOnFinishFunctionBody(MDecl, FnBody.take()); return MDecl; } @@ -1839,7 +1852,7 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { // typename-specifier // simple-type-specifier // expression (that starts with one of the above) - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseCXXSimpleTypeSpecifier(DS); if (Tok.is(tok::l_paren)) { @@ -2337,7 +2350,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { return ExprError(Diag(Tok, diag::err_expected_colon)); ++nColons; - ConsumeToken(); // Eat the ':'. + ConsumeToken(); // Eat the ':' or '::'. if (Tok.is(tok::r_paren)) break; @@ -2353,7 +2366,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { SourceLocation Loc; SelIdent = ParseObjCSelectorPiece(Loc); KeyIdents.push_back(SelIdent); - if (!SelIdent && Tok.isNot(tok::colon)) + if (!SelIdent && Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon)) break; } } diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index dfd0da0..46225c8 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -74,7 +74,7 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, return; } PP.Lex(Tok); - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "visibility"; return; @@ -168,7 +168,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, SourceLocation RParenLoc = Tok.getLocation(); PP.Lex(Tok); - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack"; return; } @@ -177,6 +177,38 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, LParenLoc, RParenLoc); } +// #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, @@ -228,7 +260,7 @@ static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok, SourceLocation KindLoc = Tok.getLocation(); PP.Lex(Tok); - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << (IsOptions ? "options" : "align"); return; @@ -302,7 +334,7 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, } PP.Lex(Tok); - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "unused"; return; @@ -359,7 +391,7 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, PP.Lex(Tok); } - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak"; return; } @@ -387,7 +419,7 @@ void PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &Tok) { - PP.Lex(Tok); + PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::identifier)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "OPENCL"; diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h index bee6af3..1d3138f 100644 --- a/lib/Parse/ParsePragma.h +++ b/lib/Parse/ParsePragma.h @@ -58,6 +58,16 @@ public: 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; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 2d97583..f0ab531 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -40,6 +40,7 @@ using namespace clang; /// 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 @@ -81,12 +82,13 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { ParenBraceBracketBalancer BalancerRAIIObj(*this); - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // 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) { @@ -101,13 +103,103 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { ConsumeCodeCompletionToken(); return ParseStatementOrDeclaration(Stmts, OnlyStatement); - case tok::identifier: - if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement + case tok::identifier: { + Token Next = NextToken(); + if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement return ParseLabeledStatement(attrs); } - // PASS THROUGH. - + + if (Next.isNot(tok::coloncolon)) { + CXXScopeSpec SS; + IdentifierInfo *Name = Tok.getIdentifierInfo(); + SourceLocation NameLoc = Tok.getLocation(); + 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, Id, SourceLocation(), + /*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 ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; @@ -121,21 +213,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { return StmtError(); } - // FIXME: Use the attributes - // 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(); - } - // Otherwise, eat the semicolon. - ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); - return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get())); + return ParseExprStatement(attrs); } case tok::kw_case: // C99 6.8.1: labeled-statement @@ -146,8 +224,10 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { case tok::l_brace: // C99 6.8.2: compound-statement return ParseCompoundStatement(attrs); case tok::semi: { // C99 6.8.3p3: expression[opt] ';' - bool LeadingEmptyMacro = Tok.hasLeadingEmptyMacro(); - return Actions.ActOnNullStmt(ConsumeToken(), LeadingEmptyMacro); + SourceLocation LeadingEmptyMacroLoc; + if (Tok.hasLeadingEmptyMacro()) + LeadingEmptyMacroLoc = PP.getLastEmptyMacroInstantiationLoc(); + return Actions.ActOnNullStmt(ConsumeToken(), LeadingEmptyMacroLoc); } case tok::kw_if: // C99 6.8.4.1: if-statement @@ -193,6 +273,9 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { case tok::kw_try: // C++ 15: try-block return ParseCXXTryBlock(attrs); + + case tok::kw___try: + return ParseSEHTryBlock(attrs); } // If we reached this code, the statement must end in a semicolon. @@ -210,6 +293,145 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { return move(Res); } +/// \brief Parse an expression statement. +StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) { + // If a case keyword is missing, this is where it should be inserted. + Token OldToken = Tok; + + // FIXME: Use the attributes + // 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(Attrs, /*MissingCase=*/true, Expr); + } + + // Otherwise, eat the semicolon. + ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); + return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get())); +} + +StmtResult Parser::ParseSEHTryBlock(ParsedAttributes & Attrs) { + 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)); + + ParsedAttributesWithRange attrs(AttrFactory); + StmtResult TryBlock(ParseCompoundStatement(attrs)); + if(TryBlock.isInvalid()) + return move(TryBlock); + + StmtResult Handler; + if(Tok.is(tok::kw___except)) { + 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 (getLang().Borland) { + Ident__exception_info->setIsPoisoned(false); + Ident___exception_info->setIsPoisoned(false); + Ident_GetExceptionInfo->setIsPoisoned(false); + } + ExprResult FilterExpr(ParseExpression()); + + if (getLang().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(); + + ParsedAttributesWithRange attrs(AttrFactory); + StmtResult Block(ParseCompoundStatement(attrs)); + + 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); + + ParsedAttributesWithRange attrs(AttrFactory); + StmtResult Block(ParseCompoundStatement(attrs)); + if(Block.isInvalid()) + return move(Block); + + return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.take()); +} + /// ParseLabeledStatement - We have an identifier and a ':' after it. /// /// labeled-statement: @@ -251,8 +473,9 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) { /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// -StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) { - assert(Tok.is(tok::kw_case) && "Not a case stmt!"); +StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase, + ExprResult Expr) { + assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!"); // FIXME: Use attributes? // It is very very common for code to contain many case statements recursively @@ -280,7 +503,8 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) { // While we have case statements, eat and stack them. do { - SourceLocation CaseLoc = ConsumeToken(); // eat the 'case'. + SourceLocation CaseLoc = MissingCase ? Expr.get()->getExprLoc() : + ConsumeToken(); // eat the 'case'. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteCase(getCurScope()); @@ -292,7 +516,8 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) { /// expression. ColonProtectionRAIIObject ColonProtection(*this); - ExprResult LHS(ParseConstantExpression()); + ExprResult LHS(MissingCase ? Expr : ParseConstantExpression()); + MissingCase = false; if (LHS.isInvalid()) { SkipUntil(tok::colon); return StmtError(); @@ -493,14 +718,14 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { IdentifierInfo *II = Tok.getIdentifierInfo(); SourceLocation IdLoc = ConsumeToken(); - DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, true)); + DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, LabelLoc)); if (!Tok.is(tok::comma)) break; ConsumeToken(); } - DeclSpec DS; + DeclSpec DS(AttrFactory); DeclGroupPtrTy Res = Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup.data(), DeclsInGroup.size()); StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation()); @@ -528,7 +753,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { while (Tok.is(tok::kw___extension__)) ConsumeToken(); - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // If this is the start of a declaration, parse it as such. @@ -775,7 +1000,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) { // while, for, and switch statements are local to the if, while, for, or // switch statement (including the controlled statement). // - unsigned ScopeFlags = Scope::BreakScope; + unsigned ScopeFlags = Scope::BreakScope | Scope::SwitchScope; if (C99orCXX) ScopeFlags |= Scope::DeclScope | Scope::ControlScope; ParseScope SwitchScope(this, ScopeFlags); @@ -977,6 +1202,7 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) { /// '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 /// @@ -984,6 +1210,11 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) { /// [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(ParsedAttributes &attrs) { // FIXME: Use attributes? @@ -1025,11 +1256,12 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { SourceLocation LParenLoc = ConsumeParen(); ExprResult Value; - bool ForEach = false; + bool ForEach = false, ForRange = false; StmtResult FirstPart; bool SecondPartIsInvalid = false; FullExprArg SecondPart(Actions); ExprResult Collection; + ForRangeInit ForRangeInit; FullExprArg ThirdPart(Actions); Decl *SecondVar = 0; @@ -1049,16 +1281,24 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode? Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); + // In C++0x, "for (T NS:a" might not be a typo for :: + bool MightBeForRangeStmt = getLang().CPlusPlus; + ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); + SourceLocation DeclStart = Tok.getLocation(), DeclEnd; StmtVector Stmts(Actions); DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext, - DeclEnd, attrs, false); + DeclEnd, attrs, false, + MightBeForRangeStmt ? + &ForRangeInit : 0); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); - if (Tok.is(tok::semi)) { // for (int x = 4; + if (ForRangeInit.ParsedForRangeDecl()) { + ForRange = true; + } else if (Tok.is(tok::semi)) { // for (int x = 4; ConsumeToken(); } else if ((ForEach = isTokIdentifier_in())) { Actions.ActOnForEachDeclStmt(DG); @@ -1107,7 +1347,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { } } } - if (!ForEach) { + 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 (...;; @@ -1149,6 +1389,17 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { // Match the ')'. SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + // 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, LParenLoc, + FirstPart.take(), + ForRangeInit.ColonLoc, + ForRangeInit.RangeExpr.get(), + RParenLoc); + // 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. @@ -1175,15 +1426,19 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { if (Body.isInvalid()) return StmtError(); - if (!ForEach) - return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart, - SecondVar, ThirdPart, RParenLoc, Body.take()); + if (ForEach) + // FIXME: It isn't clear how to communicate the late destruction of + // C++ temporaries used to create the collection. + return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, + FirstPart.take(), + Collection.take(), RParenLoc, + Body.take()); + + if (ForRange) + return Actions.FinishCXXForRangeStmt(ForRangeStmt.take(), Body.take()); - // FIXME: It isn't clear how to communicate the late destruction of - // C++ temporaries used to create the collection. - return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, FirstPart.take(), - Collection.take(), RParenLoc, - Body.take()); + return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart, + SecondVar, ThirdPart, RParenLoc, Body.take()); } /// ParseGotoStatement @@ -1267,7 +1522,16 @@ StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) { return StmtError(); } - R = ParseExpression(); + // FIXME: This is a hack to allow something like C++0x's generalized + // initializer lists, but only enough of this feature to allow Clang to + // parse libstdc++ 4.5's headers. + if (Tok.is(tok::l_brace) && getLang().CPlusPlus) { + R = ParseInitializer(); + if (R.isUsable() && !getLang().CPlusPlus0x) + Diag(R.get()->getLocStart(), 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(); @@ -1350,7 +1614,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { msAsm = true; return FuzzyParseMicrosoftAsmStatement(AsmLoc); } - DeclSpec DS; + DeclSpec DS(AttrFactory); SourceLocation Loc = Tok.getLocation(); ParseTypeQualifierListOpt(DS, true, false); @@ -1522,14 +1786,17 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names, return true; } -Decl *Parser::ParseFunctionStatementBody(Decl *Decl) { +Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { assert(Tok.is(tok::l_brace)); SourceLocation LBraceLoc = Tok.getLocation(); - if (PP.isCodeCompletionEnabled()) - if (trySkippingFunctionBodyForCodeCompletion()) + if (PP.isCodeCompletionEnabled()) { + if (trySkippingFunctionBodyForCodeCompletion()) { + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, 0); - + } + } + PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc, "parsing function body"); @@ -1543,6 +1810,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl) { FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, MultiStmtArg(Actions), false); + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); } @@ -1551,7 +1819,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl) { /// function-try-block: /// 'try' ctor-initializer[opt] compound-statement handler-seq /// -Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { +Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { assert(Tok.is(tok::kw_try) && "Expected 'try'"); SourceLocation TryLoc = ConsumeToken(); @@ -1562,9 +1830,12 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { if (Tok.is(tok::colon)) ParseConstructorInitializer(Decl); - if (PP.isCodeCompletionEnabled()) - if (trySkippingFunctionBodyForCodeCompletion()) + if (PP.isCodeCompletionEnabled()) { + if (trySkippingFunctionBodyForCodeCompletion()) { + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, 0); + } + } SourceLocation LBraceLoc = Tok.getLocation(); StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc)); @@ -1574,6 +1845,7 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, MultiStmtArg(Actions), false); + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); } @@ -1622,32 +1894,58 @@ StmtResult Parser::ParseCXXTryBlock(ParsedAttributes &attrs) { /// 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? - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); StmtResult TryBlock(ParseCompoundStatement(attrs)); if (TryBlock.isInvalid()) return move(TryBlock); - StmtVector Handlers(Actions); - 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()); + // Borland allows SEH-handlers with 'try' + if(Tok.is(tok::kw___except) || Tok.is(tok::kw___finally)) { + // TODO: Factor into common return ParseSEHHandlerCommon(...) + StmtResult Handler; + if(Tok.is(tok::kw___except)) { + 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()); } - // Don't bother creating the full statement if we don't have any usable - // handlers. - if (Handlers.empty()) - return StmtError(); + else { + StmtVector Handlers(Actions); + 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)); + return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), move_arg(Handlers)); + } } /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard @@ -1679,7 +1977,7 @@ StmtResult Parser::ParseCXXCatchBlock() { // without default arguments. Decl *ExceptionDecl = 0; if (Tok.isNot(tok::ellipsis)) { - DeclSpec DS; + DeclSpec DS(AttrFactory); if (ParseCXXTypeSpecifierSeq(DS)) return StmtError(); Declarator ExDecl(DS, Declarator::CXXCatchContext); @@ -1695,7 +1993,7 @@ StmtResult Parser::ParseCXXCatchBlock() { return StmtError(Diag(Tok, diag::err_expected_lbrace)); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); StmtResult Block(ParseCompoundStatement(attrs)); if (Block.isInvalid()) return move(Block); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 59ced8b..12e38da 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -17,6 +17,8 @@ #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 @@ -196,7 +198,7 @@ Parser::ParseSingleDeclarationAfterTemplate( return 0; } - ParsedAttributesWithRange prefixAttrs; + ParsedAttributesWithRange prefixAttrs(AttrFactory); MaybeParseCXX0XAttributes(prefixAttrs); if (Tok.is(tok::kw_using)) @@ -205,7 +207,7 @@ Parser::ParseSingleDeclarationAfterTemplate( // Parse the declaration specifiers, stealing the accumulated // diagnostics from the template parameters. - ParsingDeclSpec DS(DiagsFromTParams); + ParsingDeclSpec DS(*this, &DiagsFromTParams); DS.takeAttributesFrom(prefixAttrs); @@ -598,7 +600,7 @@ 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; + DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS); // Parse this as a typename. @@ -661,7 +663,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { bool Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, SourceLocation TemplateNameLoc, - const CXXScopeSpec *SS, + const CXXScopeSpec &SS, bool ConsumeLastToken, SourceLocation &LAngleLoc, TemplateArgList &TemplateArgs, @@ -756,7 +758,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, /// formed, this function returns true. /// bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, - const CXXScopeSpec *SS, + CXXScopeSpec &SS, UnqualifiedId &TemplateName, SourceLocation TemplateKWLoc, bool AllowTypeAnnotation) { @@ -790,7 +792,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // Build the annotation token. if (TNK == TNK_Type_template && AllowTypeAnnotation) { TypeResult Type - = Actions.ActOnTemplateIdType(Template, TemplateNameLoc, + = Actions.ActOnTemplateIdType(SS, + Template, TemplateNameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc); if (Type.isInvalid()) { @@ -803,8 +806,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, Tok.setKind(tok::annot_typename); setTypeAnnotation(Tok, Type.get()); - if (SS && SS->isNotEmpty()) - Tok.setLocation(SS->getBeginLoc()); + if (SS.isNotEmpty()) + Tok.setLocation(SS.getBeginLoc()); else if (TemplateKWLoc.isValid()) Tok.setLocation(TemplateKWLoc); else @@ -823,6 +826,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateId->Name = 0; TemplateId->Operator = TemplateName.OperatorFunctionId.Operator; } + TemplateId->SS = SS; TemplateId->Template = Template; TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; @@ -854,7 +858,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, /// 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(const CXXScopeSpec *SS) { +void Parser::AnnotateTemplateIdTokenAsType() { assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens"); TemplateIdAnnotation *TemplateId @@ -868,7 +872,8 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { TemplateId->NumArgs); TypeResult Type - = Actions.ActOnTemplateIdType(TemplateId->Template, + = Actions.ActOnTemplateIdType(TemplateId->SS, + TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, @@ -876,8 +881,8 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { // Create the new "type" annotation token. Tok.setKind(tok::annot_typename); setTypeAnnotation(Tok, Type.isInvalid() ? ParsedType() : Type.get()); - if (SS && SS->isNotEmpty()) // it was a C++ qualified type name. - Tok.setLocation(SS->getBeginLoc()); + 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 @@ -1122,3 +1127,125 @@ SourceRange Parser::ParsedTemplateInfo::getSourceRange() const { 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; + + // If this is a member template, introduce the template parameter scope. + ParseScope TemplateScope(this, Scope::TemplateParamScope); + + // Get the FunctionDecl. + FunctionDecl *FD = 0; + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(LMT.D)) + FD = FunTmpl->getTemplatedDecl(); + else + FD = cast<FunctionDecl>(LMT.D); + + // Reinject the template parameters. + DeclaratorDecl* Declarator = dyn_cast<DeclaratorDecl>(FD); + if (Declarator && Declarator->getNumTemplateParameterLists() != 0) { + Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator); + Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); + } else { + Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); + + DeclContext *DD = FD->getLexicalParent(); + while (DD && DD->isRecord()) { + if (ClassTemplatePartialSpecializationDecl* MD = + dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(DD)) + Actions.ActOnReenterTemplateScope(getCurScope(), MD); + else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(DD)) + Actions.ActOnReenterTemplateScope(getCurScope(), + MD->getDescribedClassTemplate()); + + DD = DD->getLexicalParent(); + } + } + 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 DeclContext. + Sema::ContextRAII SavedContext(Actions, Actions.getContainingDC(FD)); + + if (FunctionTemplateDecl *FunctionTemplate + = dyn_cast_or_null<FunctionTemplateDecl>(LMT.D)) + Actions.ActOnStartOfFunctionDef(getCurScope(), + FunctionTemplate->getTemplatedDecl()); + if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(LMT.D)) + Actions.ActOnStartOfFunctionDef(getCurScope(), Function); + + + if (Tok.is(tok::kw_try)) { + ParseFunctionTryBlock(LMT.D, FnScope); + return; + } + if (Tok.is(tok::colon)) { + ParseConstructorInitializer(LMT.D); + + // Error recovery. + if (!Tok.is(tok::l_brace)) { + Actions.ActOnFinishFunctionBody(LMT.D, 0); + return; + } + } else + Actions.ActOnDefaultCtorInitializers(LMT.D); + + ParseFunctionStatementBody(LMT.D, FnScope); + Actions.MarkAsLateParsedTemplate(FD, false); + + 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(); + // We may have a constructor initializer or function-try-block here. + if (kind == tok::colon || kind == tok::kw_try) + ConsumeAndStoreUntil(tok::l_brace, Toks); + else { + Toks.push_back(Tok); + ConsumeBrace(); + } + // 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/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index a603c37..1c4e2b3 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -58,6 +58,7 @@ bool Parser::isCXXDeclarationStatement() { case tok::kw_using: // static_assert-declaration case tok::kw_static_assert: + case tok::kw__Static_assert: return true; // simple-declaration default: @@ -658,10 +659,12 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___is_convertible_to: case tok::kw___is_empty: case tok::kw___is_enum: + 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_union: - case tok::kw___is_literal: case tok::kw___uuidof: return TPResult::True(); @@ -673,6 +676,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_float: case tok::kw_int: case tok::kw_long: + case tok::kw___int64: case tok::kw_restrict: case tok::kw_short: case tok::kw_signed: @@ -907,7 +911,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { if (TemplateId->Kind != TNK_Type_template) return TPResult::False(); CXXScopeSpec SS; - AnnotateTemplateIdTokenAsType(&SS); + AnnotateTemplateIdTokenAsType(); assert(Tok.is(tok::annot_typename)); goto case_typename; } @@ -968,6 +972,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw_short: case tok::kw_int: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_float: @@ -1151,7 +1156,7 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() { return TPResult::True(); // '...' is a sign of a function declarator. } - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseMicrosoftAttributes(attrs); // decl-specifier-seq @@ -1238,6 +1243,16 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() { 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(); } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 07e592c..4d08699 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -19,10 +19,11 @@ #include "llvm/Support/raw_ostream.h" #include "RAIIObjectsForParser.h" #include "ParsePragma.h" +#include "clang/AST/DeclTemplate.h" using namespace clang; Parser::Parser(Preprocessor &pp, Sema &actions) - : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()), + : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), GreaterThanIsOperator(true), ColonIsSacred(false), InMessageExpression(false), TemplateParameterDepth(0) { Tok.setKind(tok::eof); @@ -44,6 +45,9 @@ Parser::Parser(Preprocessor &pp, Sema &actions) 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()); @@ -362,6 +366,11 @@ Parser::~Parser() { 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(); @@ -371,6 +380,8 @@ Parser::~Parser() { OptionsHandler.reset(); PP.RemovePragmaHandler(PackHandler.get()); PackHandler.reset(); + PP.RemovePragmaHandler(MSStructHandler.get()); + MSStructHandler.reset(); PP.RemovePragmaHandler(UnusedHandler.get()); UnusedHandler.reset(); PP.RemovePragmaHandler(WeakHandler.get()); @@ -422,6 +433,37 @@ void Parser::Initialize() { 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__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(getLang().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); + } } /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the @@ -433,11 +475,15 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { Result = DeclGroupPtrTy(); if (Tok.is(tok::eof)) { + // Late template parsing can begin. + if (getLang().DelayedTemplateParsing) + Actions.SetLateTemplateParser(LateTemplateParserCallback, this); + Actions.ActOnEndOfTranslationUnit(); return true; } - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); @@ -513,14 +559,16 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw_asm: { ProhibitAttributes(attrs); - ExprResult Result(ParseSimpleAsm()); + 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(Tok.getLocation(), Result.get()); + SingleDecl = Actions.ActOnFileScopeAsmDecl(Result.get(), StartLoc, EndLoc); break; } case tok::at: @@ -550,6 +598,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, 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; @@ -743,6 +792,8 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs, /// Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo) { + // 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 @@ -778,6 +829,44 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, return 0; } + // 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 (getLang().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(); + + Decl *DP = Actions.HandleDeclarator(ParentScope, D, + move(TemplateParameterLists), + /*IsFunctionDefinition=*/true); + D.complete(DP); + D.getMutableDeclSpec().abort(); + + if (DP) { + LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(this, DP); + + FunctionDecl *FnD = 0; + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(DP)) + FnD = FunTmpl->getTemplatedDecl(); + else + FnD = cast<FunctionDecl>(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); @@ -799,7 +888,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, D.getMutableDeclSpec().abort(); if (Tok.is(tok::kw_try)) - return ParseFunctionTryBlock(Res); + return ParseFunctionTryBlock(Res, BodyScope); // If we have a colon, then we're probably parsing a C++ // ctor-initializer. @@ -808,13 +897,14 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // Recover from error. if (!Tok.is(tok::l_brace)) { + BodyScope.Exit(); Actions.ActOnFinishFunctionBody(Res, 0); return Res; } } else Actions.ActOnDefaultCtorInitializers(Res); - return ParseFunctionStatementBody(Res); + return ParseFunctionStatementBody(Res, BodyScope); } /// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides @@ -832,7 +922,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { SourceLocation DSStart = Tok.getLocation(); // Parse the common declaration-specifiers piece. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS); // C99 6.9.1p6: 'each declaration in the declaration list shall have at @@ -1029,10 +1119,14 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { // simple-template-id SourceLocation TypenameLoc = ConsumeToken(); CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(), false)) + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(), false, + 0, /*IsTypename*/true)) return true; if (!SS.isSet()) { - Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); + if (getLang().Microsoft) + Diag(Tok.getLocation(), diag::warn_expected_qualified_after_typename); + else + Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); return true; } @@ -1051,15 +1145,18 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { return true; } - AnnotateTemplateIdTokenAsType(0); - assert(Tok.is(tok::annot_typename) && - "AnnotateTemplateIdTokenAsType isn't working properly"); - if (Tok.getAnnotationValue()) - Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS, - SourceLocation(), - getTypeAnnotation(Tok)); - else - Ty = true; + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + + Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS, + /*FIXME:*/SourceLocation(), + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); + TemplateId->Destroy(); } else { Diag(Tok, diag::err_expected_type_name_after_typename) << SS.getRange(); @@ -1088,7 +1185,9 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { if (ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS, false, - NextToken().is(tok::period))) { + NextToken().is(tok::period), + ParsedType(), + /*NonTrivialTypeSourceInfo*/true)) { // This is a typename. Replace the current token in-place with an // annotation type token. Tok.setKind(tok::annot_typename); @@ -1124,7 +1223,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { Template, MemberOfUnknownSpecialization)) { // Consume the identifier. ConsumeToken(); - if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) { + if (AnnotateTemplateIdToken(Template, TNK, SS, 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. @@ -1147,7 +1246,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { // 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(&SS); + AnnotateTemplateIdTokenAsType(); return false; } } @@ -1184,7 +1283,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { assert(getLang().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); - assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) && + assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)))&& "Cannot be a type or scope token!"); CXXScopeSpec SS; diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h index 583f184..3765f92 100644 --- a/lib/Parse/RAIIObjectsForParser.h +++ b/lib/Parse/RAIIObjectsForParser.h @@ -112,7 +112,31 @@ namespace clang { 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 |