diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2012-08-15 20:02:54 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2012-08-15 20:02:54 +0000 |
commit | 56d91b49b13fe55c918afbda19f6165b5fbff87a (patch) | |
tree | 9abb1a658a297776086f4e0dfa6ca533de02104e /lib/Parse | |
parent | 41e20f564abdb05101d6b2b29c59459a966c22cc (diff) |
Vendor import of clang trunk r161861:vendor/clang/clang-trunk-r161861
Notes
Notes:
svn path=/vendor/clang/dist/; revision=239313
svn path=/vendor/clang/clang-trunk-r161861/; revision=239314; tag=vendor/clang/clang-trunk-r161861
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/CMakeLists.txt | 21 | ||||
-rw-r--r-- | lib/Parse/ParseAST.cpp | 45 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 8 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 838 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 327 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 158 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 77 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 242 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.h | 21 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 127 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 135 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 93 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 182 | ||||
-rw-r--r-- | lib/Parse/RAIIObjectsForParser.h | 298 |
14 files changed, 1772 insertions, 800 deletions
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt index 6c980ced7ee4..55e2aebca870 100644 --- a/lib/Parse/CMakeLists.txt +++ b/lib/Parse/CMakeLists.txt @@ -1,5 +1,3 @@ -set(LLVM_USED_LIBS clangBasic clangAST clangLex clangSema) - add_clang_library(clangParse ParseAST.cpp ParseCXXInlineMethods.cpp @@ -16,4 +14,21 @@ add_clang_library(clangParse Parser.cpp ) -add_dependencies(clangParse ClangAttrClasses ClangAttrList ClangDeclNodes ClangDiagnosticParse ClangStmtNodes ClangAttrLateParsed) +add_dependencies(clangParse + ClangAttrClasses + ClangAttrLateParsed + ClangAttrList + ClangAttrParsedAttrList + ClangCommentNodes + ClangDeclNodes + ClangDiagnosticCommon + ClangDiagnosticParse + ClangStmtNodes + ) + +target_link_libraries(clangParse + clangBasic + clangAST + clangLex + clangSema + ) diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp index d1c2624f8cb3..bd4f85952120 100644 --- a/lib/Parse/ParseAST.cpp +++ b/lib/Parse/ParseAST.cpp @@ -12,11 +12,13 @@ //===----------------------------------------------------------------------===// #include "clang/Parse/ParseAST.h" +#include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/Sema.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Stmt.h" @@ -77,28 +79,29 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { S.getPreprocessor().EnterMainSourceFile(); P.Initialize(); S.Initialize(); - - if (ExternalASTSource *External = S.getASTContext().getExternalSource()) - External->StartTranslationUnit(Consumer); - - bool Abort = false; + + // C11 6.9p1 says translation units must have at least one top-level + // declaration. C++ doesn't have this restriction. We also don't want to + // complain if we have a precompiled header, although technically if the PCH + // is empty we should still emit the (pedantic) diagnostic. Parser::DeclGroupPtrTy ADecl; - - while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. - // If we got a null return and something *was* parsed, ignore it. This - // is due to a top-level semicolon, an action override, or a parse error - // skipping something. - if (ADecl) { - if (!Consumer->HandleTopLevelDecl(ADecl.get())) { - Abort = true; - break; - } - } - }; - - if (Abort) - return; - + ExternalASTSource *External = S.getASTContext().getExternalSource(); + if (External) + External->StartTranslationUnit(Consumer); + + if (P.ParseTopLevelDecl(ADecl)) { + if (!External && !S.getLangOpts().CPlusPlus) + P.Diag(diag::ext_empty_translation_unit); + } else { + do { + // If we got a null return and something *was* parsed, ignore it. This + // is due to a top-level semicolon, an action override, or a parse error + // skipping something. + if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) + return; + } while (!P.ParseTopLevelDecl(ADecl)); + } + // Process any TopLevelDecls generated by #pragma weak. for (SmallVector<Decl*,2>::iterator I = S.WeakTopLevelDecls().begin(), diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index c7b29d9ba28e..abce27c3f820 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -16,6 +16,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/AST/DeclTemplate.h" +#include "RAIIObjectsForParser.h" using namespace clang; /// ParseCXXInlineMethodDef - We parsed and verified that the specified @@ -45,7 +46,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, else { FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D, move(TemplateParams), 0, - VS, /*HasDeferredInit=*/false); + VS, ICIS_NoInit); if (FnD) { Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, false, true); @@ -108,6 +109,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, // or if we are about to parse function member template then consume // the tokens and store them for parsing at the end of the translation unit. if (getLangOpts().DelayedTemplateParsing && + DefinitionKind == FDK_Definition && ((Actions.CurContext->isDependentContext() || TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) && !Actions.IsInsideALocalClassWithinATemplateFunction())) { @@ -458,7 +460,7 @@ void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); - { + if (!Class.LateParsedDeclarations.empty()) { // C++11 [expr.prim.general]p4: // Otherwise, if a member-declarator declares a non-static data member // (9.2) of a class X, the expression this is a prvalue of type "pointer @@ -492,7 +494,7 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { ConsumeAnyToken(); SourceLocation EqualLoc; - + ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false, EqualLoc); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 7995e68d3f27..b830d9ccfd9f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -14,6 +14,7 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Basic/OpenCL.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/PrettyDeclStackTrace.h" @@ -37,6 +38,8 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, AccessSpecifier AS, Decl **OwnedType) { DeclSpecContext DSC = getDeclSpecContextFromDeclaratorContext(Context); + if (DSC == DSC_normal) + DSC = DSC_type_specifier; // Parse the common declaration-specifiers piece. DeclSpec DS(AttrFactory); @@ -156,7 +159,7 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, } } else { attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0); + 0, SourceLocation(), 0, 0, AttributeList::AS_GNU); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) @@ -272,67 +275,175 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { AttributeList *attr = Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc, - ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size()); - if (BuiltinType && attr->getKind() == AttributeList::AT_iboutletcollection) + ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size(), + AttributeList::AS_GNU); + if (BuiltinType && attr->getKind() == AttributeList::AT_IBOutletCollection) Diag(Tok, diag::err_iboutletcollection_builtintype); } } +/// \brief Parses a single argument for a declspec, including the +/// surrounding parens. +void Parser::ParseMicrosoftDeclSpecWithSingleArg(IdentifierInfo *AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs) +{ + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, + AttrName->getNameStart(), tok::r_paren)) + return; + + ExprResult ArgExpr(ParseConstantExpression()); + if (ArgExpr.isInvalid()) { + T.skipToEnd(); + return; + } + Expr *ExprList = ArgExpr.take(); + Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), + &ExprList, 1, AttributeList::AS_Declspec); + + T.consumeClose(); +} + +/// \brief Determines whether a declspec is a "simple" one requiring no +/// arguments. +bool Parser::IsSimpleMicrosoftDeclSpec(IdentifierInfo *Ident) { + return llvm::StringSwitch<bool>(Ident->getName()) + .Case("dllimport", true) + .Case("dllexport", true) + .Case("noreturn", true) + .Case("nothrow", true) + .Case("noinline", true) + .Case("naked", true) + .Case("appdomain", true) + .Case("process", true) + .Case("jitintrinsic", true) + .Case("noalias", true) + .Case("restrict", true) + .Case("novtable", true) + .Case("selectany", true) + .Case("thread", true) + .Default(false); +} + +/// \brief Attempts to parse a declspec which is not simple (one that takes +/// parameters). Will return false if we properly handled the declspec, or +/// true if it is an unknown declspec. +void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, + SourceLocation Loc, + ParsedAttributes &Attrs) { + // Try to handle the easy case first -- these declspecs all take a single + // parameter as their argument. + if (llvm::StringSwitch<bool>(Ident->getName()) + .Case("uuid", true) + .Case("align", true) + .Case("allocate", true) + .Default(false)) { + ParseMicrosoftDeclSpecWithSingleArg(Ident, Loc, Attrs); + } else if (Ident->getName() == "deprecated") { + // The deprecated declspec has an optional single argument, so we will + // check for a l-paren to decide whether we should parse an argument or + // not. + if (Tok.getKind() == tok::l_paren) + ParseMicrosoftDeclSpecWithSingleArg(Ident, Loc, Attrs); + else + Attrs.addNew(Ident, Loc, 0, Loc, 0, SourceLocation(), 0, 0, + AttributeList::AS_Declspec); + } else if (Ident->getName() == "property") { + // The property declspec is more complex in that it can take one or two + // assignment expressions as a parameter, but the lhs of the assignment + // must be named get or put. + // + // For right now, we will just skip to the closing right paren of the + // property expression. + // + // FIXME: we should deal with __declspec(property) at some point because it + // is used in the platform SDK headers for the Parallel Patterns Library + // and ATL. + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, + Ident->getNameStart(), tok::r_paren)) + return; + T.skipToEnd(); + } else { + // We don't recognize this as a valid declspec, but instead of creating the + // attribute and allowing sema to warn about it, we will warn here instead. + // This is because some attributes have multiple spellings, but we need to + // disallow that for declspecs (such as align vs aligned). If we made the + // attribute, we'd have to split the valid declspec spelling logic into + // both locations. + Diag(Loc, diag::warn_ms_declspec_unknown) << Ident; + + // If there's an open paren, we should eat the open and close parens under + // the assumption that this unknown declspec has parameters. + BalancedDelimiterTracker T(*this, tok::l_paren); + if (!T.consumeOpen()) + T.skipToEnd(); + } +} -/// ParseMicrosoftDeclSpec - Parse an __declspec construct -/// /// [MS] decl-specifier: /// __declspec ( extended-decl-modifier-seq ) /// /// [MS] extended-decl-modifier-seq: /// extended-decl-modifier[opt] /// extended-decl-modifier extended-decl-modifier-seq - -void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) { +void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &Attrs) { assert(Tok.is(tok::kw___declspec) && "Not a declspec!"); ConsumeToken(); - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, - "declspec")) { - SkipUntil(tok::r_paren, true); // skip until ) or ; + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, "__declspec", + tok::r_paren)) return; - } - while (Tok.getIdentifierInfo()) { - IdentifierInfo *AttrName = Tok.getIdentifierInfo(); - SourceLocation AttrNameLoc = ConsumeToken(); - - // FIXME: Remove this when we have proper __declspec(property()) support. - // Just skip everything inside property(). - if (AttrName->getName() == "property") { - ConsumeParen(); - SkipUntil(tok::r_paren); + // An empty declspec is perfectly legal and should not warn. Additionally, + // you can specify multiple attributes per declspec. + while (Tok.getKind() != tok::r_paren) { + // We expect either a well-known identifier or a generic string. Anything + // else is a malformed declspec. + bool IsString = Tok.getKind() == tok::string_literal ? true : false; + if (!IsString && Tok.getKind() != tok::identifier && + Tok.getKind() != tok::kw_restrict) { + Diag(Tok, diag::err_ms_declspec_type); + T.skipToEnd(); + return; } - if (Tok.is(tok::l_paren)) { - ConsumeParen(); - // FIXME: This doesn't parse __declspec(property(get=get_func_name)) - // correctly. - ExprResult ArgExpr(ParseAssignmentExpression()); - if (!ArgExpr.isInvalid()) { - Expr *ExprList = ArgExpr.take(); - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), &ExprList, 1, true); + + IdentifierInfo *AttrName; + SourceLocation AttrNameLoc; + if (IsString) { + SmallString<8> StrBuffer; + bool Invalid = false; + StringRef Str = PP.getSpelling(Tok, StrBuffer, &Invalid); + if (Invalid) { + T.skipToEnd(); + return; } - if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) - SkipUntil(tok::r_paren, false); + AttrName = PP.getIdentifierInfo(Str); + AttrNameLoc = ConsumeStringToken(); } else { - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0, true); + AttrName = Tok.getIdentifierInfo(); + AttrNameLoc = ConsumeToken(); } + + if (IsString || IsSimpleMicrosoftDeclSpec(AttrName)) + // If we have a generic string, we will allow it because there is no + // documented list of allowable string declspecs, but we know they exist + // (for instance, SAL declspecs in older versions of MSVC). + // + // Alternatively, if the identifier is a simple one, then it requires no + // arguments and can be turned into an attribute directly. + Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), + 0, 0, AttributeList::AS_Declspec); + else + ParseComplexMicrosoftDeclSpec(AttrName, AttrNameLoc, Attrs); } - if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) - SkipUntil(tok::r_paren, false); - return; + T.consumeClose(); } void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { // Treat these like attributes - // FIXME: Allow Sema to distinguish between these and real attributes! while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) || Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) || @@ -340,12 +451,8 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { Tok.is(tok::kw___unaligned)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) || - Tok.is(tok::kw___ptr32)) - // FIXME: Support these properly! - continue; attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, true); + SourceLocation(), 0, 0, AttributeList::AS_MSTypespec); } } @@ -355,7 +462,7 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, true); + SourceLocation(), 0, 0, AttributeList::AS_MSTypespec); } } @@ -365,7 +472,7 @@ void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) { SourceLocation AttrNameLoc = ConsumeToken(); attrs.addNew(PP.getIdentifierInfo("opencl_kernel_function"), AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, false); + SourceLocation(), 0, 0, AttributeList::AS_GNU); } } @@ -374,42 +481,42 @@ void Parser::ParseOpenCLQualifiers(DeclSpec &DS) { switch(Tok.getKind()) { // OpenCL qualifiers: case tok::kw___private: - case tok::kw_private: + case tok::kw_private: DS.getAttributes().addNewInteger( - Actions.getASTContext(), + 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(), + Actions.getASTContext(), PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_only); break; - + case tok::kw___write_only: DS.getAttributes().addNewInteger( - Actions.getASTContext(), + Actions.getASTContext(), PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_write_only); break; - + case tok::kw___read_write: DS.getAttributes().addNewInteger( Actions.getASTContext(), @@ -490,21 +597,21 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { 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); + 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(); + return VersionTuple(); } // Parse the subminor version. @@ -599,7 +706,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, if (UnavailableLoc.isValid()) { Diag(KeywordLoc, diag::err_availability_redundant) << Keyword << SourceRange(UnavailableLoc); - } + } UnavailableLoc = KeywordLoc; if (Tok.isNot(tok::comma)) @@ -607,8 +714,8 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, ConsumeToken(); continue; - } - + } + if (Tok.isNot(tok::equal)) { Diag(Tok, diag::err_expected_equal_after) << Keyword; @@ -625,10 +732,10 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, MessageExpr = ParseStringLiteralExpression(); break; } - + SourceRange VersionRange; VersionTuple Version = ParseVersionTuple(VersionRange); - + if (Version.empty()) { SkipUntil(tok::r_paren); return; @@ -641,13 +748,13 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, Index = Deprecated; else if (Keyword == Ident_obsoleted) Index = Obsoleted; - else + else Index = Unknown; if (Index < Unknown) { if (!Changes[Index].KeywordLoc.isInvalid()) { Diag(KeywordLoc, diag::err_availability_redundant) - << Keyword + << Keyword << SourceRange(Changes[Index].KeywordLoc, Changes[Index].VersionRange.getEnd()); } @@ -693,15 +800,15 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, } // Record this attribute - attrs.addNew(&Availability, - SourceRange(AvailabilityLoc, T.getCloseLocation()), + attrs.addNew(&Availability, + SourceRange(AvailabilityLoc, T.getCloseLocation()), 0, AvailabilityLoc, Platform, PlatformLoc, Changes[Introduced], Changes[Deprecated], - Changes[Obsoleted], + Changes[Obsoleted], UnavailableLoc, MessageExpr.take(), - false, false); + AttributeList::AS_GNU); } @@ -739,16 +846,16 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) { if (!AlreadyHasClassScope) Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); - { + if (!Class.LateParsedDeclarations.empty()) { // Allow 'this' within late-parsed attributes. - Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate, + Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate, /*TypeQuals=*/0); - + for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i){ Class.LateParsedDeclarations[i]->ParseLexedAttributes(); } } - + if (!AlreadyHasClassScope) Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); @@ -770,7 +877,7 @@ void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D, /// \brief Finish parsing an attribute for which parsing was delayed. /// This will be called at the end of parsing a class declaration /// for each LateParsedAttribute. We consume the saved tokens and -/// create an attribute with the arguments filled in. We add this +/// create an attribute with the arguments filled in. We add this /// to the Attribute list for the decl. void Parser::ParseLexedAttribute(LateParsedAttribute &LA, bool EnterScope, bool OnDefinition) { @@ -885,10 +992,10 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - + ExprVector ArgExprs(Actions); bool ArgExprsOk = true; - + // now parse the list of expressions while (Tok.isNot(tok::r_paren)) { ExprResult ArgExpr(ParseAssignmentExpression()); @@ -906,7 +1013,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, // Match the ')'. if (ArgExprsOk && !T.consumeClose()) { Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), - ArgExprs.take(), ArgExprs.size()); + ArgExprs.take(), ArgExprs.size(), AttributeList::AS_GNU); } if (EndLoc) *EndLoc = T.getCloseLocation(); @@ -975,7 +1082,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, // Must temporarily exit the objective-c container scope for // parsing c none objective-c decls. ObjCDeclContextSwitch ObjCDC(*this); - + Decl *SingleDecl = 0; Decl *OwnedType = 0; switch (Tok.getKind()) { @@ -992,7 +1099,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, SingleDecl = ParseNamespace(Context, DeclEnd, InlineLoc); break; } - return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs, + return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs, true); case tok::kw_namespace: ProhibitAttributes(attrs); @@ -1010,7 +1117,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, default: return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs, true); } - + // This routine returns a DeclGroup, if the thing we parsed only contains a // single decl, convert it now. Alias declarations can also declare a type; // include that too if it is present. @@ -1019,10 +1126,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, /// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl] /// declaration-specifiers init-declarator-list[opt] ';' +/// [C++11] attribute-specifier-seq decl-specifier-seq[opt] +/// init-declarator-list ';' ///[C90/C++]init-declarator-list ';' [TODO] /// [OMP] threadprivate-directive [TODO] /// -/// for-range-declaration: [C++0x 6.5p1: stmt.ranged] +/// for-range-declaration: [C++11 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 @@ -1031,12 +1140,11 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, /// If FRI is non-null, we might be parsing a for-range-declaration instead /// of a simple-declaration. If we find that we are, we also parse the /// for-range-initializer, and place it here. -Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts, - unsigned Context, - SourceLocation &DeclEnd, - ParsedAttributes &attrs, - bool RequireSemi, - ForRangeInit *FRI) { +Parser::DeclGroupPtrTy +Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context, + SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs, + bool RequireSemi, ForRangeInit *FRI) { // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); DS.takeAttributesFrom(attrs); @@ -1047,14 +1155,15 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts, // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { + DeclEnd = Tok.getLocation(); if (RequireSemi) ConsumeToken(); Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, DS); DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } - - return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI); + + return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI); } /// Returns true if this might be the start of a declarator, or a common typo @@ -1161,15 +1270,33 @@ void Parser::SkipMalformedDecl() { case tok::kw_inline: // 'inline namespace' at the start of a line is almost certainly - // a good place to pick back up parsing. - if (Tok.isAtStartOfLine() && NextToken().is(tok::kw_namespace)) + // a good place to pick back up parsing, except in an Objective-C + // @interface context. + if (Tok.isAtStartOfLine() && NextToken().is(tok::kw_namespace) && + (!ParsingInObjCContainer || CurParsedObjCImpl)) return; break; case tok::kw_namespace: // 'namespace' at the start of a line is almost certainly a good - // place to pick back up parsing. - if (Tok.isAtStartOfLine()) + // place to pick back up parsing, except in an Objective-C + // @interface context. + if (Tok.isAtStartOfLine() && + (!ParsingInObjCContainer || CurParsedObjCImpl)) + return; + break; + + case tok::at: + // @end is very much like } in Objective-C contexts. + if (NextToken().isObjCAtKeyword(tok::objc_end) && + ParsingInObjCContainer) + return; + break; + + case tok::minus: + case tok::plus: + // - and + probably start new method declarations in Objective-C contexts. + if (Tok.isAtStartOfLine() && ParsingInObjCContainer) return; break; @@ -1214,7 +1341,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // declaration. We have to check this because __attribute__ might be the // start of a function definition in GCC-extended K&R C. !isDeclarationAfterDeclarator()) { - + if (isStartOfFunctionDefinition(D)) { if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { Diag(Tok, diag::err_function_declared_typedef); @@ -1227,7 +1354,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs); return Actions.ConvertDeclToDeclGroup(TheDecl); } - + if (isDeclarationSpecifier()) { // If there is an invalid declaration specifier right after the function // prototype, then we must be in a missing semicolon case where this isn't @@ -1269,7 +1396,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, DeclsInGroup.push_back(FirstDecl); bool ExpectSemi = Context != Declarator::ForContext; - + // If we don't have a comma, it is either the end of the list (a ';') or an // error, bail out. while (Tok.is(tok::comma)) { @@ -1303,7 +1430,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, Decl *ThisDecl = ParseDeclarationAfterDeclarator(D); D.complete(ThisDecl); if (ThisDecl) - DeclsInGroup.push_back(ThisDecl); + DeclsInGroup.push_back(ThisDecl); } } @@ -1311,10 +1438,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, *DeclEnd = Tok.getLocation(); if (ExpectSemi && - ExpectAndConsume(tok::semi, - Context == Declarator::FileContext - ? diag::err_invalid_token_after_toplevel_declarator - : diag::err_expected_semi_declaration)) { + ExpectAndConsumeSemi(Context == Declarator::FileContext + ? diag::err_invalid_token_after_toplevel_declarator + : diag::err_expected_semi_declaration)) { // Okay, there was no semicolon and one was expected. If we see a // declaration specifier, just assume it was missing and continue parsing. // Otherwise things are very confused and we skip to recover. @@ -1388,7 +1514,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, case ParsedTemplateInfo::NonTemplate: ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); break; - + case ParsedTemplateInfo::Template: case ParsedTemplateInfo::ExplicitSpecialization: ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(), @@ -1397,9 +1523,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, TemplateInfo.TemplateParams->size()), D); break; - + case ParsedTemplateInfo::ExplicitInstantiation: { - DeclResult ThisRes + DeclResult ThisRes = Actions.ActOnExplicitInstantiation(getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, @@ -1408,7 +1534,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, SkipUntil(tok::semi, true, true); return 0; } - + ThisDecl = ThisRes.get(); break; } @@ -1441,10 +1567,11 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteInitializer(getCurScope(), ThisDecl); + Actions.FinalizeDeclaration(ThisDecl); cutOffParsing(); return 0; } - + ExprResult Init(ParseInitializer()); if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { @@ -1497,7 +1624,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, Actions.AddInitializerToDecl(ThisDecl, Initializer.take(), /*DirectInit=*/true, TypeContainsAuto); } - } else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + } else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace) && + (!CurParsedObjCImpl || !D.isFunctionDeclarator())) { // Parse C++0x braced-init-list. Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); @@ -1543,7 +1671,8 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, // Validate declspec for type-name. unsigned Specs = DS.getParsedSpecifiers(); - if (DSC == DSC_type_specifier && !DS.hasTypeSpecifier()) { + if ((DSC == DSC_type_specifier || DSC == DSC_trailing) && + !DS.hasTypeSpecifier()) { Diag(Tok, diag::err_expected_type); DS.SetTypeSpecError(); } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() && @@ -1635,12 +1764,13 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, assert(!DS.hasTypeSpecifier() && "Type specifier checked above"); // Since we know that this either implicit int (which is rare) or an - // error, do lookahead to try to do better recovery. This never applies within - // a type specifier. - // FIXME: Don't bail out here in languages with no implicit int (like - // C++ with no -fms-extensions). This is much more likely to be an undeclared - // type or typo than a use of implicit int. - if (DSC != DSC_type_specifier && + // error, do lookahead to try to do better recovery. This never applies + // within a type specifier. Outside of C++, we allow this even if the + // language doesn't "officially" support implicit int -- we support + // implicit int as an extension in C99 and C11. Allegedly, MS also + // supports implicit int in C++ mode. + if (DSC != DSC_type_specifier && DSC != DSC_trailing && + (!getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt) && isValidAfterIdentifierInDeclarator(NextToken())) { // If this token is valid for implicit int, e.g. "static x = 4", then // we just avoid eating the identifier, so it will be parsed as the @@ -1648,6 +1778,13 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, return false; } + if (getLangOpts().CPlusPlus && + DS.getStorageClassSpec() == DeclSpec::SCS_auto) { + // Don't require a type specifier if we have the 'auto' storage class + // specifier in C++98 -- we'll promote it to a type specifier. + return false; + } + // Otherwise, if we don't consume this token, we are going to emit an // error anyway. Try to recover from various common problems. Check // to see if this was a reference to a tag name without a tag specified. @@ -1671,9 +1808,20 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, } if (TagName) { + IdentifierInfo *TokenName = Tok.getIdentifierInfo(); + LookupResult R(Actions, TokenName, SourceLocation(), + Sema::LookupOrdinaryName); + Diag(Loc, diag::err_use_of_tag_name_without_tag) - << Tok.getIdentifierInfo() << TagName << getLangOpts().CPlusPlus - << FixItHint::CreateInsertion(Tok.getLocation(),FixitTagName); + << TokenName << TagName << getLangOpts().CPlusPlus + << FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName); + + if (Actions.LookupParsedName(R, getCurScope(), SS)) { + for (LookupResult::iterator I = R.begin(), IEnd = R.end(); + I != IEnd; ++I) + Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type) + << TokenName << TagName; + } // Parse this as a tag as if the missing tag were present. if (TagKind == tok::kw_enum) @@ -1685,11 +1833,55 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, } } - // This is almost certainly an invalid type name. Let the action emit a + // Determine whether this identifier could plausibly be the name of something + // being declared (with a missing type). + if (DSC != DSC_type_specifier && DSC != DSC_trailing && + (!SS || DSC == DSC_top_level || DSC == DSC_class)) { + // Look ahead to the next token to try to figure out what this declaration + // was supposed to be. + switch (NextToken().getKind()) { + case tok::comma: + case tok::equal: + case tok::kw_asm: + case tok::l_brace: + case tok::l_square: + case tok::semi: + // This looks like a variable declaration. The type is probably missing. + // We're done parsing decl-specifiers. + return false; + + case tok::l_paren: { + // static x(4); // 'x' is not a type + // x(int n); // 'x' is not a type + // x (*p)[]; // 'x' is a type + // + // Since we're in an error case (or the rare 'implicit int in C++' MS + // extension), we can afford to perform a tentative parse to determine + // which case we're in. + TentativeParsingAction PA(*this); + ConsumeToken(); + TPResult TPR = TryParseDeclarator(/*mayBeAbstract*/false); + PA.Revert(); + if (TPR == TPResult::False()) + return false; + // The identifier is followed by a parenthesized declarator. + // It's supposed to be a type. + break; + } + + default: + // This is probably supposed to be a type. This includes cases like: + // int f(itn); + // struct S { unsinged : 4; }; + break; + } + } + + // This is almost certainly an invalid type name. Let the action emit a // diagnostic and attempt to recover. ParsedType T; - if (Actions.DiagnoseUnknownTypeName(*Tok.getIdentifierInfo(), Loc, - getCurScope(), SS, T)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + if (Actions.DiagnoseUnknownTypeName(II, Loc, getCurScope(), SS, T)) { // The action emitted a diagnostic, so we don't have to. if (T) { // The action has suggested that the type T could be used. Set that as @@ -1700,11 +1892,15 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T); DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); - + // There may be other declaration specifiers after this. + return true; + } else if (II != Tok.getIdentifierInfo()) { + // If no type was suggested, the correction is to a keyword + Tok.setKind(II->getTokenID()); // There may be other declaration specifiers after this. return true; } - + // Fall through; the action had no suggestion for us. } else { // The action did not emit a diagnostic, so emit one now. @@ -1729,7 +1925,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, /// /// \param Context the declarator context, which is one of the /// Declarator::TheContext enumerator values. -Parser::DeclSpecContext +Parser::DeclSpecContext Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { if (Context == Declarator::MemberContext) return DSC_class; @@ -1806,8 +2002,12 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, ExprVector ArgExprs(Actions); ArgExprs.push_back(ArgExpr.release()); + // FIXME: This should not be GNU, but we since the attribute used is + // based on the spelling, and there is no true spelling for + // C++11 attributes, this isn't accepted. Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc, - 0, T.getOpenLocation(), ArgExprs.take(), 1, false, true); + 0, T.getOpenLocation(), ArgExprs.take(), 1, + AttributeList::AS_GNU); } /// ParseDeclarationSpecifiers @@ -1845,8 +2045,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeStart(Tok.getLocation()); DS.SetRangeEnd(Tok.getLocation()); } - + bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level); + bool AttrsLastTime = false; + ParsedAttributesWithRange attrs(AttrFactory); while (1) { bool isInvalid = false; const char *PrevSpec = 0; @@ -1857,14 +2059,32 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, switch (Tok.getKind()) { default: DoneWithDeclSpec: - // [C++0x] decl-specifier-seq: decl-specifier attribute-specifier-seq[opt] - MaybeParseCXX0XAttributes(DS.getAttributes()); + if (!AttrsLastTime) + ProhibitAttributes(attrs); + else + DS.takeAttributesFrom(attrs); // If this is not a declaration specifier token, we're done reading decl // specifiers. First verify that DeclSpec's are consistent. DS.Finish(Diags, PP); return; + case tok::l_square: + case tok::kw_alignas: + if (!isCXX11AttributeSpecifier()) + goto DoneWithDeclSpec; + + ProhibitAttributes(attrs); + // FIXME: It would be good to recover by accepting the attributes, + // but attempting to do that now would cause serious + // madness in terms of diagnostics. + attrs.clear(); + attrs.Range = SourceRange(); + + ParseCXX11Attributes(attrs); + AttrsLastTime = true; + continue; + case tok::code_completion: { Sema::ParserCompletionContext CCC = Sema::PCC_Namespace; if (DS.hasTypeSpecifier()) { @@ -1875,25 +2095,25 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Scope::FunctionPrototypeScope | Scope::AtCatchScope)) == 0; bool AllowNestedNameSpecifiers - = DSContext == DSC_top_level || + = DSContext == DSC_top_level || (DSContext == DSC_class && DS.isFriendSpecified()); Actions.CodeCompleteDeclSpec(getCurScope(), DS, - AllowNonIdentifiers, + AllowNonIdentifiers, AllowNestedNameSpecifiers); return cutOffParsing(); - } - + } + if (getCurScope()->getFnParent() || getCurScope()->getBlockParent()) CCC = Sema::PCC_LocalDeclarationSpecifiers; else if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) - CCC = DSContext == DSC_class? Sema::PCC_MemberTemplate + CCC = DSContext == DSC_class? Sema::PCC_MemberTemplate : Sema::PCC_Template; else if (DSContext == DSC_class) CCC = Sema::PCC_Class; else if (CurParsedObjCImpl) CCC = Sema::PCC_ObjCImplementation; - + Actions.CodeCompleteOrdinaryName(getCurScope(), CCC); return cutOffParsing(); } @@ -1910,7 +2130,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; case tok::annot_cxxscope: { - if (DS.hasTypeSpecifier()) + if (DS.hasTypeSpecifier() || DS.isTypeAltiVecVector()) goto DoneWithDeclSpec; CXXScopeSpec SS; @@ -1940,10 +2160,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // // the name is instead considered to name the constructor of // class C. - // + // // Thus, if the template-name is actually the constructor // name, then the code is ill-formed; this interpretation is - // reinforced by the NAD status of core issue 635. + // reinforced by the NAD status of core issue 635. TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next); if ((DSContext == DSC_top_level || (DSContext == DSC_class && DS.isFriendSpecified())) && @@ -1980,7 +2200,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Tok.getAnnotationValue()) { ParsedType T = getTypeAnnotation(Tok); isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, - Tok.getAnnotationEndLoc(), + Tok.getAnnotationEndLoc(), PrevSpec, DiagID, T); } else @@ -1996,7 +2216,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // check whether this is a constructor declaration. if ((DSContext == DSC_top_level || (DSContext == DSC_class && DS.isFriendSpecified())) && - Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(), + Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(), &SS)) { if (isConstructorDeclarator()) goto DoneWithDeclSpec; @@ -2049,7 +2269,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DiagID, T); } else DS.SetTypeSpecError(); - + if (isInvalid) break; @@ -2058,10 +2278,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. + // Objective-C interface. if (Tok.is(tok::less) && getLangOpts().ObjC1) ParseObjCProtocolQualifiers(DS); - + continue; } @@ -2082,7 +2302,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // We're done with the declaration-specifiers. goto DoneWithDeclSpec; - + // typedef-name case tok::kw_decltype: case tok::identifier: { @@ -2108,6 +2328,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) break; + // [AltiVec] 2.2: [If the 'vector' specifier is used] The syntax does not + // allow the use of a typedef name as a type specifier. + if (DS.isTypeAltiVecVector()) + goto DoneWithDeclSpec; + ParsedType TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope()); @@ -2136,10 +2361,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. + // Objective-C interface. if (Tok.is(tok::less) && getLangOpts().ObjC1) ParseObjCProtocolQualifiers(DS); - + // Need to support trailing type qualifiers (e.g. "id<p> const"). // If a type specifier follows, it will be diagnosed elsewhere. continue; @@ -2179,9 +2404,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; // Microsoft single token adornments. - case tok::kw___forceinline: - // FIXME: Add handling here! - break; + case tok::kw___forceinline: { + isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID); + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + // FIXME: This does not work correctly if it is set to be a declspec + // attribute, and a GNU attribute is simply incorrect. + DS.getAttributes().addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, AttributeList::AS_GNU); + continue; + } case tok::kw___ptr64: case tok::kw___ptr32: @@ -2266,7 +2498,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // alignment-specifier case tok::kw__Alignas: if (!getLangOpts().C11) - Diag(Tok, diag::ext_c11_alignas); + Diag(Tok, diag::ext_c11_alignment) << Tok.getName(); ParseAlignmentSpecifier(DS.getAttributes()); continue; @@ -2285,7 +2517,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___module_private__: isInvalid = DS.setModulePrivateSpec(Loc, PrevSpec, DiagID); break; - + // constexpr case tok::kw_constexpr: isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID); @@ -2422,15 +2654,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // cv-qualifier: case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID, - getLangOpts()); + getLangOpts(), /*IsTypeSpec*/true); break; case tok::kw_volatile: isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, - getLangOpts()); + getLangOpts(), /*IsTypeSpec*/true); break; case tok::kw_restrict: isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, - getLangOpts()); + getLangOpts(), /*IsTypeSpec*/true); break; // C++ typename-specifier: @@ -2461,7 +2693,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; // OpenCL qualifiers: - case tok::kw_private: + case tok::kw_private: if (!getLangOpts().OpenCL) goto DoneWithDeclSpec; case tok::kw___private: @@ -2473,7 +2705,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, 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, @@ -2485,7 +2717,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id) << FixItHint::CreateInsertion(Loc, "id") << SourceRange(Loc, DS.getSourceRange().getEnd()); - + // Need to support trailing type qualifiers (e.g. "id<p> const"). // If a type specifier follows, it will be diagnosed elsewhere. continue; @@ -2494,7 +2726,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (isInvalid) { assert(PrevSpec && "Method did not return previous specifier!"); assert(DiagID); - + if (DiagID == diag::ext_duplicate_declspec) Diag(Tok, DiagID) << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); @@ -2505,6 +2737,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(Tok.getLocation()); if (DiagID != diag::err_bool_redeclaration) ConsumeToken(); + + AttrsLastTime = false; } } @@ -2526,8 +2760,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, /// [GNU] declarator[opt] ':' constant-expression attributes[opt] /// void Parser:: -ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { - +ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) { + if (Tok.is(tok::kw___extension__)) { // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. @@ -2541,7 +2775,9 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { // If there are no declarators, this is a free-standing declaration // specifier. Let the actions module cope with it. if (Tok.is(tok::semi)) { - Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, DS); + Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, + DS); + DS.complete(TheDecl); return; } @@ -2549,8 +2785,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { bool FirstDeclarator = true; SourceLocation CommaLoc; while (1) { - ParsingDeclRAIIObject PD(*this); - FieldDeclarator DeclaratorInfo(DS); + ParsingFieldDeclarator DeclaratorInfo(*this, DS); DeclaratorInfo.D.setCommaLoc(CommaLoc); // Attributes are only allowed here on successive declarators. @@ -2578,8 +2813,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { MaybeParseGNUAttributes(DeclaratorInfo.D); // We're done with this declarator; invoke the callback. - Decl *D = Fields.invoke(DeclaratorInfo); - PD.complete(D); + Fields.invoke(DeclaratorInfo); // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. @@ -2630,16 +2864,10 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { - Diag(Tok, diag::ext_extra_struct_semi) - << DeclSpec::getSpecifierName((DeclSpec::TST)TagType) - << FixItHint::CreateRemoval(Tok.getLocation()); - ConsumeToken(); + ConsumeExtraSemi(InsideStruct, TagType); continue; } - // Parse all the comma separated declarators. - DeclSpec DS(AttrFactory); - if (!Tok.is(tok::at)) { struct CFieldCallback : FieldCallback { Parser &P; @@ -2650,16 +2878,18 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, SmallVectorImpl<Decl *> &FieldDecls) : P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {} - virtual Decl *invoke(FieldDeclarator &FD) { + void invoke(ParsingFieldDeclarator &FD) { // Install the declarator into the current TagDecl. Decl *Field = P.Actions.ActOnField(P.getCurScope(), TagDecl, FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D, FD.BitfieldSize); FieldDecls.push_back(Field); - return Field; + FD.complete(Field); } } Callback(*this, TagDecl, FieldDecls); + // Parse all the comma separated declarators. + ParsingDeclSpec DS(*this); ParseStructDeclaration(DS, Callback); } else { // Handle @defs ConsumeToken(); @@ -2752,30 +2982,46 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return cutOffParsing(); } + // If attributes exist after tag, parse them. + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseGNUAttributes(attrs); + MaybeParseCXX0XAttributes(attrs); + + // If declspecs exist after tag, parse them. + while (Tok.is(tok::kw___declspec)) + ParseMicrosoftDeclSpec(attrs); + SourceLocation ScopedEnumKWLoc; bool IsScopedUsingClassTag = false; + // In C++11, recognize 'enum class' and 'enum struct'. if (getLangOpts().CPlusPlus0x && (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) { Diag(Tok, diag::warn_cxx98_compat_scoped_enum); IsScopedUsingClassTag = Tok.is(tok::kw_class); ScopedEnumKWLoc = ConsumeToken(); - } - // C++11 [temp.explicit]p12: The usual access controls do not apply to names - // used to specify explicit instantiations. We extend this to also cover - // explicit specializations. - Sema::SuppressAccessChecksRAII SuppressAccess(Actions, - TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || - TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + // Attributes are not allowed between these keywords. Diagnose, + // but then just treat them like they appeared in the right place. + ProhibitAttributes(attrs); - // If attributes exist after tag, parse them. - ParsedAttributes attrs(AttrFactory); - MaybeParseGNUAttributes(attrs); + // They are allowed afterwards, though. + MaybeParseGNUAttributes(attrs); + MaybeParseCXX0XAttributes(attrs); + while (Tok.is(tok::kw___declspec)) + ParseMicrosoftDeclSpec(attrs); + } - // If declspecs exist after tag, parse them. - while (Tok.is(tok::kw___declspec)) - ParseMicrosoftDeclSpec(attrs); + // C++11 [temp.explicit]p12: + // The usual access controls do not apply to names used to specify + // explicit instantiations. + // We extend this to also cover explicit specializations. Note that + // we don't suppress if this turns out to be an elaborated type + // specifier. + bool shouldDelayDiagsInTag = + (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag); // Enum definitions should not be parsed in a trailing-return-type. bool AllowDeclaration = DSC != DSC_trailing; @@ -2789,8 +3035,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // "enum foo : bar;" is not a potential typo for "enum foo::bar;" // if a fixed underlying type is allowed. ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType); - - if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false)) return; @@ -2831,32 +3077,35 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, IsScopedUsingClassTag = false; } - // Stop suppressing access control now we've parsed the enum name. - SuppressAccess.done(); + // Okay, end the suppression area. We'll decide whether to emit the + // diagnostics in a second. + if (shouldDelayDiagsInTag) + diagsFromTag.done(); TypeResult BaseType; // Parse the fixed underlying type. + bool CanBeBitfield = getCurScope()->getFlags() & Scope::ClassScope; if (AllowFixedUnderlyingType && Tok.is(tok::colon)) { bool PossibleBitfield = false; - if (getCurScope()->getFlags() & Scope::ClassScope) { + if (CanBeBitfield) { // If we're in class scope, this can either be an enum declaration with // an underlying type, or a declaration of a bitfield member. We try to // use a simple disambiguation scheme first to catch the common cases - // (integer literal, sizeof); if it's still ambiguous, we then consider - // anything that's a simple-type-specifier followed by '(' as an - // expression. This suffices because function types are not valid + // (integer literal, sizeof); if it's still ambiguous, we then consider + // anything that's a simple-type-specifier followed by '(' as an + // expression. This suffices because function types are not valid // underlying types anyway. TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind()); - // If the next token starts an expression, we know we're parsing a + // If the next token starts an expression, we know we're parsing a // bit-field. This is the common case. if (TPR == TPResult::True()) PossibleBitfield = true; // If the next token starts a type-specifier-seq, it may be either a // a fixed underlying type or the start of a function-style cast in C++; - // lookahead one more token to see if it's obvious that we have a + // lookahead one more token to see if it's obvious that we have a // fixed underlying type. - else if (TPR == TPResult::False() && + else if (TPR == TPResult::False() && GetLookAheadToken(2).getKind() == tok::semi) { // Consume the ':'. ConsumeToken(); @@ -2894,7 +3143,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (!PossibleBitfield) { SourceRange Range; BaseType = ParseTypeName(&Range); - + if (!getLangOpts().CPlusPlus0x && !getLangOpts().ObjC2) Diag(StartLoc, diag::ext_ms_enum_fixed_underlying_type) << Range; @@ -2914,16 +3163,39 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // enum foo {..}; void bar() { enum foo x; } <- use of old foo. // Sema::TagUseKind TUK; - if (DS.isFriendSpecified()) - TUK = Sema::TUK_Friend; - else if (!AllowDeclaration) + if (!AllowDeclaration) { TUK = Sema::TUK_Reference; - else if (Tok.is(tok::l_brace)) - TUK = Sema::TUK_Definition; - else if (Tok.is(tok::semi) && DSC != DSC_type_specifier) - TUK = Sema::TUK_Declaration; - else + } else if (Tok.is(tok::l_brace)) { + if (DS.isFriendSpecified()) { + Diag(Tok.getLocation(), diag::err_friend_decl_defines_type) + << SourceRange(DS.getFriendSpecLoc()); + ConsumeBrace(); + SkipUntil(tok::r_brace); + TUK = Sema::TUK_Friend; + } else { + TUK = Sema::TUK_Definition; + } + } else if (DSC != DSC_type_specifier && + (Tok.is(tok::semi) || + (Tok.isAtStartOfLine() && + !isValidAfterTypeSpecifier(CanBeBitfield)))) { + TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; + if (Tok.isNot(tok::semi)) { + // A semicolon was missing after this declaration. Diagnose and recover. + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, + "enum"); + PP.EnterToken(Tok); + Tok.setKind(tok::semi); + } + } else { TUK = Sema::TUK_Reference; + } + + // If this is an elaborated type specifier, and we delayed + // diagnostics before, just merge them into the current pool. + if (TUK == Sema::TUK_Reference && shouldDelayDiagsInTag) { + diagsFromTag.redelay(); + } MultiTemplateParamsArg TParams; if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && @@ -2947,6 +3219,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, TemplateInfo.TemplateParams->size()); } + if (TUK == Sema::TUK_Reference) + ProhibitAttributes(attrs); + if (!Name && TUK != Sema::TUK_Definition) { Diag(Tok, diag::err_enumerator_unnamed_no_def); @@ -2966,52 +3241,44 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, IsScopedUsingClassTag, BaseType); if (IsDependent) { - // This enum has a dependent nested-name-specifier. Handle it as a + // This enum has a dependent nested-name-specifier. Handle it as a // dependent tag. if (!Name) { DS.SetTypeSpecError(); Diag(Tok, diag::err_expected_type_name_after_typename); return; } - + TypeResult Type = Actions.ActOnDependentTag(getCurScope(), DeclSpec::TST_enum, - TUK, SS, Name, StartLoc, + TUK, SS, Name, StartLoc, NameLoc); if (Type.isInvalid()) { DS.SetTypeSpecError(); return; } - + if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec, DiagID, Type.get())) Diag(StartLoc, DiagID) << PrevSpec; - + return; } if (!TagDecl) { - // The action failed to produce an enumeration tag. If this is a + // The action failed to produce an enumeration tag. If this is a // definition, consume the entire definition. if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { ConsumeBrace(); SkipUntil(tok::r_brace); } - + DS.SetTypeSpecError(); return; } - if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { - if (TUK == Sema::TUK_Friend) { - Diag(Tok, diag::err_friend_decl_defines_type) - << SourceRange(DS.getFriendSpecLoc()); - ConsumeBrace(); - SkipUntil(tok::r_brace); - } else { - ParseEnumBody(StartLoc, TagDecl); - } - } + if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) + ParseEnumBody(StartLoc, TagDecl); if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, @@ -3051,13 +3318,15 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { SourceLocation IdentLoc = ConsumeToken(); // If attributes exist after the enumerator, parse them. - ParsedAttributes attrs(AttrFactory); + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseGNUAttributes(attrs); + MaybeParseCXX0XAttributes(attrs); + ProhibitAttributes(attrs); SourceLocation EqualLoc; ExprResult AssignedVal; - ParsingDeclRAIIObject PD(*this); - + ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent); + if (Tok.is(tok::equal)) { EqualLoc = ConsumeToken(); AssignedVal = ParseConstantExpression(); @@ -3072,26 +3341,27 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { attrs.getList(), EqualLoc, AssignedVal.release()); PD.complete(EnumConstDecl); - + EnumConstantDecls.push_back(EnumConstDecl); LastEnumConstDecl = EnumConstDecl; if (Tok.is(tok::identifier)) { // We're missing a comma between enumerators. SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation); - Diag(Loc, diag::err_enumerator_list_missing_comma) + Diag(Loc, diag::err_enumerator_list_missing_comma) << FixItHint::CreateInsertion(Loc, ", "); continue; } - + if (Tok.isNot(tok::comma)) break; SourceLocation CommaLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) { if (!getLangOpts().C99 && !getLangOpts().CPlusPlus0x) - Diag(CommaLoc, diag::ext_enumerator_list_comma) - << getLangOpts().CPlusPlus + Diag(CommaLoc, getLangOpts().CPlusPlus ? + diag::ext_enumerator_list_comma_cxx : + diag::ext_enumerator_list_comma_c) << FixItHint::CreateRemoval(CommaLoc); else if (getLangOpts().CPlusPlus0x) Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma) @@ -3114,6 +3384,18 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { EnumScope.Exit(); Actions.ActOnTagFinishDefinition(getCurScope(), EnumDecl, T.getCloseLocation()); + + // The next token must be valid after an enum definition. If not, a ';' + // was probably forgotten. + bool CanBeBitfield = getCurScope()->getFlags() & Scope::ClassScope; + if (!isValidAfterTypeSpecifier(CanBeBitfield)) { + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, "enum"); + // Push this token back into the preprocessor and change our current token + // to ';' so that the rest of the code recovers as though there were an + // ';' after the definition. + PP.EnterToken(Tok); + Tok.setKind(tok::semi); + } } /// isTypeSpecifierQualifier - Return true if the current token could be the @@ -3171,14 +3453,14 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { case tok::kw__Decimal64: case tok::kw__Decimal128: case tok::kw___vector: - + // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: case tok::kw_union: // enum-specifier case tok::kw_enum: - + // typedef-name case tok::annot_typename: return true; @@ -3319,16 +3601,16 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { return true; if (Tok.is(tok::identifier)) return false; - + // If we're in Objective-C and we have an Objective-C class type followed - // by an identifier and then either ':' or ']', in a place where an + // by an identifier and then either ':' or ']', in a place where an // expression is permitted, then this is probably a class message send // missing the initial '['. In this case, we won't consider this to be // the start of a declaration. - if (DisambiguatingWithExpression && + if (DisambiguatingWithExpression && isStartOfObjCClassMessageMissingOpenBracket()) return false; - + return isDeclarationSpecifier(); case tok::coloncolon: // ::foo::bar @@ -3353,7 +3635,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { // Modules case tok::kw___module_private__: - + // type-specifiers case tok::kw_short: case tok::kw_long: @@ -3423,7 +3705,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::annot_typename: return !DisambiguatingWithExpression || !isStartOfObjCClassMessageMissingOpenBracket(); - + case tok::kw___declspec: case tok::kw___cdecl: case tok::kw___stdcall: @@ -3453,7 +3735,7 @@ bool Parser::isConstructorDeclarator() { // Parse the C++ scope specifier. CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/true)) { TPA.Revert(); return false; @@ -3540,10 +3822,10 @@ bool Parser::isConstructorDeclarator() { /// ParseTypeQualifierListOpt /// type-qualifier-list: [C99 6.7.5] /// type-qualifier -/// [vendor] attributes +/// [vendor] attributes /// [ only if VendorAttributesAllowed=true ] /// type-qualifier-list type-qualifier -/// [vendor] type-qualifier-list attributes +/// [vendor] type-qualifier-list attributes /// [ only if VendorAttributesAllowed=true ] /// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq /// [ only if CXX0XAttributesAllowed=true ] @@ -3571,22 +3853,22 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, case tok::code_completion: Actions.CodeCompleteTypeQualifiers(DS); return cutOffParsing(); - + case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID, - getLangOpts()); + getLangOpts(), /*IsTypeSpec*/false); break; case tok::kw_volatile: isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, - getLangOpts()); + getLangOpts(), /*IsTypeSpec*/false); break; case tok::kw_restrict: isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, - getLangOpts()); + getLangOpts(), /*IsTypeSpec*/false); break; // OpenCL qualifiers: - case tok::kw_private: + case tok::kw_private: if (!getLangOpts().OpenCL) goto DoneWithTypeQuals; case tok::kw___private: @@ -3692,7 +3974,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, DirectDeclParseFunction DirectDeclParser) { if (Diags.hasAllExtensionsSilenced()) D.setExtension(); - + // C++ member pointers start with a '::' or a nested-name. // Member pointers get special handling, since there's no place for the // scope spec in the generic path below. @@ -3886,7 +4168,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (D.getCXXScopeSpec().isEmpty()) { bool EnteringContext = D.getContext() == Declarator::FileContext || D.getContext() == Declarator::MemberContext; - ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(), + ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(), EnteringContext); } @@ -3899,9 +4181,9 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // C++0x [dcl.fct]p14: // There is a syntactic ambiguity when an ellipsis occurs at the end - // of a parameter-declaration-clause without a preceding comma. In - // this case, the ellipsis is parsed as part of the - // abstract-declarator if the type of the parameter names a template + // of a parameter-declaration-clause without a preceding comma. In + // this case, the ellipsis is parsed as part of the + // abstract-declarator if the type of the parameter names a template // parameter pack that has not been expanded; otherwise, it is parsed // as part of the parameter-declaration-clause. if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() && @@ -3940,9 +4222,9 @@ void Parser::ParseDirectDeclarator(Declarator &D) { AllowConstructorName = (D.getContext() == Declarator::MemberContext); SourceLocation TemplateKWLoc; - if (ParseUnqualifiedId(D.getCXXScopeSpec(), - /*EnteringContext=*/true, - /*AllowDestructorName=*/true, + if (ParseUnqualifiedId(D.getCXXScopeSpec(), + /*EnteringContext=*/true, + /*AllowDestructorName=*/true, AllowConstructorName, ParsedType(), TemplateKWLoc, @@ -3992,6 +4274,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // portion is empty), if an abstract-declarator is allowed. D.SetIdentifier(0, Tok.getLocation()); } else { + if (Tok.getKind() == tok::annot_pragma_parser_crash) + *(volatile int*) 0x11 = 0; if (D.getContext() == Declarator::MemberContext) Diag(Tok, diag::err_expected_member_name_or_semi) << D.getDeclSpec().getSourceRange(); @@ -4020,17 +4304,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // The paren may be part of a C++ direct initializer, eg. "int x(1);". // In such a case, check if we actually have a function declarator; if it // is not, the declarator has been fully parsed. - if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { - // When not in file scope, warn for ambiguous function declarators, just - // in case the author intended it as a variable definition. - bool warnIfAmbiguous = D.getContext() != Declarator::FileContext; - if (!isCXXFunctionDeclarator(warnIfAmbiguous)) - break; - } + bool IsAmbiguous = false; + if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit() && + !isCXXFunctionDeclarator(&IsAmbiguous)) + break; ParsedAttributes attrs(AttrFactory); BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - ParseFunctionDeclarator(D, attrs, T); + ParseFunctionDeclarator(D, attrs, T, IsAmbiguous); PrototypeScope.Exit(); } else if (Tok.is(tok::l_square)) { ParseBracketDeclarator(D); @@ -4038,7 +4319,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { break; } } -} +} /// ParseParenDeclarator - We parsed the declarator D up to a paren. This is /// only called before the identifier, so these are most likely just grouping @@ -4124,7 +4405,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); // Match the ')'. T.consumeClose(); - D.AddTypeInfo(DeclaratorChunk::getParen(T.getOpenLocation(), + D.AddTypeInfo(DeclaratorChunk::getParen(T.getOpenLocation(), T.getCloseLocation()), attrs, T.getCloseLocation()); @@ -4147,7 +4428,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { // function prototype scope, including parameter declarators. ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); - ParseFunctionDeclarator(D, attrs, T, RequiresArg); + ParseFunctionDeclarator(D, attrs, T, false, RequiresArg); PrototypeScope.Exit(); } @@ -4173,8 +4454,9 @@ void Parser::ParseParenDeclarator(Declarator &D) { void Parser::ParseFunctionDeclarator(Declarator &D, ParsedAttributes &FirstArgAttrs, BalancedDelimiterTracker &Tracker, + bool IsAmbiguous, bool RequiresArg) { - assert(getCurScope()->isFunctionPrototypeScope() && + assert(getCurScope()->isFunctionPrototypeScope() && "Should call from a Function scope"); // lparen is already consumed! assert(D.isPastIdentifier() && "Should not call before identifier!"); @@ -4198,7 +4480,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, SmallVector<SourceRange, 2> DynamicExceptionRanges; ExprResult NoexceptExpr; ParsedAttributes FnAttrs(AttrFactory); - ParsedType TrailingReturnType; + TypeResult TrailingReturnType; Actions.ActOnStartFunctionDeclarator(); @@ -4248,16 +4530,16 @@ void Parser::ParseFunctionDeclarator(Declarator &D, } // C++11 [expr.prim.general]p3: - // If a declaration declares a member function or member function - // template of a class X, the expression this is a prvalue of type + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq - // and the end of the function-definition, member-declarator, or + // and the end of the function-definition, member-declarator, or // declarator. - bool IsCXX11MemberFunction = + bool IsCXX11MemberFunction = getLangOpts().CPlusPlus0x && (D.getContext() == Declarator::MemberContext || (D.getContext() == Declarator::FileContext && - D.getCXXScopeSpec().isValid() && + D.getCXXScopeSpec().isValid() && Actions.CurContext->isRecord())); Sema::CXXThisScopeRAII ThisScope(Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), @@ -4280,7 +4562,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) { Diag(Tok, diag::warn_cxx98_compat_trailing_return_type); SourceRange Range; - TrailingReturnType = ParseTrailingReturnType(Range).get(); + TrailingReturnType = ParseTrailingReturnType(Range); if (Range.getEnd().isValid()) EndLoc = Range.getEnd(); } @@ -4290,7 +4572,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, // Remember that we parsed a function type, and remember the attributes. D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto, /*isVariadic=*/EllipsisLoc.isValid(), - EllipsisLoc, + IsAmbiguous, EllipsisLoc, ParamInfo.data(), ParamInfo.size(), DS.getTypeQualifiers(), RefQualifierIsLValueRef, @@ -4303,7 +4585,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : 0, - Tracker.getOpenLocation(), + Tracker.getOpenLocation(), EndLoc, D, TrailingReturnType), FnAttrs, EndLoc); @@ -4528,7 +4810,7 @@ void Parser::ParseParameterDeclarationClause( // Consume the '='. ConsumeToken(); - // The argument isn't actually potentially evaluated unless it is + // The argument isn't actually potentially evaluated unless it is // used. EnterExpressionEvaluationContext Eval(Actions, Sema::PotentiallyEvaluatedIfUsed, @@ -4560,7 +4842,7 @@ void Parser::ParseParameterDeclarationClause( if (Tok.isNot(tok::comma)) { if (Tok.is(tok::ellipsis)) { EllipsisLoc = ConsumeToken(); // Consume the ellipsis. - + if (!getLangOpts().CPlusPlus) { // We have ellipsis without a preceding ',', which is ill-formed // in C. Complain and provide the fix. @@ -4568,7 +4850,7 @@ void Parser::ParseParameterDeclarationClause( << FixItHint::CreateInsertion(EllipsisLoc, ", "); } } - + break; } @@ -4598,7 +4880,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { T.consumeClose(); ParsedAttributes attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); - + // Remember that we parsed the empty array type. ExprResult NumElements; D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, @@ -4646,7 +4928,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // Handle the case where we have '[*]' as the array size. However, a leading // star could be the start of an expression, for example 'X[*p + 4]'. Verify - // the the token after the star is a ']'. Since stars in arrays are + // the token after the star is a ']'. Since stars in arrays are // infrequent, use of lookahead is not costly here. if (Tok.is(tok::star) && GetLookAheadToken(1).is(tok::r_square)) { ConsumeToken(); // Eat the '*'. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 5e6c4f50e036..3dc96cf0d294 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -444,6 +444,13 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, CXXScopeSpec SS; SourceLocation TypenameLoc; bool IsTypeName; + ParsedAttributesWithRange attrs(AttrFactory); + + // FIXME: Simply skip the attributes and diagnose, don't bother parsing them. + MaybeParseCXX0XAttributes(attrs); + ProhibitAttributes(attrs); + attrs.clear(); + attrs.Range = SourceRange(); // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. @@ -480,7 +487,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } - ParsedAttributes attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); // Maybe this is an alias-declaration. bool IsAliasDecl = Tok.is(tok::equal); @@ -533,9 +540,14 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, TypeAlias = ParseTypeName(0, TemplateInfo.Kind ? Declarator::AliasTemplateContext : Declarator::AliasDeclContext, AS, OwnedType); - } else + } else { + // C++11 attributes are not allowed on a using-declaration, but GNU ones + // are. + ProhibitAttributes(attrs); + // Parse (optional) attributes (most likely GNU strong-using extension). MaybeParseGNUAttributes(attrs); + } // Eat ';'. DeclEnd = Tok.getLocation(); @@ -572,6 +584,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, MultiTemplateParamsArg TemplateParamsArg(Actions, TemplateParams ? TemplateParams->data() : 0, TemplateParams ? TemplateParams->size() : 0); + // FIXME: Propagate attributes. return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg, UsingLoc, Name, TypeAlias); } @@ -874,10 +887,12 @@ Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, } // We have an identifier; check whether it is actually a type. + IdentifierInfo *CorrectedII = 0; ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true, false, ParsedType(), /*IsCtorOrDtorName=*/false, - /*NonTrivialTypeSourceInfo=*/true); + /*NonTrivialTypeSourceInfo=*/true, + &CorrectedII); if (!Type) { Diag(IdLoc, diag::err_expected_class_name); return true; @@ -900,6 +915,77 @@ Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } +void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) { + while (Tok.is(tok::kw___single_inheritance) || + Tok.is(tok::kw___multiple_inheritance) || + Tok.is(tok::kw___virtual_inheritance)) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, AttributeList::AS_GNU); + } +} + +/// Determine whether the following tokens are valid after a type-specifier +/// which could be a standalone declaration. This will conservatively return +/// true if there's any doubt, and is appropriate for insert-';' fixits. +bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { + // This switch enumerates the valid "follow" set for type-specifiers. + switch (Tok.getKind()) { + default: break; + case tok::semi: // struct foo {...} ; + case tok::star: // struct foo {...} * P; + case tok::amp: // struct foo {...} & R = ... + case tok::identifier: // struct foo {...} V ; + case tok::r_paren: //(struct foo {...} ) {4} + case tok::annot_cxxscope: // struct foo {...} a:: b; + case tok::annot_typename: // struct foo {...} a ::b; + case tok::annot_template_id: // struct foo {...} a<int> ::b; + case tok::l_paren: // struct foo {...} ( x); + case tok::comma: // __builtin_offsetof(struct foo{...} , + return true; + case tok::colon: + return CouldBeBitfield; // enum E { ... } : 2; + // Type qualifiers + case tok::kw_const: // struct foo {...} const x; + case tok::kw_volatile: // struct foo {...} volatile x; + case tok::kw_restrict: // struct foo {...} restrict x; + case tok::kw_inline: // struct foo {...} inline foo() {}; + // Storage-class specifiers + case tok::kw_static: // struct foo {...} static x; + case tok::kw_extern: // struct foo {...} extern x; + case tok::kw_typedef: // struct foo {...} typedef x; + case tok::kw_register: // struct foo {...} register x; + case tok::kw_auto: // struct foo {...} auto x; + case tok::kw_mutable: // struct foo {...} mutable x; + case tok::kw_constexpr: // struct foo {...} constexpr x; + // As shown above, type qualifiers and storage class specifiers absolutely + // can occur after class specifiers according to the grammar. However, + // almost no one actually writes code like this. If we see one of these, + // it is much more likely that someone missed a semi colon and the + // type/storage class specifier we're seeing is part of the *next* + // intended declaration, as in: + // + // struct foo { ... } + // typedef int X; + // + // We'd really like to emit a missing semicolon error instead of emitting + // an error on the 'int' saying that you can't have two type specifiers in + // the same declaration of X. Because of this, we look ahead past this + // token to see if it's a type specifier. If so, we know the code is + // otherwise invalid, so we can produce the expected semi error. + if (!isKnownToBeTypeSpecifier(NextToken())) + return true; + break; + case tok::r_brace: // struct bar { struct foo {...} } + // Missing ';' at end of struct is accepted as an extension in C mode. + if (!getLangOpts().CPlusPlus) + return true; + break; + } + return false; +} + /// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or /// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which /// until we reach the start of a definition or see a token that @@ -968,11 +1054,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // As an extension we do not perform access checking on the names used to // specify explicit specializations either. This is important to allow // specializing traits classes for private types. - Sema::SuppressAccessChecksRAII SuppressAccess(Actions, - TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || - TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + // + // Note that we don't suppress if this turns out to be an elaborated + // type specifier. + bool shouldDelayDiagsInTag = + (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag); - ParsedAttributes attrs(AttrFactory); + ParsedAttributesWithRange attrs(AttrFactory); // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) ParseGNUAttributes(attrs); @@ -981,6 +1071,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, while (Tok.is(tok::kw___declspec)) ParseMicrosoftDeclSpec(attrs); + // Parse inheritance specifiers. + if (Tok.is(tok::kw___single_inheritance) || + Tok.is(tok::kw___multiple_inheritance) || + Tok.is(tok::kw___virtual_inheritance)) + ParseMicrosoftInheritanceClassAttributes(attrs); + // If C++0x attributes exist here, parse them. // FIXME: Are we consistent with the ordering of parsing of different // styles of attributes? @@ -1103,10 +1199,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } } - // As soon as we're finished parsing the class's template-id, turn access - // checking back on. - SuppressAccess.done(); - // There are four options here. // - If we are in a trailing return type, this is always just a reference, // and we must not try to parse a definition. For instance, @@ -1144,11 +1236,29 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Okay, this is a class definition. TUK = Sema::TUK_Definition; } - } else if (Tok.is(tok::semi) && DSC != DSC_type_specifier) + } else if (DSC != DSC_type_specifier && + (Tok.is(tok::semi) || + (Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(false)))) { TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; - else + if (Tok.isNot(tok::semi)) { + // A semicolon was missing after this declaration. Diagnose and recover. + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, + TagType == DeclSpec::TST_class ? "class" : + TagType == DeclSpec::TST_struct ? "struct" : "union"); + PP.EnterToken(Tok); + Tok.setKind(tok::semi); + } + } else TUK = Sema::TUK_Reference; + // If this is an elaborated type specifier, and we delayed + // diagnostics before, just merge them into the current pool. + if (shouldDelayDiagsInTag) { + diagsFromTag.done(); + if (TUK == Sema::TUK_Reference) + diagsFromTag.redelay(); + } + if (!Name && !TemplateId && (DS.getTypeSpecType() == DeclSpec::TST_error || TUK != Sema::TUK_Definition)) { if (DS.getTypeSpecType() != DeclSpec::TST_error) { @@ -1175,6 +1285,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Sema::TUK_Declaration) { // This is an explicit instantiation of a class template. + ProhibitAttributes(attrs); + TagOrTempResult = Actions.ActOnExplicitInstantiation(getCurScope(), TemplateInfo.ExternLoc, @@ -1196,6 +1308,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } else if (TUK == Sema::TUK_Reference || (TUK == Sema::TUK_Friend && TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { + ProhibitAttributes(attrs); TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc, TemplateId->SS, TemplateId->TemplateKWLoc, @@ -1260,6 +1373,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // // template struct Outer<int>::Inner; // + ProhibitAttributes(attrs); + TagOrTempResult = Actions.ActOnExplicitInstantiation(getCurScope(), TemplateInfo.ExternLoc, @@ -1268,6 +1383,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, NameLoc, attrs.getList()); } else if (TUK == Sema::TUK_Friend && TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) { + ProhibitAttributes(attrs); + TagOrTempResult = Actions.ActOnTemplatedFriendTag(getCurScope(), DS.getFriendSpecLoc(), TagType, StartLoc, SS, @@ -1281,6 +1398,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // FIXME: Diagnose this particular error. } + if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition) + ProhibitAttributes(attrs); + bool IsDependent = false; // Don't pass down template parameter lists if this is just a tag @@ -1344,77 +1464,19 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // impossible token occurs next, we assume that the programmer forgot a ; at // the end of the declaration and recover that way. // - // This switch enumerates the valid "follow" set for definition. - if (TUK == Sema::TUK_Definition) { - bool ExpectedSemi = true; - switch (Tok.getKind()) { - default: break; - case tok::semi: // struct foo {...} ; - case tok::star: // struct foo {...} * P; - case tok::amp: // struct foo {...} & R = ... - case tok::identifier: // struct foo {...} V ; - case tok::r_paren: //(struct foo {...} ) {4} - case tok::annot_cxxscope: // struct foo {...} a:: b; - case tok::annot_typename: // struct foo {...} a ::b; - case tok::annot_template_id: // struct foo {...} a<int> ::b; - case tok::l_paren: // struct foo {...} ( x); - case tok::comma: // __builtin_offsetof(struct foo{...} , - ExpectedSemi = false; - break; - // Type qualifiers - case tok::kw_const: // struct foo {...} const x; - case tok::kw_volatile: // struct foo {...} volatile x; - case tok::kw_restrict: // struct foo {...} restrict x; - case tok::kw_inline: // struct foo {...} inline foo() {}; - // Storage-class specifiers - case tok::kw_static: // struct foo {...} static x; - case tok::kw_extern: // struct foo {...} extern x; - case tok::kw_typedef: // struct foo {...} typedef x; - case tok::kw_register: // struct foo {...} register x; - case tok::kw_auto: // struct foo {...} auto x; - case tok::kw_mutable: // struct foo {...} mutable x; - case tok::kw_constexpr: // struct foo {...} constexpr x; - // As shown above, type qualifiers and storage class specifiers absolutely - // can occur after class specifiers according to the grammar. However, - // almost no one actually writes code like this. If we see one of these, - // it is much more likely that someone missed a semi colon and the - // type/storage class specifier we're seeing is part of the *next* - // intended declaration, as in: - // - // struct foo { ... } - // typedef int X; - // - // We'd really like to emit a missing semicolon error instead of emitting - // an error on the 'int' saying that you can't have two type specifiers in - // the same declaration of X. Because of this, we look ahead past this - // token to see if it's a type specifier. If so, we know the code is - // otherwise invalid, so we can produce the expected semi error. - if (!isKnownToBeTypeSpecifier(NextToken())) - ExpectedSemi = false; - break; - - case tok::r_brace: // struct bar { struct foo {...} } - // Missing ';' at end of struct is accepted as an extension in C mode. - if (!getLangOpts().CPlusPlus) - ExpectedSemi = false; - break; - } - - // C++ [temp]p3 In a template-declaration which defines a class, no - // declarator is permitted. - if (TemplateInfo.Kind) - ExpectedSemi = true; - - if (ExpectedSemi) { - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, - TagType == DeclSpec::TST_class ? "class" - : TagType == DeclSpec::TST_struct? "struct" : "union"); - // Push this token back into the preprocessor and change our current token - // to ';' so that the rest of the code recovers as though there were an - // ';' after the definition. - PP.EnterToken(Tok); - Tok.setKind(tok::semi); - } + // Also enforce C++ [temp]p3: + // In a template-declaration which defines a class, no declarator + // is permitted. + if (TUK == Sema::TUK_Definition && + (TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) { + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, + TagType == DeclSpec::TST_class ? "class" : + TagType == DeclSpec::TST_struct ? "struct" : "union"); + // Push this token back into the preprocessor and change our current token + // to ';' so that the rest of the code recovers as though there were an + // ';' after the definition. + PP.EnterToken(Tok); + Tok.setKind(tok::semi); } } @@ -1696,12 +1758,16 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } // Access declarations. + bool MalformedTypeSpec = false; if (!TemplateInfo.Kind && - (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) && - !TryAnnotateCXXScopeToken() && - Tok.is(tok::annot_cxxscope)) { - bool isAccessDecl = false; - if (NextToken().is(tok::identifier)) + (Tok.is(tok::identifier) || Tok.is(tok::coloncolon))) { + if (TryAnnotateCXXScopeToken()) + MalformedTypeSpec = true; + + bool isAccessDecl; + if (Tok.isNot(tok::annot_cxxscope)) + isAccessDecl = false; + else if (NextToken().is(tok::identifier)) isAccessDecl = GetLookAheadToken(2).is(tok::semi); else isAccessDecl = NextToken().is(tok::kw_operator); @@ -1798,6 +1864,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this, TemplateDiags); DS.takeAttributesFrom(attrs); + if (MalformedTypeSpec) + DS.SetTypeSpecError(); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, &CommonLateParsedAttrs); @@ -1915,9 +1983,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, LateParsedAttrs.clear(); // Consume the ';' - it's optional unless we have a delete or default - if (Tok.is(tok::semi)) { - ConsumeToken(); - } + if (Tok.is(tok::semi)) + ConsumeExtraSemi(AfterMemberFunctionDefinition); return; } @@ -1961,18 +2028,19 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // goes before or after the GNU attributes and __asm__. ParseOptionalCXX0XVirtSpecifierSeq(VS); - bool HasDeferredInitializer = false; + InClassInitStyle HasInClassInit = ICIS_NoInit; if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) { if (BitfieldSize.get()) { Diag(Tok, diag::err_bitfield_member_init); SkipUntil(tok::comma, true, true); } else { HasInitializer = true; - HasDeferredInitializer = !DeclaratorInfo.isDeclarationOfFunction() && - DeclaratorInfo.getDeclSpec().getStorageClassSpec() - != DeclSpec::SCS_static && - DeclaratorInfo.getDeclSpec().getStorageClassSpec() - != DeclSpec::SCS_typedef; + if (!DeclaratorInfo.isDeclarationOfFunction() && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_static && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_typedef) + HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit; } } @@ -1990,7 +2058,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, DeclaratorInfo, move(TemplateParams), BitfieldSize.release(), - VS, HasDeferredInitializer); + VS, HasInClassInit); if (AccessAttrs) Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs, false, true); @@ -2006,15 +2074,15 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, LateParsedAttrs.clear(); // Handle the initializer. - if (HasDeferredInitializer) { + if (HasInClassInit != ICIS_NoInit) { // The initializer was deferred; parse it and cache the tokens. Diag(Tok, getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_nonstatic_member_init : diag::ext_nonstatic_member_init); if (DeclaratorInfo.isArrayOfUnknownBound()) { - // C++0x [dcl.array]p3: An array bound may also be omitted when the - // declarator is followed by an initializer. + // C++11 [dcl.array]p3: An array bound may also be omitted when the + // declarator is followed by an initializer. // // A brace-or-equal-initializer for a member-declarator is not an // initializer in the grammar, so this is ill-formed. @@ -2266,10 +2334,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { - Diag(Tok, diag::ext_extra_struct_semi) - << DeclSpec::getSpecifierName((DeclSpec::TST)TagType) - << FixItHint::CreateRemoval(Tok.getLocation()); - ConsumeToken(); + ConsumeExtraSemi(InsideStruct, TagType); continue; } @@ -2779,7 +2844,7 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf); if (std::isalpha(Spelling[0])) { Loc = ConsumeToken(); - return &PP.getIdentifierTable().get(Spelling.data()); + return &PP.getIdentifierTable().get(Spelling); } return 0; } @@ -2870,28 +2935,31 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, } bool AttrParsed = false; - // No scoped names are supported; ideally we could put all non-standard - // attributes into namespaces. - if (!ScopeName) { - switch (AttributeList::getKind(AttrName)) { - // No arguments - case AttributeList::AT_carries_dependency: - case AttributeList::AT_noreturn: { - if (Tok.is(tok::l_paren)) { - Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments) - << AttrName->getName(); - break; - } - - attrs.addNew(AttrName, AttrLoc, 0, AttrLoc, 0, - SourceLocation(), 0, 0, false, true); - AttrParsed = true; + switch (AttributeList::getKind(AttrName, ScopeName, + AttributeList::AS_CXX11)) { + // No arguments + case AttributeList::AT_CarriesDependency: + // FIXME: implement generic support of attributes with C++11 syntax + // see Parse/ParseDecl.cpp: ParseGNUAttributes + case AttributeList::AT_FallThrough: + case AttributeList::AT_NoReturn: { + if (Tok.is(tok::l_paren)) { + Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments) + << AttrName->getName(); break; } - // Silence warnings - default: break; - } + attrs.addNew(AttrName, + SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, + AttrLoc), + ScopeName, ScopeLoc, 0, + SourceLocation(), 0, 0, AttributeList::AS_CXX11); + AttrParsed = true; + break; + } + + // Silence warnings + default: break; } // Skip the entire parameter clause, if any @@ -2917,7 +2985,7 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, SkipUntil(tok::r_square, false); } -/// ParseCXX11Attributes - Parse a C++0x attribute-specifier-seq. +/// ParseCXX11Attributes - Parse a C++11 attribute-specifier-seq. /// /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier @@ -2991,10 +3059,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { - Diag(Tok, diag::ext_extra_struct_semi) - << DeclSpec::getSpecifierName((DeclSpec::TST)TagType) - << FixItHint::CreateRemoval(Tok.getLocation()); - ConsumeToken(); + ConsumeExtraSemi(InsideStruct, TagType); continue; } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 6d31396cc016..8d4668b95481 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -6,17 +6,19 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -// -// This file implements the Expression parsing implementation. Expressions in -// C99 basically consist of a bunch of binary operators with unary operators and -// other random stuff at the leaves. -// -// In the C99 grammar, these unary operators bind tightest and are represented -// as the 'cast-expression' production. Everything else is either a binary -// operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are -// handled by ParseCastExpression, the higher level pieces are handled by -// ParseBinaryExpression. -// +/// +/// \file +/// \brief Provides the Expression parsing implementation. +/// +/// Expressions in C99 basically consist of a bunch of binary operators with +/// unary operators and other random stuff at the leaves. +/// +/// In the C99 grammar, these unary operators bind tightest and are represented +/// as the 'cast-expression' production. Everything else is either a binary +/// operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are +/// handled by ParseCastExpression, the higher level pieces are handled by +/// ParseBinaryExpression. +/// //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" @@ -30,8 +32,7 @@ #include "llvm/ADT/SmallString.h" using namespace clang; -/// getBinOpPrecedence - Return the precedence of the specified binary operator -/// token. +/// \brief Return the precedence of the specified binary operator token. static prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator, bool CPlusPlus0x) { @@ -92,8 +93,7 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, } -/// ParseExpression - Simple precedence-based parser for binary/ternary -/// operators. +/// \brief Simple precedence-based parser for binary/ternary operators. /// /// Note: we diverge from the C99 grammar when parsing the assignment-expression /// production. C99 specifies that the LHS of an assignment operator should be @@ -104,6 +104,7 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, /// consistency, we parse the LHS as a conditional-expression, then check for /// l-value-ness in semantic analysis stages. /// +/// \verbatim /// pm-expression: [C++ 5.5] /// cast-expression /// pm-expression '.*' cast-expression @@ -175,6 +176,7 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, /// expression: [C99 6.5.17] /// assignment-expression ...[opt] /// expression ',' assignment-expression ...[opt] +/// \endverbatim ExprResult Parser::ParseExpression(TypeCastState isTypeCast) { ExprResult LHS(ParseAssignmentExpression(isTypeCast)); return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); @@ -182,8 +184,8 @@ ExprResult Parser::ParseExpression(TypeCastState isTypeCast) { /// This routine is called when the '@' is seen and consumed. /// Current token is an Identifier and is not a 'try'. This -/// routine is necessary to disambiguate @try-statement from, -/// for example, @encode-expression. +/// routine is necessary to disambiguate \@try-statement from, +/// for example, \@encode-expression. /// ExprResult Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { @@ -211,7 +213,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); } -/// ParseAssignmentExpression - Parse an expr that doesn't include commas. +/// \brief Parse an expr that doesn't include (top-level) commas. ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); @@ -228,11 +230,12 @@ ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment); } -/// ParseAssignmentExprWithObjCMessageExprStart - Parse an assignment expression -/// where part of an objc message send has already been parsed. In this case -/// LBracLoc indicates the location of the '[' of the message send, and either -/// ReceiverName or ReceiverExpr is non-null indicating the receiver of the -/// message. +/// \brief Parse an assignment expression where part of an Objective-C message +/// send has already been parsed. +/// +/// In this case \p LBracLoc indicates the location of the '[' of the message +/// send, and either \p ReceiverName or \p ReceiverExpr is non-null indicating +/// the receiver of the message. /// /// Since this handles full assignment-expression's, it handles postfix /// expressions and other binary operators for these expressions as well. @@ -262,8 +265,8 @@ ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { return Actions.ActOnConstantExpression(Res); } -/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with -/// LHS and has a precedence of at least MinPrec. +/// \brief Parse a binary expression that starts with \p LHS and has a +/// precedence of at least \p MinPrec. ExprResult Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(), @@ -439,10 +442,11 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { } } -/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is -/// true, parse a unary-expression. isAddressOfOperand exists because an -/// id-expression that is the operand of address-of gets special treatment -/// due to member pointers. +/// \brief Parse a cast-expression, or, if \p isUnaryExpression is true, +/// parse a unary-expression. +/// +/// \p isAddressOfOperand exists because an id-expression that is the +/// operand of address-of gets special treatment due to member pointers. /// ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, @@ -480,12 +484,15 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { }; } -/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is -/// true, parse a unary-expression. isAddressOfOperand exists because an -/// id-expression that is the operand of address-of gets special treatment -/// due to member pointers. NotCastExpr is set to true if the token is not the -/// start of a cast-expression, and no diagnostic is emitted in this case. +/// \brief Parse a cast-expression, or, if \pisUnaryExpression is true, parse +/// a unary-expression. /// +/// \p isAddressOfOperand exists because an id-expression that is the operand +/// of address-of gets special treatment due to member pointers. NotCastExpr +/// is set to true if the token is not the start of a cast-expression, and no +/// diagnostic is emitted in this case. +/// +/// \verbatim /// cast-expression: [C99 6.5.4] /// unary-expression /// '(' type-name ')' cast-expression @@ -500,6 +507,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { /// [C++11] 'sizeof' '...' '(' identifier ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' +/// [C11] '_Alignof' '(' type-name ')' /// [C++11] 'alignof' '(' type-id ')' /// [GNU] '&&' identifier /// [C++11] 'noexcept' '(' expression ')' [C++11 5.3.7] @@ -531,9 +539,9 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' /// [GNU] '__null' /// [OBJC] '[' objc-message-expr ']' -/// [OBJC] '@selector' '(' objc-selector-arg ')' -/// [OBJC] '@protocol' '(' identifier ')' -/// [OBJC] '@encode' '(' type-name ')' +/// [OBJC] '\@selector' '(' objc-selector-arg ')' +/// [OBJC] '\@protocol' '(' identifier ')' +/// [OBJC] '\@encode' '(' type-name ')' /// [OBJC] objc-string-literal /// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] /// [C++11] simple-type-specifier braced-init-list [C++11 5.2.3] @@ -641,6 +649,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { /// [Embarcadero] expression-trait: /// '__is_lvalue_expr' /// '__is_rvalue_expr' +/// \endverbatim /// ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, @@ -846,6 +855,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, break; case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2] case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU] + case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS] case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind); ConsumeToken(); @@ -912,12 +922,15 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return move(Res); } - case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression - // unary-expression: 'sizeof' '(' type-name ')' - case tok::kw_alignof: + case tok::kw__Alignof: // unary-expression: '_Alignof' '(' type-name ')' + if (!getLangOpts().C11) + Diag(Tok, diag::ext_c11_alignment) << Tok.getName(); + // fallthrough + case tok::kw_alignof: // unary-expression: 'alignof' '(' type-id ')' case tok::kw___alignof: // unary-expression: '__alignof' unary-expression // unary-expression: '__alignof' '(' type-name ')' - // unary-expression: 'alignof' '(' type-id ')' + case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression + // unary-expression: 'sizeof' '(' type-name ')' case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression return ParseUnaryExprOrTypeTraitExpression(); case tok::ampamp: { // unary-expression: '&&' identifier @@ -1228,9 +1241,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, return ParsePostfixExpressionSuffix(Res); } -/// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression -/// is parsed, this method parses any suffixes that apply. +/// \brief Once the leading part of a postfix-expression is parsed, this +/// method parses any suffixes that apply. /// +/// \verbatim /// postfix-expression: [C99 6.5.2] /// primary-expression /// postfix-expression '[' expression ']' @@ -1246,7 +1260,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// argument-expression-list: [C99 6.5.2] /// argument-expression ...[opt] /// argument-expression-list ',' assignment-expression ...[opt] -/// +/// \endverbatim ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Now that the primary-expression piece of the postfix-expression has been @@ -1498,11 +1512,13 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /// type-id. OpTok is the operand token (typeof/sizeof/alignof). Returns the /// expression (isCastExpr == false) or the type (isCastExpr == true). /// +/// \verbatim /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' +/// [C11] '_Alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' /// /// [GNU] typeof-specifier: @@ -1513,7 +1529,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /// [OpenCL 1.1 6.11.12] vec_step built-in function: /// vec_step ( expressions ) /// vec_step ( type-name ) -/// +/// \endverbatim ExprResult Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, bool &isCastExpr, @@ -1522,7 +1538,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) || OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof) || - OpTok.is(tok::kw_vec_step)) && + OpTok.is(tok::kw__Alignof) || OpTok.is(tok::kw_vec_step)) && "Not a typeof/sizeof/alignof/vec_step expression!"); ExprResult Operand; @@ -1571,17 +1587,22 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, } -/// ParseUnaryExprOrTypeTraitExpression - Parse a sizeof or alignof expression. +/// \brief Parse a sizeof or alignof expression. +/// +/// \verbatim /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [C++0x] 'sizeof' '...' '(' identifier ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' +/// [C11] '_Alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' +/// \endverbatim ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { - assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof) - || Tok.is(tok::kw_alignof) || Tok.is(tok::kw_vec_step)) && + assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof) || + Tok.is(tok::kw_alignof) || Tok.is(tok::kw__Alignof) || + Tok.is(tok::kw_vec_step)) && "Not a sizeof/alignof/vec_step expression!"); Token OpTok = Tok; ConsumeToken(); @@ -1629,7 +1650,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { RParenLoc); } - if (OpTok.is(tok::kw_alignof)) + if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw__Alignof)) Diag(OpTok, diag::warn_cxx98_compat_alignof); EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); @@ -1643,7 +1664,8 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { CastRange); UnaryExprOrTypeTrait ExprKind = UETT_SizeOf; - if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw___alignof)) + if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw___alignof) || + OpTok.is(tok::kw__Alignof)) ExprKind = UETT_AlignOf; else if (OpTok.is(tok::kw_vec_step)) ExprKind = UETT_VecStep; @@ -1667,6 +1689,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { /// ParseBuiltinPrimaryExpression /// +/// \verbatim /// primary-expression: [C99 6.5.1] /// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' /// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' @@ -1679,7 +1702,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { /// [GNU] identifier /// [GNU] offsetof-member-designator '.' identifier /// [GNU] offsetof-member-designator '[' expression ']' -/// +/// \endverbatim ExprResult Parser::ParseBuiltinPrimaryExpression() { ExprResult Res; const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo(); @@ -1869,6 +1892,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { /// in ExprType. If stopIfCastExpr is true, it will only return the parsed type, /// not the parsed cast-expression. /// +/// \verbatim /// primary-expression: [C99 6.5.1] /// '(' expression ')' /// [GNU] '(' compound-statement ')' (if !ParenExprOnly) @@ -1883,12 +1907,12 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { /// (__bridge type-name) cast-expression /// (__bridge_transfer type-name) cast-expression /// (__bridge_retained type-name) cast-expression +/// \endverbatim ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, bool isTypeCast, ParsedType &CastTy, SourceLocation &RParenLoc) { assert(Tok.is(tok::l_paren) && "Not a paren expr!"); - GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.consumeOpen()) return ExprError(); @@ -2102,10 +2126,11 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, /// ParseCompoundLiteralExpression - We have parsed the parenthesized type-name /// and we are at the left brace. /// +/// \verbatim /// postfix-expression: [C99 6.5.2] /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' -/// +/// \endverbatim ExprResult Parser::ParseCompoundLiteralExpression(ParsedType Ty, SourceLocation LParenLoc, @@ -2123,8 +2148,10 @@ Parser::ParseCompoundLiteralExpression(ParsedType Ty, /// form string literals, and also handles string concatenation [C99 5.1.1.2, /// translation phase #6]. /// +/// \verbatim /// primary-expression: [C99 6.5.1] /// string-literal +/// \verbatim ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) { assert(isTokenStringLiteral() && "Not a string literal!"); @@ -2145,6 +2172,7 @@ ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) { /// ParseGenericSelectionExpression - Parse a C11 generic-selection /// [C11 6.5.1.1]. /// +/// \verbatim /// generic-selection: /// _Generic ( assignment-expression , generic-assoc-list ) /// generic-assoc-list: @@ -2153,6 +2181,7 @@ ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) { /// generic-association: /// type-name : assignment-expression /// default : assignment-expression +/// \endverbatim ExprResult Parser::ParseGenericSelectionExpression() { assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected"); SourceLocation KeyLoc = ConsumeToken(); @@ -2239,6 +2268,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { /// ParseExpressionList - Used for C/C++ (argument-)expression-list. /// +/// \verbatim /// argument-expression-list: /// assignment-expression /// argument-expression-list , assignment-expression @@ -2257,7 +2287,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { /// [C++0x] initializer-clause: /// [C++0x] assignment-expression /// [C++0x] braced-init-list -/// +/// \endverbatim bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs, SmallVectorImpl<SourceLocation> &CommaLocs, void (Sema::*Completer)(Scope *S, @@ -2297,10 +2327,11 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs, /// ParseBlockId - Parse a block-id, which roughly looks like int (int x). /// +/// \verbatim /// [clang] block-id: /// [clang] specifier-qualifier-list block-declarator -/// -void Parser::ParseBlockId() { +/// \endverbatim +void Parser::ParseBlockId(SourceLocation CaretLoc) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); return cutOffParsing(); @@ -2320,18 +2351,19 @@ void Parser::ParseBlockId() { MaybeParseGNUAttributes(DeclaratorInfo); // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(DeclaratorInfo, getCurScope()); + Actions.ActOnBlockArguments(CaretLoc, DeclaratorInfo, getCurScope()); } /// ParseBlockLiteralExpression - Parse a block literal, which roughly looks /// like ^(int x){ return x+1; } /// +/// \verbatim /// block-literal: /// [clang] '^' block-args[opt] compound-statement /// [clang] '^' block-id compound-statement /// [clang] block-args: /// [clang] '(' parameter-list ')' -/// +/// \endverbatim ExprResult Parser::ParseBlockLiteralExpression() { assert(Tok.is(tok::caret) && "block literal starts with ^"); SourceLocation CaretLoc = ConsumeToken(); @@ -2377,13 +2409,13 @@ ExprResult Parser::ParseBlockLiteralExpression() { MaybeParseGNUAttributes(ParamInfo); // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(ParamInfo, getCurScope()); + Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); } else if (!Tok.is(tok::l_brace)) { - ParseBlockId(); + ParseBlockId(CaretLoc); } else { // Otherwise, pretend we saw (void). ParsedAttributes attrs(AttrFactory); - ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, + ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, false, SourceLocation(), 0, 0, 0, true, SourceLocation(), @@ -2400,7 +2432,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { MaybeParseGNUAttributes(ParamInfo); // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(ParamInfo, getCurScope()); + Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 715218448a3e..afac25793a73 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -36,7 +36,7 @@ static int SelectDigraphErrorMessage(tok::TokenKind Kind) { } // Are the two tokens adjacent in the same source file? -static bool AreTokensAdjacent(Preprocessor &PP, Token &First, Token &Second) { +bool Parser::areTokensAdjacent(const Token &First, const Token &Second) { SourceManager &SM = PP.getSourceManager(); SourceLocation FirstLoc = SM.getSpellingLoc(First.getLocation()); SourceLocation FirstEnd = FirstLoc.getLocWithOffset(First.getLength()); @@ -80,7 +80,7 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, return; Token SecondToken = GetLookAheadToken(2); - if (!SecondToken.is(tok::colon) || !AreTokensAdjacent(PP, Next, SecondToken)) + if (!SecondToken.is(tok::colon) || !areTokensAdjacent(Next, SecondToken)) return; TemplateTy Template; @@ -642,7 +642,13 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro){ while (Tok.isNot(tok::r_square)) { if (!first) { if (Tok.isNot(tok::comma)) { - if (Tok.is(tok::code_completion)) { + // Provide a completion for a lambda introducer here. Except + // in Objective-C, where this is Almost Surely meant to be a message + // send. In that case, fail here and let the ObjC message + // expression parser perform the completion. + if (Tok.is(tok::code_completion) && + !(getLangOpts().ObjC1 && Intro.Default == LCD_None && + !Intro.Captures.empty())) { Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, /*AfterAmpersand=*/false); ConsumeCodeCompletionToken(); @@ -792,10 +798,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( MaybeParseCXX0XAttributes(Attr, &DeclEndLoc); // Parse trailing-return-type[opt]. - ParsedType TrailingReturnType; + TypeResult TrailingReturnType; if (Tok.is(tok::arrow)) { SourceRange Range; - TrailingReturnType = ParseTrailingReturnType(Range).get(); + TrailingReturnType = ParseTrailingReturnType(Range); if (Range.getEnd().isValid()) DeclEndLoc = Range.getEnd(); } @@ -804,7 +810,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, /*isVariadic=*/EllipsisLoc.isValid(), - EllipsisLoc, + /*isAmbiguous=*/false, EllipsisLoc, ParamInfo.data(), ParamInfo.size(), DS.getTypeQualifiers(), /*RefQualifierIsLValueRef=*/true, @@ -838,10 +844,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( } // Parse the return type, if there is one. - ParsedType TrailingReturnType; + TypeResult TrailingReturnType; if (Tok.is(tok::arrow)) { SourceRange Range; - TrailingReturnType = ParseTrailingReturnType(Range).get(); + TrailingReturnType = ParseTrailingReturnType(Range); if (Range.getEnd().isValid()) DeclEndLoc = Range.getEnd(); } @@ -849,6 +855,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( ParsedAttributes Attr(AttrFactory); D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, /*isVariadic=*/false, + /*isAmbiguous=*/false, /*EllipsisLoc=*/SourceLocation(), /*Params=*/0, /*NumParams=*/0, /*TypeQuals=*/0, @@ -921,7 +928,7 @@ ExprResult Parser::ParseCXXCasts() { // 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)) + areTokensAdjacent(Tok, Next)) FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true); if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName)) @@ -1235,8 +1242,6 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { MultiExprArg(&InitList, 1), SourceLocation()); } else { - GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); - BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); @@ -1298,7 +1303,12 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, return true; } + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + if (!isCXXConditionDeclaration()) { + ProhibitAttributes(attrs); + // Parse the expression. ExprOut = ParseExpression(); // expression DeclOut = 0; @@ -1379,39 +1389,6 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, return false; } -/// \brief Determine whether the current token starts a C++ -/// simple-type-specifier. -bool Parser::isCXXSimpleTypeSpecifier() const { - switch (Tok.getKind()) { - case tok::annot_typename: - case tok::kw_short: - case tok::kw_long: - case tok::kw___int64: - case tok::kw___int128: - case tok::kw_signed: - case tok::kw_unsigned: - case tok::kw_void: - case tok::kw_char: - case tok::kw_int: - case tok::kw_half: - case tok::kw_float: - case tok::kw_double: - case tok::kw_wchar_t: - case tok::kw_char16_t: - case tok::kw_char32_t: - case tok::kw_bool: - case tok::kw_decltype: - case tok::kw_typeof: - case tok::kw___underlying_type: - return true; - - default: - break; - } - - return false; -} - /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. /// This should only be called when the current token is known to be part of /// simple-type-specifier. @@ -2426,10 +2403,14 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { // Array delete? bool ArrayDelete = false; if (Tok.is(tok::l_square) && NextToken().is(tok::r_square)) { - // FIXME: This could be the start of a lambda-expression. We should - // disambiguate this, but that will require arbitrary lookahead if - // the next token is '(': - // delete [](int*){ /* ... */ + // C++11 [expr.delete]p1: + // Whenever the delete keyword is followed by empty square brackets, it + // shall be interpreted as [array delete]. + // [Footnote: A lambda expression with a lambda-introducer that consists + // of empty square brackets can follow the delete keyword if + // the lambda expression is enclosed in parentheses.] + // FIXME: Produce a better diagnostic if the '[]' is unambiguously a + // lambda-introducer. ArrayDelete = true; BalancedDelimiterTracker T(*this, tok::l_square); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 789a8ae7a93a..db35a386c350 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -308,16 +308,16 @@ public: MethodImplKind(MethodImplKind) { } - Decl *invoke(FieldDeclarator &FD) { + void invoke(ParsingFieldDeclarator &FD) { if (FD.D.getIdentifier() == 0) { P.Diag(AtLoc, diag::err_objc_property_requires_field_name) << FD.D.getSourceRange(); - return 0; + return; } if (FD.BitfieldSize) { P.Diag(AtLoc, diag::err_objc_property_bitfield) << FD.D.getSourceRange(); - return 0; + return; } // Install the property declarator into interfaceDecl. @@ -344,7 +344,7 @@ public: if (!isOverridingProperty) Props.push_back(Property); - return Property; + FD.complete(Property); } }; @@ -375,9 +375,9 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, while (1) { // If this is a method prototype, parse it. if (Tok.is(tok::minus) || Tok.is(tok::plus)) { - Decl *methodPrototype = - ParseObjCMethodPrototype(MethodImplKind, false); - allMethods.push_back(methodPrototype); + if (Decl *methodPrototype = + ParseObjCMethodPrototype(MethodImplKind, false)) + allMethods.push_back(methodPrototype); // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for // method definitions. if (ExpectAndConsumeSemi(diag::err_expected_semi_after_method_proto)) { @@ -420,7 +420,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, // erroneous r_brace would cause an infinite loop if not handled here. if (Tok.is(tok::r_brace)) break; - ParsedAttributes attrs(AttrFactory); + ParsedAttributesWithRange attrs(AttrFactory); allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs)); continue; } @@ -493,7 +493,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, OCDS, AtLoc, LParenLoc, MethodImplKind); // Parse all the comma separated declarators. - DeclSpec DS(AttrFactory); + ParsingDeclSpec DS(*this); ParseStructDeclaration(DS, Callback); ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list); @@ -894,6 +894,7 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, DeclSpec declSpec(AttrFactory); declSpec.setObjCQualifiers(&DS); ParseSpecifierQualifierList(declSpec); + declSpec.SetRangeEnd(Tok.getLocation()); Declarator declarator(declSpec, context); ParseDeclarator(declarator); @@ -965,7 +966,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType, tok::ObjCKeywordKind MethodImplKind, bool MethodDefinition) { - ParsingDeclRAIIObject PD(*this); + ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, @@ -1000,8 +1001,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, if (!SelIdent && Tok.isNot(tok::colon)) { // missing selector name. Diag(Tok, diag::err_expected_selector_for_method) << SourceRange(mLoc, Tok.getLocation()); - // Skip until we get a ; or {}. - SkipUntil(tok::r_brace); + // Skip until we get a ; or @. + SkipUntil(tok::at, true /*StopAtSemi*/, true /*don't consume*/); return 0; } @@ -1105,7 +1106,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, } bool isVariadic = false; - + bool cStyleParamWarned = false; // Parse the (optional) parameter list. while (Tok.is(tok::comma)) { ConsumeToken(); @@ -1114,6 +1115,10 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ConsumeToken(); break; } + if (!cStyleParamWarned) { + Diag(Tok, diag::warn_cstyle_param); + cStyleParamWarned = true; + } DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS); // Parse the declarator. @@ -1125,7 +1130,6 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ParmDecl.getIdentifierLoc(), Param, 0)); - } // FIXME: Add support for optional parameter list... @@ -1258,9 +1262,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { - Diag(Tok, diag::ext_extra_ivar_semi) - << FixItHint::CreateRemoval(Tok.getLocation()); - ConsumeToken(); + ConsumeExtraSemi(InstanceVariableList); continue; } @@ -1304,7 +1306,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) { } - Decl *invoke(FieldDeclarator &FD) { + void invoke(ParsingFieldDeclarator &FD) { P.Actions.ActOnObjCContainerStartDefinition(IDecl); // Install the declarator into the interface decl. Decl *Field @@ -1314,12 +1316,12 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, P.Actions.ActOnObjCContainerFinishDefinition(); if (Field) AllIvarDecls.push_back(Field); - return Field; + FD.complete(Field); } } Callback(*this, interfaceDecl, visibility, AllIvarDecls); // Parse all the comma separated declarators. - DeclSpec DS(AttrFactory); + ParsingDeclSpec DS(*this); ParseStructDeclaration(DS, Callback); if (Tok.is(tok::semi)) { @@ -1348,15 +1350,15 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, /// objc-protocol-forward-reference /// /// objc-protocol-definition: -/// @protocol identifier +/// \@protocol identifier /// objc-protocol-refs[opt] /// objc-interface-decl-list -/// @end +/// \@end /// /// objc-protocol-forward-reference: -/// @protocol identifier-list ';' +/// \@protocol identifier-list ';' /// -/// "@protocol identifier ;" should be resolved as "@protocol +/// "\@protocol identifier ;" should be resolved as "\@protocol /// identifier-list ;": objc-interface-decl-list may not start with a /// semicolon in the first alternative if objc-protocol-refs are omitted. Parser::DeclGroupPtrTy @@ -1573,10 +1575,16 @@ void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) { assert(!Finished); P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl); for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i) - P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i]); + P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i], + true/*Methods*/); P.Actions.ActOnAtEnd(P.getCurScope(), AtEnd); + if (HasCFunction) + for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i) + P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i], + false/*c-functions*/); + /// \brief Clear and free the cached objc methods. for (LateParsedObjCMethodContainer::iterator I = LateParsedObjCMethods.begin(), @@ -1608,8 +1616,8 @@ Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { SourceLocation classLoc = ConsumeToken(); // consume class-name; ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@compatibility_alias"); - return Actions.ActOnCompatiblityAlias(atLoc, aliasId, aliasLoc, - classId, classLoc); + return Actions.ActOnCompatibilityAlias(atLoc, aliasId, aliasLoc, + classId, classLoc); } /// property-synthesis: @@ -1913,6 +1921,43 @@ Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) { AutoreleasePoolBody.take()); } +/// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them +/// for later parsing. +void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) { + LexedMethod* LM = new LexedMethod(this, MDecl); + CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM); + CachedTokens &Toks = LM->Toks; + // Begin by storing the '{' or 'try' or ':' token. + Toks.push_back(Tok); + if (Tok.is(tok::kw_try)) { + ConsumeToken(); + if (Tok.is(tok::colon)) { + Toks.push_back(Tok); + ConsumeToken(); + while (Tok.isNot(tok::l_brace)) { + ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false); + ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false); + } + } + Toks.push_back(Tok); // also store '{' + } + else if (Tok.is(tok::colon)) { + ConsumeToken(); + while (Tok.isNot(tok::l_brace)) { + ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false); + ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false); + } + Toks.push_back(Tok); // also store '{' + } + ConsumeBrace(); + // Consume everything up to (and including) the matching right brace. + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); + while (Tok.is(tok::kw_catch)) { + ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); + } +} + /// objc-method-def: objc-method-proto ';'[opt] '{' body '}' /// Decl *Parser::ParseObjCMethodDefinition() { @@ -1950,23 +1995,10 @@ Decl *Parser::ParseObjCMethodDefinition() { // Allow the rest of sema to find private method decl implementations. Actions.AddAnyMethodToGlobalPool(MDecl); - - if (CurParsedObjCImpl) { - // Consume the tokens and store them for later parsing. - LexedMethod* LM = new LexedMethod(this, MDecl); - CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM); - CachedTokens &Toks = LM->Toks; - // Begin by storing the '{' token. - Toks.push_back(Tok); - ConsumeBrace(); - // Consume everything up to (and including) the matching right brace. - ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); - - } else { - ConsumeBrace(); - SkipUntil(tok::r_brace, /*StopAtSemi=*/false); - } - + assert (CurParsedObjCImpl + && "ParseObjCMethodDefinition - Method out of @implementation"); + // Consume the tokens and store them for later parsing. + StashAwayMethodOrFunctionBodyTokens(MDecl); return MDecl; } @@ -2066,6 +2098,10 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { // Objective-C dictionary literal return ParsePostfixExpressionSuffix(ParseObjCDictionaryLiteral(AtLoc)); + case tok::l_paren: + // Objective-C boxed expression + return ParsePostfixExpressionSuffix(ParseObjCBoxedExpr(AtLoc)); + default: if (Tok.getIdentifierInfo() == 0) return ExprError(Diag(AtLoc, diag::err_unexpected_at)); @@ -2077,8 +2113,23 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc)); case tok::objc_selector: return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc)); - default: - return ExprError(Diag(AtLoc, diag::err_unexpected_at)); + default: { + const char *str = 0; + if (GetLookAheadToken(1).is(tok::l_brace)) { + char ch = Tok.getIdentifierInfo()->getNameStart()[0]; + str = + ch == 't' ? "try" + : (ch == 'f' ? "finally" + : (ch == 'a' ? "autoreleasepool" : 0)); + } + if (str) { + SourceLocation kwLoc = Tok.getLocation(); + return ExprError(Diag(AtLoc, diag::err_unexpected_at) << + FixItHint::CreateReplacement(kwLoc, str)); + } + else + return ExprError(Diag(AtLoc, diag::err_unexpected_at)); + } } } } @@ -2112,7 +2163,7 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) TryAnnotateTypeOrScopeToken(); - if (!isCXXSimpleTypeSpecifier()) { + if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) { // objc-receiver: // expression ExprResult Receiver = ParseExpression(); @@ -2449,10 +2500,14 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, } // Parse the, optional, argument list, comma separated. while (Tok.is(tok::comma)) { - ConsumeToken(); // Eat the ','. + SourceLocation commaLoc = ConsumeToken(); // Eat the ','. /// Parse the expression after ',' ExprResult Res(ParseAssignmentExpression()); if (Res.isInvalid()) { + if (Tok.is(tok::colon)) { + Diag(commaLoc, diag::note_extra_comma_message_arg) << + FixItHint::CreateRemoval(commaLoc); + } // We must manually skip to a ']', otherwise the expression skipper will // stop at the ']' when it skips to the ';'. We want it to skip beyond // the enclosing expression. @@ -2580,6 +2635,31 @@ ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) { return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take())); } +/// ParseObjCBoxedExpr - +/// objc-box-expression: +/// @( assignment-expression ) +ExprResult +Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) { + if (Tok.isNot(tok::l_paren)) + return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@"); + + BalancedDelimiterTracker T(*this, tok::l_paren); + T.consumeOpen(); + ExprResult ValueExpr(ParseAssignmentExpression()); + if (T.consumeClose()) + return ExprError(); + + if (ValueExpr.isInvalid()) + return ExprError(); + + // Wrap the sub-expression in a parenthesized expression, to distinguish + // a boxed expression from a literal. + SourceLocation LPLoc = T.getOpenLocation(), RPLoc = T.getCloseLocation(); + ValueExpr = Actions.ActOnParenExpr(LPLoc, RPLoc, ValueExpr.take()); + return Owned(Actions.BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc), + ValueExpr.take())); +} + ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) { ExprVector ElementExprs(Actions); // array elements. ConsumeBracket(); // consume the l_square. @@ -2698,7 +2778,7 @@ Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) { } /// objc-protocol-expression -/// @protocol ( protocol-name ) +/// \@protocol ( protocol-name ) ExprResult Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) { SourceLocation ProtoLoc = ConsumeToken(); @@ -2713,12 +2793,13 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) { return ExprError(Diag(Tok, diag::err_expected_ident)); IdentifierInfo *protocolId = Tok.getIdentifierInfo(); - ConsumeToken(); + SourceLocation ProtoIdLoc = ConsumeToken(); T.consumeClose(); return Owned(Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc, T.getOpenLocation(), + ProtoIdLoc, T.getCloseLocation())); } @@ -2785,8 +2866,15 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { T.getCloseLocation())); } -Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) { - +void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { + // MCDecl might be null due to error in method or c-function prototype, etc. + Decl *MCDecl = LM.D; + bool skip = MCDecl && + ((parseMethod && !Actions.isObjCMethodDecl(MCDecl)) || + (!parseMethod && Actions.isObjCMethodDecl(MCDecl))); + if (skip) + return; + // Save the current token position. SourceLocation OrigLoc = Tok.getLocation(); @@ -2796,40 +2884,32 @@ Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) { LM.Toks.push_back(Tok); PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); - // MDecl might be null due to error in method prototype, etc. - Decl *MDecl = LM.D; // Consume the previously pushed token. ConsumeAnyToken(); - assert(Tok.is(tok::l_brace) && "Inline objective-c method not starting with '{'"); - SourceLocation BraceLoc = Tok.getLocation(); - // Enter a scope for the method body. + assert((Tok.is(tok::l_brace) || Tok.is(tok::kw_try) || + Tok.is(tok::colon)) && + "Inline objective-c method not starting with '{' or 'try' or ':'"); + // Enter a scope for the method or c-fucntion body. ParseScope BodyScope(this, - Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope); - - // Tell the actions module that we have entered a method definition with the - // specified Declarator for the method. - Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl); - - if (SkipFunctionBodies && trySkippingFunctionBody()) { - BodyScope.Exit(); - return Actions.ActOnFinishFunctionBody(MDecl, 0); - } - - StmtResult FnBody(ParseCompoundStatementBody()); + parseMethod + ? Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope + : Scope::FnScope|Scope::DeclScope); - // If the function body could not be parsed, make a bogus compoundstmt. - if (FnBody.isInvalid()) { - Sema::CompoundScopeRAII CompoundScope(Actions); - FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc, - MultiStmtArg(Actions), false); + // Tell the actions module that we have entered a method or c-function definition + // with the specified Declarator for the method/function. + if (parseMethod) + Actions.ActOnStartOfObjCMethodDef(getCurScope(), MCDecl); + else + Actions.ActOnStartOfFunctionDef(getCurScope(), MCDecl); + if (Tok.is(tok::kw_try)) + MCDecl = ParseFunctionTryBlock(MCDecl, BodyScope); + else { + if (Tok.is(tok::colon)) + ParseConstructorInitializer(MCDecl); + MCDecl = ParseFunctionStatementBody(MCDecl, BodyScope); } - - // Leave the function body scope. - BodyScope.Exit(); - - MDecl = Actions.ActOnFinishFunctionBody(MDecl, FnBody.take()); - + if (Tok.getLocation() != OrigLoc) { // Due to parsing error, we either went over the cached tokens or // there are still cached tokens left. If it's the latter case skip the @@ -2842,5 +2922,5 @@ Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) { ConsumeAnyToken(); } - return MDecl; + return; } diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h index ebb185ad1a98..fef6960813d8 100644 --- a/lib/Parse/ParsePragma.h +++ b/lib/Parse/ParsePragma.h @@ -30,10 +30,9 @@ public: }; class PragmaGCCVisibilityHandler : public PragmaHandler { - Sema &Actions; public: - explicit PragmaGCCVisibilityHandler(Sema &A) : PragmaHandler("visibility"), - Actions(A) {} + explicit PragmaGCCVisibilityHandler(Sema &/*A*/) + : PragmaHandler("visibility") {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); @@ -70,11 +69,9 @@ public: }; class PragmaUnusedHandler : public PragmaHandler { - Sema &Actions; - Parser &parser; public: - PragmaUnusedHandler(Sema &A, Parser& p) - : PragmaHandler("unused"), Actions(A), parser(p) {} + PragmaUnusedHandler(Sema &/*A*/) + : PragmaHandler("unused") {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); @@ -102,10 +99,9 @@ public: class PragmaOpenCLExtensionHandler : public PragmaHandler { Sema &Actions; - Parser &parser; public: - PragmaOpenCLExtensionHandler(Sema &S, Parser& p) : - PragmaHandler("EXTENSION"), Actions(S), parser(p) {} + PragmaOpenCLExtensionHandler(Sema &A) : + PragmaHandler("EXTENSION"), Actions(A) {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); }; @@ -113,10 +109,9 @@ public: class PragmaFPContractHandler : public PragmaHandler { Sema &Actions; - Parser &parser; public: - PragmaFPContractHandler(Sema &S, Parser& p) : - PragmaHandler("FP_CONTRACT"), Actions(S), parser(p) {} + PragmaFPContractHandler(Sema &A) : + PragmaHandler("FP_CONTRACT"), Actions(A) {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); }; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 44320dfcb3bf..d2e4309c3f4e 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -20,6 +20,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Basic/SourceManager.h" +#include "llvm/ADT/SmallString.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -771,7 +772,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { DeclsInGroup.data(), DeclsInGroup.size()); StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation()); - ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); + ExpectAndConsumeSemi(diag::err_expected_semi_declaration); if (R.isUsable()) Stmts.push_back(R.release()); } @@ -895,6 +896,16 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, // Otherwise the condition is valid or the rparen is present. T.consumeClose(); + + // Check for extraneous ')'s to catch things like "if (foo())) {". We know + // that all callers are looking for a statement after the condition, so ")" + // isn't valid. + while (Tok.is(tok::r_paren)) { + Diag(Tok, diag::err_extraneous_rparen_in_condition) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeParen(); + } + return false; } @@ -938,7 +949,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true)) return StmtError(); - FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp.get())); + FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp.get(), IfLoc)); // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this @@ -1164,7 +1175,7 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) { if (ParseParenExprOrCondition(Cond, CondVar, WhileLoc, true)) return StmtError(); - FullExprArg FullCond(Actions.MakeFullExpr(Cond.get())); + FullExprArg FullCond(Actions.MakeFullExpr(Cond.get(), WhileLoc)); // 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 @@ -1248,6 +1259,12 @@ StmtResult Parser::ParseDoStatement() { // Parse the parenthesized condition. BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); + + // FIXME: Do not just parse the attribute contents and throw them away + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + ProhibitAttributes(attrs); + ExprResult Cond = ParseExpression(); T.consumeClose(); DoScope.Exit(); @@ -1288,7 +1305,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { return StmtError(); } - bool C99orCXXorObjC = getLangOpts().C99 || getLangOpts().CPlusPlus || getLangOpts().ObjC1; + bool C99orCXXorObjC = getLangOpts().C99 || getLangOpts().CPlusPlus || + getLangOpts().ObjC1; // C99 6.8.5p5 - In C99, the for statement is a block. This is not // the case for C90. Start the loop scope. @@ -1336,8 +1354,12 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { return StmtError(); } + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + // Parse the first part of the for specifier. if (Tok.is(tok::semi)) { // for (; + ProhibitAttributes(attrs); // no first part, eat the ';'. ConsumeToken(); } else if (isForInitDeclaration()) { // for (int X = 4; @@ -1382,6 +1404,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { Diag(Tok, diag::err_expected_semi_for); } } else { + ProhibitAttributes(attrs); Value = ParseExpression(); ForEach = isTokIdentifier_in(); @@ -1441,7 +1464,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { Second.get()); } SecondPartIsInvalid = Second.isInvalid(); - SecondPart = Actions.MakeFullExpr(Second.get()); + SecondPart = Actions.MakeFullExpr(Second.get(), ForLoc); } if (Tok.isNot(tok::semi)) { @@ -1469,6 +1492,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { // statememt before parsing the body, in order to be able to deduce the type // of an auto-typed loop variable. StmtResult ForRangeStmt; + StmtResult ForEachStmt; + if (ForRange) { ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, T.getOpenLocation(), FirstPart.take(), @@ -1480,9 +1505,10 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { // Similarly, we need to do the semantic analysis for a for-range // statement immediately in order to close over temporaries correctly. } else if (ForEach) { - if (!Collection.isInvalid()) - Collection = - Actions.ActOnObjCForCollectionOperand(ForLoc, Collection.take()); + ForEachStmt = Actions.ActOnObjCForCollectionStmt(ForLoc, T.getOpenLocation(), + FirstPart.take(), + Collection.take(), + T.getCloseLocation()); } // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if @@ -1512,11 +1538,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { return StmtError(); if (ForEach) - return Actions.ActOnObjCForCollectionStmt(ForLoc, T.getOpenLocation(), - FirstPart.take(), - Collection.take(), - T.getCloseLocation(), - Body.take()); + return Actions.FinishObjCForCollectionStmt(ForEachStmt.take(), + Body.take()); if (ForRange) return Actions.FinishCXXForRangeStmt(ForRangeStmt.take(), Body.take()); @@ -1617,9 +1640,24 @@ StmtResult Parser::ParseReturnStatement() { /// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled, /// this routine is called to collect the tokens for an MS asm statement. +/// +/// [MS] ms-asm-statement: +/// ms-asm-block +/// ms-asm-block ms-asm-statement +/// +/// [MS] ms-asm-block: +/// '__asm' ms-asm-line '\n' +/// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt] +/// +/// [MS] ms-asm-instruction-block +/// ms-asm-line +/// ms-asm-line '\n' ms-asm-instruction-block +/// StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { SourceManager &SrcMgr = PP.getSourceManager(); SourceLocation EndLoc = AsmLoc; + SmallVector<Token, 4> AsmToks; + SmallVector<unsigned, 4> LineEnds; do { bool InBraces = false; unsigned short savedBraceCount = 0; @@ -1648,8 +1686,10 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { // If we hit EOF, we're done, period. if (Tok.is(tok::eof)) break; - // When we consume the closing brace, we're done. - if (InBraces && BraceCount == savedBraceCount) + + // The asm keyword is a statement separator, so multiple asm statements + // are allowed. + if (!InAsmComment && Tok.is(tok::kw_asm)) break; if (!InAsmComment && Tok.is(tok::semi)) { @@ -1681,18 +1721,28 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { break; } } + if (!InAsmComment && InBraces && Tok.is(tok::r_brace) && + BraceCount == (savedBraceCount + 1)) { + // Consume the closing brace, and finish + EndLoc = ConsumeBrace(); + break; + } // Consume the next token; make sure we don't modify the brace count etc. // if we are in a comment. EndLoc = TokLoc; if (InAsmComment) PP.Lex(Tok); - else + else { + AsmToks.push_back(Tok); ConsumeAnyToken(); + } TokLoc = Tok.getLocation(); ++NumTokensRead; } while (1); + LineEnds.push_back(AsmToks.size()); + if (InBraces && BraceCount != savedBraceCount) { // __asm without closing brace (this can happen at EOF). Diag(Tok, diag::err_expected_rbrace); @@ -1709,24 +1759,10 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { break; EndLoc = ConsumeToken(); } while (1); - // FIXME: Need to actually grab the data and pass it on to Sema. Ideally, - // what Sema wants is a string of the entire inline asm, with one instruction - // per line and all the __asm keywords stripped out, and a way of mapping - // from any character of that string to its location in the original source - // code. I'm not entirely sure how to go about that, though. - Token t; - t.setKind(tok::string_literal); - t.setLiteralData("\"/*FIXME: not done*/\""); - t.clearFlag(Token::NeedsCleaning); - t.setLength(21); - ExprResult AsmString(Actions.ActOnStringLiteral(&t, 1)); - ExprVector Constraints(Actions); - ExprVector Exprs(Actions); - ExprVector Clobbers(Actions); - return Actions.ActOnAsmStmt(AsmLoc, true, true, 0, 0, 0, - move_arg(Constraints), move_arg(Exprs), - AsmString.take(), move_arg(Clobbers), - EndLoc, true); + + // FIXME: We should be passing source locations for better diagnostics. + return Actions.ActOnMSAsmStmt(AsmLoc, llvm::makeArrayRef(AsmToks), + llvm::makeArrayRef(LineEnds), EndLoc); } /// ParseAsmStatement - Parse a GNU extended asm statement. @@ -1748,23 +1784,12 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { /// asm-string-literal /// asm-clobbers ',' asm-string-literal /// -/// [MS] ms-asm-statement: -/// ms-asm-block -/// ms-asm-block ms-asm-statement -/// -/// [MS] ms-asm-block: -/// '__asm' ms-asm-line '\n' -/// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt] -/// -/// [MS] ms-asm-instruction-block -/// ms-asm-line -/// ms-asm-line '\n' ms-asm-instruction-block -/// StmtResult Parser::ParseAsmStatement(bool &msAsm) { assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); SourceLocation AsmLoc = ConsumeToken(); - if (getLangOpts().MicrosoftExt && Tok.isNot(tok::l_paren) && !isTypeQualifier()) { + if (getLangOpts().MicrosoftExt && Tok.isNot(tok::l_paren) && + !isTypeQualifier()) { msAsm = true; return ParseMicrosoftAsmStatement(AsmLoc); } @@ -2067,7 +2092,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { return move(TryBlock); // Borland allows SEH-handlers with 'try' - + if ((Tok.is(tok::identifier) && Tok.getIdentifierInfo() == getSEHExceptKeyword()) || Tok.is(tok::kw___finally)) { @@ -2107,7 +2132,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Handlers.empty()) return StmtError(); - return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), move_arg(Handlers)); + return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(),move_arg(Handlers)); } } @@ -2203,10 +2228,10 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { case IEB_Parse: // Parse the statements below. break; - + case IEB_Dependent: llvm_unreachable("Dependent case handled above"); - + case IEB_Skip: Braces.skipToEnd(); return; diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 5c3e2ba589ff..ade918fb221a 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -90,7 +90,8 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // Tell the action that names should be checked in the context of // the declaration to come. - ParsingDeclRAIIObject ParsingTemplateParams(*this); + ParsingDeclRAIIObject + ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); // Parse multiple levels of template headers within this template // parameter scope, e.g., @@ -213,11 +214,15 @@ Parser::ParseSingleDeclarationAfterTemplate( return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, prefixAttrs); - // Parse the declaration specifiers, stealing the accumulated - // diagnostics from the template parameters. + // Parse the declaration specifiers, stealing any diagnostics from + // the template parameters. ParsingDeclSpec DS(*this, &DiagsFromTParams); - DS.takeAttributesFrom(prefixAttrs); + // Move the attributes from the prefix into the DS. + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + ProhibitAttributes(prefixAttrs); + else + DS.takeAttributesFrom(prefixAttrs); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, getDeclSpecContextFromDeclaratorContext(Context)); @@ -259,7 +264,7 @@ Parser::ParseSingleDeclarationAfterTemplate( } // Eat the semi colon after the declaration. - ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); + ExpectAndConsumeSemi(diag::err_expected_semi_declaration); if (LateParsedAttrs.size() > 0) ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false); DeclaratorInfo.complete(ThisDecl); @@ -314,6 +319,11 @@ bool Parser::ParseTemplateParameters(unsigned Depth, Failed = ParseTemplateParameterList(Depth, TemplateParams); if (Tok.is(tok::greatergreater)) { + // No diagnostic required here: a template-parameter-list can only be + // followed by a declaration or, for a template template parameter, the + // 'class' keyword. Therefore, the second '>' will be diagnosed later. + // This matters for elegant diagnosis of: + // template<template<typename>> struct S; Tok.setKind(tok::greater); RAngleLoc = Tok.getLocation(); Tok.setLocation(Tok.getLocation().getLocWithOffset(1)); @@ -711,34 +721,104 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, } } - if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater)) { + // What will be left once we've consumed the '>'. + tok::TokenKind RemainingToken; + const char *ReplacementStr = "> >"; + + switch (Tok.getKind()) { + default: Diag(Tok.getLocation(), diag::err_expected_greater); return true; - } - // Determine the location of the '>' or '>>'. Only consume this - // token if the caller asked us to. - RAngleLoc = Tok.getLocation(); + case tok::greater: + // Determine the location of the '>' token. Only consume this token + // if the caller asked us to. + RAngleLoc = Tok.getLocation(); + if (ConsumeLastToken) + ConsumeToken(); + return false; - if (Tok.is(tok::greatergreater)) { - const char *ReplaceStr = "> >"; - if (NextToken().is(tok::greater) || NextToken().is(tok::greatergreater)) - ReplaceStr = "> > "; + case tok::greatergreater: + RemainingToken = tok::greater; + break; - Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? - diag::warn_cxx98_compat_two_right_angle_brackets : - diag::err_two_right_angle_brackets_need_space) - << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), - ReplaceStr); + case tok::greatergreatergreater: + RemainingToken = tok::greatergreater; + break; - Tok.setKind(tok::greater); - if (!ConsumeLastToken) { - // Since we're not supposed to consume the '>>' token, we need - // to insert a second '>' token after the first. - PP.EnterToken(Tok); - } - } else if (ConsumeLastToken) + case tok::greaterequal: + RemainingToken = tok::equal; + ReplacementStr = "> ="; + break; + + case tok::greatergreaterequal: + RemainingToken = tok::greaterequal; + break; + } + + // This template-id is terminated by a token which starts with a '>'. Outside + // C++11, this is now error recovery, and in C++11, this is error recovery if + // the token isn't '>>'. + + RAngleLoc = Tok.getLocation(); + + // The source range of the '>>' or '>=' at the start of the token. + CharSourceRange ReplacementRange = + CharSourceRange::getCharRange(RAngleLoc, + Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(), + getLangOpts())); + + // A hint to put a space between the '>>'s. In order to make the hint as + // clear as possible, we include the characters either side of the space in + // the replacement, rather than just inserting a space at SecondCharLoc. + FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange, + ReplacementStr); + + // A hint to put another space after the token, if it would otherwise be + // lexed differently. + FixItHint Hint2; + Token Next = NextToken(); + if ((RemainingToken == tok::greater || + RemainingToken == tok::greatergreater) && + (Next.is(tok::greater) || Next.is(tok::greatergreater) || + Next.is(tok::greatergreatergreater) || Next.is(tok::equal) || + Next.is(tok::greaterequal) || Next.is(tok::greatergreaterequal) || + Next.is(tok::equalequal)) && + areTokensAdjacent(Tok, Next)) + Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " "); + + unsigned DiagId = diag::err_two_right_angle_brackets_need_space; + if (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater)) + DiagId = diag::warn_cxx98_compat_two_right_angle_brackets; + else if (Tok.is(tok::greaterequal)) + DiagId = diag::err_right_angle_bracket_equal_needs_space; + Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2; + + // Strip the initial '>' from the token. + if (RemainingToken == tok::equal && Next.is(tok::equal) && + areTokensAdjacent(Tok, Next)) { + // Join two adjacent '=' tokens into one, for cases like: + // void (*p)() = f<int>; + // return f<int>==p; ConsumeToken(); + Tok.setKind(tok::equalequal); + Tok.setLength(Tok.getLength() + 1); + } else { + Tok.setKind(RemainingToken); + Tok.setLength(Tok.getLength() - 1); + } + Tok.setLocation(Lexer::AdvanceToTokenCharacter(RAngleLoc, 1, + PP.getSourceManager(), + getLangOpts())); + + if (!ConsumeLastToken) { + // Since we're not supposed to consume the '>' token, we need to push + // this token and revert the current token back to the '>'. + PP.EnterToken(Tok); + Tok.setKind(tok::greater); + Tok.setLength(1); + Tok.setLocation(RAngleLoc); + } return false; } @@ -1132,7 +1212,8 @@ Decl *Parser::ParseExplicitInstantiation(unsigned Context, SourceLocation &DeclEnd, AccessSpecifier AS) { // This isn't really required here. - ParsingDeclRAIIObject ParsingTemplateParams(*this); + ParsingDeclRAIIObject + ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); return ParseSingleDeclarationAfterTemplate(Context, ParsedTemplateInfo(ExternLoc, diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 28c5e8b67370..1a4df4791b5f 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -671,7 +671,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // initializer that follows the declarator. Note that ctor-style // initializers are not possible in contexts where abstract declarators // are allowed. - if (!mayBeAbstract && !isCXXFunctionDeclarator(false/*warnIfAmbiguous*/)) + if (!mayBeAbstract && !isCXXFunctionDeclarator()) break; // direct-declarator '(' parameter-declaration-clause ')' @@ -735,6 +735,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_alignof: case tok::kw_noexcept: case tok::kw_nullptr: + case tok::kw__Alignof: case tok::kw___null: case tok::kw___alignof: case tok::kw___builtin_choose_expr: @@ -744,6 +745,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___imag: case tok::kw___real: case tok::kw___FUNCTION__: + case tok::kw_L__FUNCTION__: case tok::kw___PRETTY_FUNCTION__: case tok::kw___has_nothrow_assign: case tok::kw___has_nothrow_copy: @@ -827,6 +829,10 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { /// be either a decl-specifier or a function-style cast, and TPResult::Error() /// if a parsing error was found and reported. /// +/// If HasMissingTypename is provided, a name with a dependent scope specifier +/// will be treated as ambiguous if the 'typename' keyword is missing. If this +/// happens, *HasMissingTypename will be set to 'true'. +/// /// decl-specifier: /// storage-class-specifier /// type-specifier @@ -918,7 +924,8 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { /// [GNU] restrict /// Parser::TPResult -Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) { +Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, + bool *HasMissingTypename) { switch (Tok.getKind()) { case tok::identifier: // foo::bar // Check for need to substitute AltiVec __vector keyword @@ -931,9 +938,12 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) { // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return TPResult::Error(); - if (Tok.is(tok::identifier)) - return TPResult::False(); - return isCXXDeclarationSpecifier(BracedCastResult); + if (Tok.is(tok::identifier)) { + const Token &Next = NextToken(); + return (!getLangOpts().ObjC1 && Next.is(tok::identifier)) ? + TPResult::True() : TPResult::False(); + } + return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); case tok::coloncolon: { // ::foo::bar const Token &Next = NextToken(); @@ -947,7 +957,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) { // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return TPResult::Error(); - return isCXXDeclarationSpecifier(BracedCastResult); + return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); // decl-specifier: // storage-class-specifier @@ -1049,12 +1059,20 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) { bool isIdentifier = Tok.is(tok::identifier); TPResult TPR = TPResult::False(); if (!isIdentifier) - TPR = isCXXDeclarationSpecifier(BracedCastResult); + TPR = isCXXDeclarationSpecifier(BracedCastResult, + HasMissingTypename); PA.Revert(); if (isIdentifier || TPR == TPResult::True() || TPR == TPResult::Error()) return TPResult::Error(); + + if (HasMissingTypename) { + // We can't tell whether this is a missing 'typename' or a valid + // expression. + *HasMissingTypename = true; + return TPResult::Ambiguous(); + } } } return TPResult::False(); @@ -1218,21 +1236,24 @@ Parser::TPResult Parser::TryParseProtocolQualifiers() { return TPResult::Error(); } -Parser::TPResult Parser::TryParseDeclarationSpecifier() { - TPResult TPR = isCXXDeclarationSpecifier(); +Parser::TPResult +Parser::TryParseDeclarationSpecifier(bool *HasMissingTypename) { + TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(), + HasMissingTypename); if (TPR != TPResult::Ambiguous()) return TPR; if (Tok.is(tok::kw_typeof)) TryParseTypeofSpecifier(); else { + if (Tok.is(tok::annot_cxxscope)) + ConsumeToken(); ConsumeToken(); if (getLangOpts().ObjC1 && Tok.is(tok::less)) TryParseProtocolQualifiers(); } - assert(Tok.is(tok::l_paren) && "Expected '('!"); return TPResult::Ambiguous(); } @@ -1246,7 +1267,7 @@ Parser::TPResult Parser::TryParseDeclarationSpecifier() { /// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] /// exception-specification[opt] /// -bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) { +bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) { // C++ 8.2p1: // The ambiguity arising from the similarity between a function-style cast and @@ -1260,27 +1281,36 @@ bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) { TentativeParsingAction PA(*this); ConsumeParen(); - TPResult TPR = TryParseParameterDeclarationClause(); - if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren)) - TPR = TPResult::False(); + bool InvalidAsDeclaration = false; + TPResult TPR = TryParseParameterDeclarationClause(&InvalidAsDeclaration); + if (TPR == TPResult::Ambiguous()) { + if (Tok.isNot(tok::r_paren)) + TPR = TPResult::False(); + else { + const Token &Next = NextToken(); + if (Next.is(tok::amp) || Next.is(tok::ampamp) || + Next.is(tok::kw_const) || Next.is(tok::kw_volatile) || + Next.is(tok::kw_throw) || Next.is(tok::kw_noexcept) || + Next.is(tok::l_square) || isCXX0XVirtSpecifier(Next) || + Next.is(tok::l_brace) || Next.is(tok::kw_try) || + Next.is(tok::equal) || Next.is(tok::arrow)) + // The next token cannot appear after a constructor-style initializer, + // and can appear next in a function definition. This must be a function + // declarator. + TPR = TPResult::True(); + else if (InvalidAsDeclaration) + // Use the absence of 'typename' as a tie-breaker. + TPR = TPResult::False(); + } + } - SourceLocation TPLoc = Tok.getLocation(); PA.Revert(); - // In case of an error, let the declaration parsing code handle it. - if (TPR == TPResult::Error()) - return true; + if (IsAmbiguous && TPR == TPResult::Ambiguous()) + *IsAmbiguous = true; - if (TPR == TPResult::Ambiguous()) { - // Function declarator has precedence over constructor-style initializer. - // Emit a warning just in case the author intended a variable definition. - if (warnIfAmbiguous) - Diag(Tok, diag::warn_parens_disambiguated_as_function_decl) - << SourceRange(Tok.getLocation(), TPLoc); - return true; - } - - return TPR == TPResult::True(); + // In case of an error, let the declaration parsing code handle it. + return TPR != TPResult::False(); } /// parameter-declaration-clause: @@ -1300,10 +1330,11 @@ bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) { /// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] /// attributes[opt] '=' assignment-expression /// -Parser::TPResult Parser::TryParseParameterDeclarationClause() { +Parser::TPResult +Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) { if (Tok.is(tok::r_paren)) - return TPResult::True(); + return TPResult::Ambiguous(); // parameter-declaration-list[opt] '...'[opt] // parameter-declaration-list ',' '...' @@ -1333,7 +1364,7 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() { // decl-specifier-seq // A parameter-declaration's initializer must be preceded by an '=', so // decl-specifier-seq '{' is not a parameter in C++11. - TPResult TPR = TryParseDeclarationSpecifier(); + TPResult TPR = TryParseDeclarationSpecifier(InvalidAsDeclaration); if (TPR != TPResult::Ambiguous()) return TPR; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index f1b99fb0a129..3725e2b84550 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -23,6 +23,22 @@ #include "clang/AST/ASTConsumer.h" using namespace clang; +namespace { +/// \brief A comment handler that passes comments found by the preprocessor +/// to the parser action. +class ActionCommentHandler : public CommentHandler { + Sema &S; + +public: + explicit ActionCommentHandler(Sema &S) : S(S) { } + + virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) { + S.ActOnComment(Comment); + return false; + } +}; +} // end anonymous namespace + IdentifierInfo *Parser::getSEHExceptKeyword() { // __except is accepted as a (contextual) keyword if (!Ident__except && (getLangOpts().MicrosoftExt || getLangOpts().Borland)) @@ -35,7 +51,7 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies) : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), GreaterThanIsOperator(true), ColonIsSacred(false), InMessageExpression(false), TemplateParameterDepth(0), - SkipFunctionBodies(SkipFunctionBodies) { + ParsingInObjCContainer(false), SkipFunctionBodies(SkipFunctionBodies) { Tok.setKind(tok::eof); Actions.CurScope = 0; NumCachedScopes = 0; @@ -59,7 +75,7 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies) MSStructHandler.reset(new PragmaMSStructHandler(actions)); PP.AddPragmaHandler(MSStructHandler.get()); - UnusedHandler.reset(new PragmaUnusedHandler(actions, *this)); + UnusedHandler.reset(new PragmaUnusedHandler(actions)); PP.AddPragmaHandler(UnusedHandler.get()); WeakHandler.reset(new PragmaWeakHandler(actions)); @@ -68,17 +84,19 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies) RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler(actions)); PP.AddPragmaHandler(RedefineExtnameHandler.get()); - FPContractHandler.reset(new PragmaFPContractHandler(actions, *this)); + FPContractHandler.reset(new PragmaFPContractHandler(actions)); PP.AddPragmaHandler("STDC", FPContractHandler.get()); if (getLangOpts().OpenCL) { - OpenCLExtensionHandler.reset( - new PragmaOpenCLExtensionHandler(actions, *this)); + OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler(actions)); PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get()); PP.AddPragmaHandler("OPENCL", FPContractHandler.get()); } - + + CommentSemaHandler.reset(new ActionCommentHandler(actions)); + PP.addCommentHandler(CommentSemaHandler.get()); + PP.setCodeCompletionHandler(*this); } @@ -185,7 +203,7 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, bool Parser::ExpectAndConsumeSemi(unsigned DiagID) { if (Tok.is(tok::semi) || Tok.is(tok::code_completion)) { - ConsumeAnyToken(); + ConsumeToken(); return false; } @@ -202,6 +220,42 @@ bool Parser::ExpectAndConsumeSemi(unsigned DiagID) { return ExpectAndConsume(tok::semi, DiagID); } +void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) { + if (!Tok.is(tok::semi)) return; + + bool HadMultipleSemis = false; + SourceLocation StartLoc = Tok.getLocation(); + SourceLocation EndLoc = Tok.getLocation(); + ConsumeToken(); + + while ((Tok.is(tok::semi) && !Tok.isAtStartOfLine())) { + HadMultipleSemis = true; + EndLoc = Tok.getLocation(); + ConsumeToken(); + } + + // C++11 allows extra semicolons at namespace scope, but not in any of the + // other contexts. + if (Kind == OutsideFunction && getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus0x) + Diag(StartLoc, diag::warn_cxx98_compat_top_level_semi) + << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc)); + else + Diag(StartLoc, diag::ext_extra_semi_cxx11) + << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc)); + return; + } + + if (Kind != AfterMemberFunctionDefinition || HadMultipleSemis) + Diag(StartLoc, diag::ext_extra_semi) + << Kind << DeclSpec::getSpecifierName((DeclSpec::TST)TST) + << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc)); + else + // A single semicolon is valid after a member function definition. + Diag(StartLoc, diag::warn_extra_semi_after_mem_fn_def) + << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc)); +} + //===----------------------------------------------------------------------===// // Error recovery. //===----------------------------------------------------------------------===// @@ -396,6 +450,9 @@ Parser::~Parser() { PP.RemovePragmaHandler("STDC", FPContractHandler.get()); FPContractHandler.reset(); + + PP.removeCommentHandler(CommentSemaHandler.get()); + PP.clearCodeCompletionHandler(); assert(TemplateIds.empty() && "Still alive TemplateIdAnnotations around?"); @@ -412,10 +469,6 @@ void Parser::Initialize() { // Prime the lexer look-ahead. ConsumeToken(); - if (Tok.is(tok::eof) && - !getLangOpts().CPlusPlus) // Empty source file is an extension in C - Diag(Tok, diag::ext_empty_source_file); - // Initialization for Objective-C context sensitive keywords recognition. // Referenced in Parser::ParseObjCTypeQualifierList. if (getLangOpts().ObjC1) { @@ -582,11 +635,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, HandlePragmaPack(); return DeclGroupPtrTy(); case tok::semi: - Diag(Tok, getLangOpts().CPlusPlus0x ? - diag::warn_cxx98_compat_top_level_semi : diag::ext_top_level_semi) - << FixItHint::CreateRemoval(Tok.getLocation()); - - ConsumeToken(); + ConsumeExtraSemi(OutsideFunction); // TODO: Invoke action for top-level semicolon. return DeclGroupPtrTy(); case tok::r_brace: @@ -641,7 +690,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, 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. + // A function definition cannot start with any of these keywords. { SourceLocation DeclEnd; StmtVector Stmts(Actions); @@ -708,8 +757,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, dont_know: // We can't tell whether this is a function-definition or declaration yet. if (DS) { - DS->takeAttributesFrom(attrs); - return ParseDeclarationOrFunctionDefinition(*DS); + return ParseDeclarationOrFunctionDefinition(attrs, DS); } else { return ParseDeclarationOrFunctionDefinition(attrs); } @@ -729,7 +777,7 @@ bool Parser::isDeclarationAfterDeclarator() { if (KW.is(tok::kw_default) || KW.is(tok::kw_delete)) return false; } - + return Tok.is(tok::equal) || // int X()= -> not a function def Tok.is(tok::comma) || // int X(), -> not a function def Tok.is(tok::semi) || // int X(); -> not a function def @@ -777,20 +825,24 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) { /// [OMP] threadprivate-directive [TODO] /// Parser::DeclGroupPtrTy -Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, - AccessSpecifier AS) { +Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, + ParsingDeclSpec &DS, + AccessSpecifier AS) { // Parse the common declaration-specifiers piece. ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { + ProhibitAttributes(attrs); ConsumeToken(); Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } + DS.takeAttributesFrom(attrs); + // ObjC2 allows prefix attributes on class interfaces and protocols. // FIXME: This still needs better diagnostics. We should only accept // attributes here, no types, etc. @@ -831,16 +883,20 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, } Parser::DeclGroupPtrTy -Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs, +Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs, + ParsingDeclSpec *DS, AccessSpecifier AS) { - ParsingDeclSpec DS(*this); - DS.takeAttributesFrom(attrs); - // Must temporarily exit the objective-c container scope for - // parsing c constructs and re-enter objc container scope - // afterwards. - ObjCDeclContextSwitch ObjCDC(*this); - - return ParseDeclarationOrFunctionDefinition(DS, AS); + if (DS) { + return ParseDeclOrFunctionDefInternal(attrs, *DS, AS); + } else { + ParsingDeclSpec PDS(*this); + // Must temporarily exit the objective-c container scope for + // parsing c constructs and re-enter objc container scope + // afterwards. + ObjCDeclContextSwitch ObjCDC(*this); + + return ParseDeclOrFunctionDefInternal(attrs, PDS, AS); + } } /// ParseFunctionDefinition - We parsed and verified that the specified @@ -914,6 +970,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // In delayed template parsing mode, for function template we consume the // tokens and store them for late parsing at the end of the translation unit. if (getLangOpts().DelayedTemplateParsing && + Tok.isNot(tok::equal) && TemplateInfo.Kind == ParsedTemplateInfo::Template) { MultiTemplateParamsArg TemplateParameterLists(Actions, TemplateInfo.TemplateParams->data(), @@ -947,7 +1004,28 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, } return DP; } - + else if (CurParsedObjCImpl && + !TemplateInfo.TemplateParams && + (Tok.is(tok::l_brace) || Tok.is(tok::kw_try) || + Tok.is(tok::colon)) && + Actions.CurContext->isTranslationUnit()) { + MultiTemplateParamsArg TemplateParameterLists(Actions, 0, 0); + ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); + Scope *ParentScope = getCurScope()->getParent(); + + D.setFunctionDefinitionKind(FDK_Definition); + Decl *FuncDecl = Actions.HandleDeclarator(ParentScope, D, + move(TemplateParameterLists)); + D.complete(FuncDecl); + D.getMutableDeclSpec().abort(); + if (FuncDecl) { + // Consume the tokens and store them for later parsing. + StashAwayMethodOrFunctionBodyTokens(FuncDecl); + CurParsedObjCImpl->HasCFunction = true; + return FuncDecl; + } + } + // Enter a scope for the function body. ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); @@ -1130,10 +1208,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { ParseDeclarator(ParmDeclarator); } - if (Tok.is(tok::semi)) { - ConsumeToken(); - } else { - Diag(Tok, diag::err_expected_semi_declaration); + if (ExpectAndConsumeSemi(diag::err_expected_semi_declaration)) { // Skip to end of block or statement SkipUntil(tok::semi, true); if (Tok.is(tok::semi)) @@ -1251,7 +1326,8 @@ TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) { bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) - || Tok.is(tok::kw_decltype)) && "Cannot be a type or scope token!"); + || Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id)) + && "Cannot be a type or scope token!"); if (Tok.is(tok::kw_typename)) { // Parse a C++ typename-specifier, e.g., "typename T::type". @@ -1267,10 +1343,23 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { 0, /*IsTypename*/true)) return true; if (!SS.isSet()) { - if (getLangOpts().MicrosoftExt) - Diag(Tok.getLocation(), diag::warn_expected_qualified_after_typename); - else - Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); + if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id) || + Tok.is(tok::annot_decltype)) { + // Attempt to recover by skipping the invalid 'typename' + if (Tok.is(tok::annot_decltype) || + (!TryAnnotateTypeOrScopeToken(EnteringContext, NeedType) && + Tok.isAnnotation())) { + unsigned DiagID = diag::err_expected_qualified_after_typename; + // MS compatibility: MSVC permits using known types with typename. + // e.g. "typedef typename T* pointer_type" + if (getLangOpts().MicrosoftExt) + DiagID = diag::warn_expected_qualified_after_typename; + Diag(Tok.getLocation(), DiagID); + return false; + } + } + + Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); return true; } @@ -1423,8 +1512,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { /// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only /// annotates C++ scope specifiers and template-ids. This returns -/// true if the token was annotated or there was an error that could not be -/// recovered from. +/// true if there was an error that could not be recovered from. /// /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. @@ -1678,13 +1766,13 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) { return Actions.ConvertDeclToDeclGroup(Import.get()); } -bool Parser::BalancedDelimiterTracker::diagnoseOverflow() { +bool BalancedDelimiterTracker::diagnoseOverflow() { P.Diag(P.Tok, diag::err_parser_impl_limit_overflow); P.SkipUntil(tok::eof); return true; } -bool Parser::BalancedDelimiterTracker::expectAndConsume(unsigned DiagID, +bool BalancedDelimiterTracker::expectAndConsume(unsigned DiagID, const char *Msg, tok::TokenKind SkipToToc ) { LOpen = P.Tok.getLocation(); @@ -1697,7 +1785,7 @@ bool Parser::BalancedDelimiterTracker::expectAndConsume(unsigned DiagID, return diagnoseOverflow(); } -bool Parser::BalancedDelimiterTracker::diagnoseMissingClose() { +bool BalancedDelimiterTracker::diagnoseMissingClose() { assert(!P.Tok.is(Close) && "Should have consumed closing delimiter"); const char *LHSName = "unknown"; @@ -1715,6 +1803,6 @@ bool Parser::BalancedDelimiterTracker::diagnoseMissingClose() { return true; } -void Parser::BalancedDelimiterTracker::skipToEnd() { +void BalancedDelimiterTracker::skipToEnd() { P.SkipUntil(Close, false); } diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h index ef17aee3f512..455c4af2ffae 100644 --- a/lib/Parse/RAIIObjectsForParser.h +++ b/lib/Parse/RAIIObjectsForParser.h @@ -16,13 +16,230 @@ #define LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/Sema.h" namespace clang { - // TODO: move ParsingDeclRAIIObject here. // TODO: move ParsingClassDefinition here. // TODO: move TentativeParsingAction here. - - + + /// \brief A RAII object used to temporarily suppress access-like + /// checking. Access-like checks are those associated with + /// controlling the use of a declaration, like C++ access control + /// errors and deprecation warnings. They are contextually + /// dependent, in that they can only be resolved with full + /// information about what's being declared. They are also + /// suppressed in certain contexts, like the template arguments of + /// an explicit instantiation. However, those suppression contexts + /// cannot necessarily be fully determined in advance; for + /// example, something starting like this: + /// template <> class std::vector<A::PrivateType> + /// might be the entirety of an explicit instantiation: + /// template <> class std::vector<A::PrivateType>; + /// or just an elaborated type specifier: + /// template <> class std::vector<A::PrivateType> make_vector<>(); + /// Therefore this class collects all the diagnostics and permits + /// them to be re-delayed in a new context. + class SuppressAccessChecks { + Sema &S; + sema::DelayedDiagnosticPool DiagnosticPool; + Sema::ParsingDeclState State; + bool Active; + + public: + /// Begin suppressing access-like checks + SuppressAccessChecks(Parser &P, bool activate = true) + : S(P.getActions()), DiagnosticPool(NULL) { + if (activate) { + State = S.PushParsingDeclaration(DiagnosticPool); + Active = true; + } else { + Active = false; + } + } + + void done() { + assert(Active && "trying to end an inactive suppression"); + S.PopParsingDeclaration(State, NULL); + Active = false; + } + + void redelay() { + assert(!Active && "redelaying without having ended first"); + if (!DiagnosticPool.pool_empty()) + S.redelayDiagnostics(DiagnosticPool); + assert(DiagnosticPool.pool_empty()); + } + + ~SuppressAccessChecks() { + if (Active) done(); + } + }; + + /// \brief RAII object used to inform the actions that we're + /// currently parsing a declaration. This is active when parsing a + /// variable's initializer, but not when parsing the body of a + /// class or function definition. + class ParsingDeclRAIIObject { + Sema &Actions; + sema::DelayedDiagnosticPool DiagnosticPool; + Sema::ParsingDeclState State; + bool Popped; + + // Do not implement. + ParsingDeclRAIIObject(const ParsingDeclRAIIObject &other); + ParsingDeclRAIIObject &operator=(const ParsingDeclRAIIObject &other); + + public: + enum NoParent_t { NoParent }; + ParsingDeclRAIIObject(Parser &P, NoParent_t _) + : Actions(P.getActions()), DiagnosticPool(NULL) { + push(); + } + + /// Creates a RAII object whose pool is optionally parented by another. + ParsingDeclRAIIObject(Parser &P, + const sema::DelayedDiagnosticPool *parentPool) + : Actions(P.getActions()), DiagnosticPool(parentPool) { + push(); + } + + /// Creates a RAII object and, optionally, initialize its + /// diagnostics pool by stealing the diagnostics from another + /// RAII object (which is assumed to be the current top pool). + ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *other) + : Actions(P.getActions()), + DiagnosticPool(other ? other->DiagnosticPool.getParent() : NULL) { + if (other) { + DiagnosticPool.steal(other->DiagnosticPool); + other->abort(); + } + push(); + } + + ~ParsingDeclRAIIObject() { + abort(); + } + + sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() { + return DiagnosticPool; + } + const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { + return DiagnosticPool; + } + + /// Resets the RAII object for a new declaration. + void reset() { + abort(); + push(); + } + + /// Signals that the context was completed without an appropriate + /// declaration being parsed. + void abort() { + pop(0); + } + + void complete(Decl *D) { + assert(!Popped && "ParsingDeclaration has already been popped!"); + pop(D); + } + + /// Unregister this object from Sema, but remember all the + /// diagnostics that were emitted into it. + void abortAndRemember() { + pop(0); + } + + private: + void push() { + State = Actions.PushParsingDeclaration(DiagnosticPool); + Popped = false; + } + + void pop(Decl *D) { + if (!Popped) { + Actions.PopParsingDeclaration(State, D); + Popped = true; + } + } + }; + + /// A class for parsing a DeclSpec. + class ParsingDeclSpec : public DeclSpec { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingDeclSpec(Parser &P) + : DeclSpec(P.getAttrFactory()), + ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {} + ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) + : DeclSpec(P.getAttrFactory()), + ParsingRAII(P, RAII) {} + + const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { + return ParsingRAII.getDelayedDiagnosticPool(); + } + + void complete(Decl *D) { + ParsingRAII.complete(D); + } + + void abort() { + ParsingRAII.abort(); + } + }; + + /// A class for parsing a declarator. + class ParsingDeclarator : public Declarator { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C) + : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { + } + + const ParsingDeclSpec &getDeclSpec() const { + return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec()); + } + + ParsingDeclSpec &getMutableDeclSpec() const { + return const_cast<ParsingDeclSpec&>(getDeclSpec()); + } + + void clear() { + Declarator::clear(); + ParsingRAII.reset(); + } + + void complete(Decl *D) { + ParsingRAII.complete(D); + } + }; + + /// A class for parsing a field declarator. + class ParsingFieldDeclarator : public FieldDeclarator { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS) + : FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { + } + + const ParsingDeclSpec &getDeclSpec() const { + return static_cast<const ParsingDeclSpec&>(D.getDeclSpec()); + } + + ParsingDeclSpec &getMutableDeclSpec() const { + return const_cast<ParsingDeclSpec&>(getDeclSpec()); + } + + void complete(Decl *D) { + ParsingRAII.complete(D); + } + }; + /// ExtensionRAIIObject - This saves the state of extension warnings when /// constructed and disables them. When destructed, it restores them back to /// the way they used to be. This is used to handle __extension__ in the @@ -137,6 +354,81 @@ namespace clang { } }; + /// \brief RAII class that helps handle the parsing of an open/close delimiter + /// pair, such as braces { ... } or parentheses ( ... ). + class BalancedDelimiterTracker : public GreaterThanIsOperatorScope { + Parser& P; + tok::TokenKind Kind, Close; + SourceLocation (Parser::*Consumer)(); + SourceLocation LOpen, LClose; + + unsigned short &getDepth() { + switch (Kind) { + case tok::l_brace: return P.BraceCount; + case tok::l_square: return P.BracketCount; + case tok::l_paren: return P.ParenCount; + default: llvm_unreachable("Wrong token kind"); + } + } + + enum { MaxDepth = 256 }; + + bool diagnoseOverflow(); + bool diagnoseMissingClose(); + + public: + BalancedDelimiterTracker(Parser& p, tok::TokenKind k) + : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true), + P(p), Kind(k) + { + switch (Kind) { + default: llvm_unreachable("Unexpected balanced token"); + case tok::l_brace: + Close = tok::r_brace; + Consumer = &Parser::ConsumeBrace; + break; + case tok::l_paren: + Close = tok::r_paren; + Consumer = &Parser::ConsumeParen; + break; + + case tok::l_square: + Close = tok::r_square; + Consumer = &Parser::ConsumeBracket; + break; + } + } + + SourceLocation getOpenLocation() const { return LOpen; } + SourceLocation getCloseLocation() const { return LClose; } + SourceRange getRange() const { return SourceRange(LOpen, LClose); } + + bool consumeOpen() { + if (!P.Tok.is(Kind)) + return true; + + if (getDepth() < MaxDepth) { + LOpen = (P.*Consumer)(); + return false; + } + + return diagnoseOverflow(); + } + + bool expectAndConsume(unsigned DiagID, + const char *Msg = "", + tok::TokenKind SkipToTok = tok::unknown); + bool consumeClose() { + if (P.Tok.is(Close)) { + LClose = (P.*Consumer)(); + return false; + } + + return diagnoseMissingClose(); + } + void skipToEnd(); + }; + } // end namespace clang #endif |