diff options
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/CMakeLists.txt | 2 | ||||
-rw-r--r-- | lib/Parse/ParseAST.cpp | 24 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 313 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 681 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 524 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 527 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 160 | ||||
-rw-r--r-- | lib/Parse/ParseInit.cpp | 15 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 281 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.cpp | 113 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.h | 40 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 326 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 97 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 236 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 208 | ||||
-rw-r--r-- | lib/Parse/RAIIObjectsForParser.h | 16 |
16 files changed, 2481 insertions, 1082 deletions
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt index 189af3d..6bf5e64 100644 --- a/lib/Parse/CMakeLists.txt +++ b/lib/Parse/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_NO_RTTI 1) +set(LLVM_USED_LIBS clangBasic clangAST clangLex clangSema) add_clang_library(clangParse ParseAST.cpp diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp index d027879..edb1675 100644 --- a/lib/Parse/ParseAST.cpp +++ b/lib/Parse/ParseAST.cpp @@ -25,26 +25,6 @@ using namespace clang; -static void DumpRecordLayouts(ASTContext &C) { - for (ASTContext::type_iterator I = C.types_begin(), E = C.types_end(); - I != E; ++I) { - const RecordType *RT = dyn_cast<RecordType>(*I); - if (!RT) - continue; - - const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); - if (!RD || RD->isImplicit() || RD->isDependentType() || - RD->isInvalidDecl() || !RD->getDefinition()) - continue; - - // FIXME: Do we really need to hard code this? - if (RD->getQualifiedNameAsString() == "__va_list_tag") - continue; - - C.DumpRecordLayout(RD, llvm::errs()); - } -} - //===----------------------------------------------------------------------===// // Public interface to the file //===----------------------------------------------------------------------===// @@ -97,10 +77,6 @@ void clang::ParseAST(Sema &S, bool PrintStats) { E = S.WeakTopLevelDecls().end(); I != E; ++I) Consumer->HandleTopLevelDecl(DeclGroupRef(*I)); - // Dump record layouts, if requested. - if (S.getLangOptions().DumpRecordLayouts) - DumpRecordLayouts(S.getASTContext()); - Consumer->HandleTranslationUnit(S.getASTContext()); if (PrintStats) { diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index d327db4..3994738 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -20,10 +20,10 @@ using namespace clang; /// ParseCXXInlineMethodDef - We parsed and verified that the specified /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. -Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, - const ParsedTemplateInfo &TemplateInfo) { - assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && - "This isn't a function declarator!"); +Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, + const ParsedTemplateInfo &TemplateInfo, + const VirtSpecifiers& VS) { + assert(D.isFunctionDeclarator() && "This isn't a function declarator!"); assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && "Current token not a '{', ':' or 'try'!"); @@ -36,19 +36,29 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, // FIXME: Friend templates FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, true, move(TemplateParams)); - else // FIXME: pass template information through + else { // FIXME: pass template information through + if (VS.isOverrideSpecified()) + Diag(VS.getOverrideLoc(), diag::ext_override_inline) << "override"; + if (VS.isFinalSpecified()) + Diag(VS.getFinalLoc(), diag::ext_override_inline) << "final"; + if (VS.isNewSpecified()) + Diag(VS.getNewLoc(), diag::ext_override_inline) << "new"; + FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D, - move(TemplateParams), 0, 0, - /*IsDefinition*/true); + move(TemplateParams), 0, + VS, 0, /*IsDefinition*/true); + } HandleMemberFunctionDefaultArgs(D, FnD); + D.complete(FnD); + // Consume the tokens and store them for later parsing. - getCurrentClass().MethodDefs.push_back(LexedMethod(FnD)); - getCurrentClass().MethodDefs.back().TemplateScope - = getCurScope()->isTemplateParamScope(); - CachedTokens &Toks = getCurrentClass().MethodDefs.back().Toks; + LexedMethod* LM = new LexedMethod(this, FnD); + getCurrentClass().LateParsedDeclarations.push_back(LM); + LM->TemplateScope = getCurScope()->isTemplateParamScope(); + CachedTokens &Toks = LM->Toks; tok::TokenKind kind = Tok.getKind(); // We may have a constructor initializer or function-try-block here. @@ -62,7 +72,8 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, // don't try to parse this method later. Diag(Tok.getLocation(), diag::err_expected_lbrace); ConsumeAnyToken(); - getCurrentClass().MethodDefs.pop_back(); + delete getCurrentClass().LateParsedDeclarations.back(); + getCurrentClass().LateParsedDeclarations.pop_back(); return FnD; } } @@ -86,13 +97,40 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, return FnD; } +Parser::LateParsedDeclaration::~LateParsedDeclaration() {} +void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {} +void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {} + +Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C) + : Self(P), Class(C) {} + +Parser::LateParsedClass::~LateParsedClass() { + Self->DeallocateParsedClasses(Class); +} + +void Parser::LateParsedClass::ParseLexedMethodDeclarations() { + Self->ParseLexedMethodDeclarations(*Class); +} + +void Parser::LateParsedClass::ParseLexedMethodDefs() { + Self->ParseLexedMethodDefs(*Class); +} + +void Parser::LateParsedMethodDeclaration::ParseLexedMethodDeclarations() { + Self->ParseLexedMethodDeclaration(*this); +} + +void Parser::LexedMethod::ParseLexedMethodDefs() { + Self->ParseLexedMethodDef(*this); +} + /// ParseLexedMethodDeclarations - We finished parsing the member /// specification of a top (non-nested) C++ class. Now go over the /// stack of method declarations with some parts for which parsing was /// delayed (such as default arguments) and parse them. void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; - ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); + ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); if (HasTemplateScope) Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); @@ -104,75 +142,79 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { if (HasClassScope) Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); - for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) { - LateParsedMethodDeclaration &LM = Class.MethodDecls.front(); - - // If this is a member template, introduce the template parameter scope. - ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); - if (LM.TemplateScope) - Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method); - - // Start the delayed C++ method declaration - Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method); - - // Introduce the parameters into scope and parse their default - // arguments. - ParseScope PrototypeScope(this, - Scope::FunctionPrototypeScope|Scope::DeclScope); - for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { - // Introduce the parameter into scope. - Actions.ActOnDelayedCXXMethodParameter(getCurScope(), LM.DefaultArgs[I].Param); + for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { + Class.LateParsedDeclarations[i]->ParseLexedMethodDeclarations(); + } - if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { - // Save the current token position. - SourceLocation origLoc = Tok.getLocation(); + if (HasClassScope) + Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); +} - // Parse the default argument from its saved token stream. - Toks->push_back(Tok); // So that the current token doesn't get lost - PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false); +void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { + // If this is a member template, introduce the template parameter scope. + ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); + if (LM.TemplateScope) + Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method); + + // Start the delayed C++ method declaration + Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method); + + // Introduce the parameters into scope and parse their default + // arguments. + ParseScope PrototypeScope(this, + Scope::FunctionPrototypeScope|Scope::DeclScope); + for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { + // Introduce the parameter into scope. + Actions.ActOnDelayedCXXMethodParameter(getCurScope(), LM.DefaultArgs[I].Param); + + if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { + // Save the current token position. + SourceLocation origLoc = Tok.getLocation(); + + // Parse the default argument from its saved token stream. + Toks->push_back(Tok); // So that the current token doesn't get lost + PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false); + + // Consume the previously-pushed token. + ConsumeAnyToken(); + + // Consume the '='. + assert(Tok.is(tok::equal) && "Default argument not starting with '='"); + SourceLocation EqualLoc = ConsumeToken(); + + // The argument isn't actually potentially evaluated unless it is + // used. + EnterExpressionEvaluationContext Eval(Actions, + Sema::PotentiallyEvaluatedIfUsed); + + ExprResult DefArgResult(ParseAssignmentExpression()); + if (DefArgResult.isInvalid()) + Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param); + else { + if (Tok.is(tok::cxx_defaultarg_end)) + ConsumeToken(); + else + Diag(Tok.getLocation(), diag::err_default_arg_unparsed); + Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc, + DefArgResult.take()); + } - // Consume the previously-pushed token. + assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, + Tok.getLocation()) && + "ParseAssignmentExpression went over the default arg tokens!"); + // There could be leftover tokens (e.g. because of an error). + // Skip through until we reach the original token position. + while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); - // Consume the '='. - assert(Tok.is(tok::equal) && "Default argument not starting with '='"); - SourceLocation EqualLoc = ConsumeToken(); - - ExprResult DefArgResult(ParseAssignmentExpression()); - if (DefArgResult.isInvalid()) - Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param); - else { - if (Tok.is(tok::cxx_defaultarg_end)) - ConsumeToken(); - else - Diag(Tok.getLocation(), diag::err_default_arg_unparsed); - Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc, - DefArgResult.take()); - } - - assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, - Tok.getLocation()) && - "ParseAssignmentExpression went over the default arg tokens!"); - // There could be leftover tokens (e.g. because of an error). - // Skip through until we reach the original token position. - while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) - ConsumeAnyToken(); - - delete Toks; - LM.DefaultArgs[I].Toks = 0; - } + delete Toks; + LM.DefaultArgs[I].Toks = 0; } - PrototypeScope.Exit(); - - // Finish the delayed C++ method declaration. - Actions.ActOnFinishDelayedCXXMethodDeclaration(getCurScope(), LM.Method); } + PrototypeScope.Exit(); - for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I) - ParseLexedMethodDeclarations(*Class.NestedClasses[I]); - - if (HasClassScope) - Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); + // Finish the delayed C++ method declaration. + Actions.ActOnFinishDelayedCXXMethodDeclaration(getCurScope(), LM.Method); } /// ParseLexedMethodDefs - We finished parsing the member specification of a top @@ -180,7 +222,7 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { /// collected during its parsing and parse them all. void Parser::ParseLexedMethodDefs(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; - ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); + ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); if (HasTemplateScope) Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); @@ -188,73 +230,72 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope); - for (; !Class.MethodDefs.empty(); Class.MethodDefs.pop_front()) { - LexedMethod &LM = Class.MethodDefs.front(); - - // If this is a member template, introduce the template parameter scope. - ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); - if (LM.TemplateScope) - Actions.ActOnReenterTemplateScope(getCurScope(), LM.D); - - // Save the current token position. - SourceLocation origLoc = Tok.getLocation(); - - assert(!LM.Toks.empty() && "Empty body!"); - // Append the current token at the end of the new token stream so that it - // doesn't get lost. - LM.Toks.push_back(Tok); - PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); - - // Consume the previously pushed token. - ConsumeAnyToken(); - assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) - && "Inline method not starting with '{', ':' or 'try'"); + for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { + Class.LateParsedDeclarations[i]->ParseLexedMethodDefs(); + } +} - // Parse the method body. Function body parsing code is similar enough - // to be re-used for method bodies as well. - ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); - Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D); +void Parser::ParseLexedMethodDef(LexedMethod &LM) { + // If this is a member template, introduce the template parameter scope. + ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); + if (LM.TemplateScope) + Actions.ActOnReenterTemplateScope(getCurScope(), LM.D); + + // Save the current token position. + SourceLocation origLoc = Tok.getLocation(); + + assert(!LM.Toks.empty() && "Empty body!"); + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + LM.Toks.push_back(Tok); + PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); + + // Consume the previously pushed token. + ConsumeAnyToken(); + assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) + && "Inline method not starting with '{', ':' or 'try'"); + + // Parse the method body. Function body parsing code is similar enough + // to be re-used for method bodies as well. + ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); + Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D); + + if (Tok.is(tok::kw_try)) { + ParseFunctionTryBlock(LM.D); + assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, + Tok.getLocation()) && + "ParseFunctionTryBlock went over the cached tokens!"); + // There could be leftover tokens (e.g. because of an error). + // Skip through until we reach the original token position. + while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) + ConsumeAnyToken(); + return; + } + if (Tok.is(tok::colon)) { + ParseConstructorInitializer(LM.D); - if (Tok.is(tok::kw_try)) { - ParseFunctionTryBlock(LM.D); - assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, - Tok.getLocation()) && - "ParseFunctionTryBlock went over the cached tokens!"); - // There could be leftover tokens (e.g. because of an error). - // Skip through until we reach the original token position. + // Error recovery. + if (!Tok.is(tok::l_brace)) { + Actions.ActOnFinishFunctionBody(LM.D, 0); + return; + } + } else + Actions.ActOnDefaultCtorInitializers(LM.D); + + ParseFunctionStatementBody(LM.D); + + if (Tok.getLocation() != origLoc) { + // Due to parsing error, we either went over the cached tokens or + // there are still cached tokens left. If it's the latter case skip the + // leftover tokens. + // Since this is an uncommon situation that should be avoided, use the + // expensive isBeforeInTranslationUnit call. + if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(), + origLoc)) while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); - continue; - } - if (Tok.is(tok::colon)) { - ParseConstructorInitializer(LM.D); - - // Error recovery. - if (!Tok.is(tok::l_brace)) { - Actions.ActOnFinishFunctionBody(LM.D, 0); - continue; - } - } else - Actions.ActOnDefaultCtorInitializers(LM.D); - - ParseFunctionStatementBody(LM.D); - - if (Tok.getLocation() != origLoc) { - // Due to parsing error, we either went over the cached tokens or - // there are still cached tokens left. If it's the latter case skip the - // leftover tokens. - // Since this is an uncommon situation that should be avoided, use the - // expensive isBeforeInTranslationUnit call. - if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(), - origLoc)) - while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) - ConsumeAnyToken(); - } } - - for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I) - ParseLexedMethodDefs(*Class.NestedClasses[I]); } /// ConsumeAndStoreUntil - Consume and store the token at the passed token diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 555fcf0..5a7fc7e 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -29,13 +29,14 @@ using namespace clang; /// specifier-qualifier-list abstract-declarator[opt] /// /// Called type-id in C++. -TypeResult Parser::ParseTypeName(SourceRange *Range) { +TypeResult Parser::ParseTypeName(SourceRange *Range, + Declarator::TheContext Context) { // Parse the common declaration-specifiers piece. DeclSpec DS; ParseSpecifierQualifierList(DS); // Parse the abstract-declarator, if present. - Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + Declarator DeclaratorInfo(DS, Context); ParseDeclarator(DeclaratorInfo); if (Range) *Range = DeclaratorInfo.getSourceRange(); @@ -82,21 +83,20 @@ TypeResult Parser::ParseTypeName(SourceRange *Range) { /// attributes are very simple in practice. Until we find a bug, I don't see /// a pressing need to implement the 2 token lookahead. -AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { +void Parser::ParseGNUAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc) { assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); - AttributeList *CurrAttr = 0; - while (Tok.is(tok::kw___attribute)) { ConsumeToken(); if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "attribute")) { SkipUntil(tok::r_paren, true); // skip until ) or ; - return CurrAttr; + return; } if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) { SkipUntil(tok::r_paren, true); // skip until ) or ; - return CurrAttr; + return; } // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") )) while (Tok.is(tok::identifier) || isDeclarationSpecifier() || @@ -122,8 +122,8 @@ AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { if (Tok.is(tok::r_paren)) { // __attribute__(( mode(byte) )) ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, - ParmName, ParmLoc, 0, 0, CurrAttr); + attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, + ParmName, ParmLoc, 0, 0)); } else if (Tok.is(tok::comma)) { ConsumeToken(); // __attribute__(( format(printf, 1, 2) )) @@ -146,10 +146,9 @@ AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { } if (ArgExprsOk && Tok.is(tok::r_paren)) { ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, + attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, ParmName, ParmLoc, - ArgExprs.take(), ArgExprs.size(), - CurrAttr); + ArgExprs.take(), ArgExprs.size())); } } } else { // not an identifier @@ -158,8 +157,8 @@ AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { // parse a possibly empty comma separated list of expressions // __attribute__(( nonnull() )) ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0, CurrAttr); + attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0)); break; case tok::kw_char: case tok::kw_wchar_t: @@ -174,10 +173,12 @@ AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { case tok::kw_float: case tok::kw_double: case tok::kw_void: - case tok::kw_typeof: - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0, CurrAttr); - if (CurrAttr->getKind() == AttributeList::AT_IBOutletCollection) + case tok::kw_typeof: { + AttributeList *attr + = AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0); + attrs.add(attr); + if (attr->getKind() == AttributeList::AT_IBOutletCollection) Diag(Tok, diag::err_iboutletcollection_builtintype); // If it's a builtin type name, eat it and expect a rparen // __attribute__(( vec_type_hint(char) )) @@ -185,6 +186,7 @@ AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { if (Tok.is(tok::r_paren)) ConsumeParen(); break; + } default: // __attribute__(( aligned(16) )) ExprVector ArgExprs(Actions); @@ -207,17 +209,16 @@ AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { // Match the ')'. if (ArgExprsOk && Tok.is(tok::r_paren)) { ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, - AttrNameLoc, 0, SourceLocation(), ArgExprs.take(), - ArgExprs.size(), - CurrAttr); + attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, + AttrNameLoc, 0, SourceLocation(), + ArgExprs.take(), ArgExprs.size())); } break; } } } else { - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0, CurrAttr); + attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0)); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) @@ -226,10 +227,9 @@ AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { SkipUntil(tok::r_paren, false); } - if (EndLoc) - *EndLoc = Loc; + if (endLoc) + *endLoc = Loc; } - return CurrAttr; } /// ParseMicrosoftDeclSpec - Parse an __declspec construct @@ -241,14 +241,14 @@ AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { /// extended-decl-modifier[opt] /// extended-decl-modifier extended-decl-modifier-seq -AttributeList* Parser::ParseMicrosoftDeclSpec(AttributeList *CurrAttr) { +void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) { assert(Tok.is(tok::kw___declspec) && "Not a declspec!"); ConsumeToken(); if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "declspec")) { SkipUntil(tok::r_paren, true); // skip until ) or ; - return CurrAttr; + return; } while (Tok.getIdentifierInfo()) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); @@ -260,23 +260,22 @@ AttributeList* Parser::ParseMicrosoftDeclSpec(AttributeList *CurrAttr) { ExprResult ArgExpr(ParseAssignmentExpression()); if (!ArgExpr.isInvalid()) { Expr *ExprList = ArgExpr.take(); - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), &ExprList, 1, - CurrAttr, true); + attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), &ExprList, 1, true)); } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) SkipUntil(tok::r_paren, false); } else { - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0, CurrAttr, true); + attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0, true)); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) SkipUntil(tok::r_paren, false); - return CurrAttr; + return; } -AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) { +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) || @@ -287,21 +286,34 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) { if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64)) // FIXME: Support these properly! continue; - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, CurrAttr, true); + attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, true)); } - return CurrAttr; } -AttributeList* Parser::ParseBorlandTypeAttributes(AttributeList *CurrAttr) { +void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { // Treat these like attributes while (Tok.is(tok::kw___pascal)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, CurrAttr, true); + attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, true)); + } +} + +void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) { + // Treat these like attributes + while (Tok.is(tok::kw___kernel)) { + SourceLocation AttrNameLoc = ConsumeToken(); + attrs.add(AttrFactory.Create(PP.getIdentifierInfo("opencl_kernel_function"), + AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, false)); } - return CurrAttr; +} + +void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { + Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) + << attrs.Range; } /// ParseDeclaration - Parse a full 'declaration', which consists of @@ -320,48 +332,43 @@ AttributeList* Parser::ParseBorlandTypeAttributes(AttributeList *CurrAttr) { /// [C++0x] static_assert-declaration /// others... [FIXME] /// -Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, +Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, + unsigned Context, SourceLocation &DeclEnd, - CXX0XAttributeList Attr) { + ParsedAttributesWithRange &attrs) { ParenBraceBracketBalancer BalancerRAIIObj(*this); Decl *SingleDecl = 0; switch (Tok.getKind()) { case tok::kw_template: case tok::kw_export: - if (Attr.HasAttr) - Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) - << Attr.Range; + ProhibitAttributes(attrs); SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd); break; case tok::kw_inline: // Could be the start of an inline namespace. Allowed as an ext in C++03. if (getLang().CPlusPlus && NextToken().is(tok::kw_namespace)) { - if (Attr.HasAttr) - Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) - << Attr.Range; + ProhibitAttributes(attrs); SourceLocation InlineLoc = ConsumeToken(); SingleDecl = ParseNamespace(Context, DeclEnd, InlineLoc); break; } - return ParseSimpleDeclaration(Context, DeclEnd, Attr.AttrList, true); + return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs, + true); case tok::kw_namespace: - if (Attr.HasAttr) - Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) - << Attr.Range; + ProhibitAttributes(attrs); SingleDecl = ParseNamespace(Context, DeclEnd); break; case tok::kw_using: - SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd, Attr); + SingleDecl = ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(), + DeclEnd, attrs); break; case tok::kw_static_assert: - if (Attr.HasAttr) - Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) - << Attr.Range; + ProhibitAttributes(attrs); SingleDecl = ParseStaticAssertDeclaration(DeclEnd); break; default: - return ParseSimpleDeclaration(Context, DeclEnd, Attr.AttrList, true); + return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs, true); } // This routine returns a DeclGroup, if the thing we parsed only contains a @@ -376,16 +383,19 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, /// /// If RequireSemi is false, this does not check for a ';' at the end of the /// declaration. If it is true, it checks for and eats it. -Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, +Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts, + unsigned Context, SourceLocation &DeclEnd, - AttributeList *Attr, + ParsedAttributes &attrs, bool RequireSemi) { // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); - if (Attr) - DS.AddAttributes(Attr); + DS.takeAttributesFrom(attrs); ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, - getDeclSpecContextFromDeclaratorContext(Context)); + getDeclSpecContextFromDeclaratorContext(Context)); + StmtResult R = Actions.ActOnVlaStmt(DS); + if (R.isUsable()) + Stmts.push_back(R.release()); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' @@ -474,11 +484,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // short __attribute__((common)) var; -> declspec // short var __attribute__((common)); -> declarator // short x, __attribute__((common)) var; -> declarator - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseGNUAttributes(&Loc); - D.AddAttributes(AttrList, Loc); - } + MaybeParseGNUAttributes(D); ParseDeclarator(D); @@ -547,12 +553,7 @@ Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, D.SetRangeEnd(Loc); } - // If attributes are present, parse them. - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseGNUAttributes(&Loc); - D.AddAttributes(AttrList, Loc); - } + MaybeParseGNUAttributes(D); // Inform the current actions module that we just parsed this declarator. Decl *ThisDecl = 0; @@ -586,11 +587,19 @@ Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, } } + bool TypeContainsAuto = + D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + // Parse declarator '=' initializer. - if (Tok.is(tok::equal)) { + if (isTokenEqualOrMistypedEqualEqual( + diag::err_invalid_equalequal_after_declarator)) { ConsumeToken(); - if (getLang().CPlusPlus0x && Tok.is(tok::kw_delete)) { + if (Tok.is(tok::kw_delete)) { SourceLocation DelLoc = ConsumeToken(); + + if (!getLang().CPlusPlus0x) + Diag(DelLoc, diag::warn_deleted_function_accepted_as_extension); + Actions.SetDeclDeleted(ThisDecl, DelLoc); } else { if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { @@ -616,7 +625,8 @@ Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, SkipUntil(tok::comma, true, true); Actions.ActOnInitializerError(ThisDecl); } else - Actions.AddInitializerToDecl(ThisDecl, Init.take()); + Actions.AddInitializerToDecl(ThisDecl, Init.take(), + /*DirectInit=*/false, TypeContainsAuto); } } else if (Tok.is(tok::l_paren)) { // Parse C++ direct initializer: '(' expression-list ')' @@ -650,12 +660,11 @@ Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, Actions.AddCXXDirectInitializerToDecl(ThisDecl, LParenLoc, move_arg(Exprs), - CommaLocs.data(), RParenLoc); + RParenLoc, + TypeContainsAuto); } } else { - bool TypeContainsUndeducedAuto = - D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; - Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsUndeducedAuto); + Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto); } return ThisDecl; @@ -675,7 +684,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS) { // Validate declspec for type-name. unsigned Specs = DS.getParsedSpecifiers(); if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() && - !DS.getAttributes()) + !DS.hasAttributes()) Diag(Tok, diag::err_typename_requires_specqual); // Issue diagnostic and remove storage class if present. @@ -868,6 +877,7 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { /// [C99] 'inline' /// [C++] 'virtual' /// [C++] 'explicit' +/// [OpenCL] '__kernel' /// 'friend': [C++ dcl.friend] /// 'constexpr': [C++0x dcl.constexpr] @@ -877,6 +887,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, AccessSpecifier AS, DeclSpecContext DSContext) { DS.SetRangeStart(Tok.getLocation()); + DS.SetRangeEnd(Tok.getLocation()); while (1) { bool isInvalid = false; const char *PrevSpec = 0; @@ -905,13 +916,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, = DSContext == DSC_top_level || (DSContext == DSC_class && DS.isFriendSpecified()); - Actions.CodeCompleteDeclarator(getCurScope(), AllowNonIdentifiers, - AllowNestedNameSpecifiers); + Actions.CodeCompleteDeclSpec(getCurScope(), DS, + AllowNonIdentifiers, + AllowNestedNameSpecifiers); ConsumeCodeCompletionToken(); return; } - if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) + if (getCurScope()->getFnParent() || getCurScope()->getBlockParent()) + CCC = Sema::PCC_LocalDeclarationSpecifiers; + else if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) CCC = DSContext == DSC_class? Sema::PCC_MemberTemplate : Sema::PCC_Template; else if (DSContext == DSC_class) @@ -1005,7 +1019,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ConsumeToken(); // The C++ scope. if (Tok.getAnnotationValue()) { ParsedType T = getTypeAnnotation(Tok); - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, + Tok.getAnnotationEndLoc(), PrevSpec, DiagID, T); } else @@ -1080,20 +1095,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. If we don't have Objective-C or a '<', this is - // just a normal reference to a typedef name. - if (!Tok.is(tok::less) || !getLang().ObjC1) - continue; - - SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector<Decl *, 8> ProtocolDecl; - llvm::SmallVector<SourceLocation, 8> ProtocolLocs; - ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, - LAngleLoc, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), - ProtocolLocs.data(), LAngleLoc); - - DS.SetRangeEnd(EndProtoLoc); + // Objective-C interface. + if (Tok.is(tok::less) && getLang().ObjC1) + ParseObjCProtocolQualifiers(DS); + continue; } @@ -1150,21 +1155,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. If we don't have Objective-C or a '<', this is - // just a normal reference to a typedef name. - if (!Tok.is(tok::less) || !getLang().ObjC1) - continue; - - SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector<Decl *, 8> ProtocolDecl; - llvm::SmallVector<SourceLocation, 8> ProtocolLocs; - ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, - LAngleLoc, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), - ProtocolLocs.data(), LAngleLoc); - - DS.SetRangeEnd(EndProtoLoc); - + // Objective-C interface. + if (Tok.is(tok::less) && getLang().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; @@ -1196,12 +1190,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // GNU attributes support. case tok::kw___attribute: - DS.AddAttributes(ParseGNUAttributes()); + ParseGNUAttributes(DS.getAttributes()); continue; // Microsoft declspec support. case tok::kw___declspec: - DS.AddAttributes(ParseMicrosoftDeclSpec()); + ParseMicrosoftDeclSpec(DS.getAttributes()); continue; // Microsoft single token adornments. @@ -1215,34 +1209,39 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: - DS.AddAttributes(ParseMicrosoftTypeAttributes()); + ParseMicrosoftTypeAttributes(DS.getAttributes()); continue; // Borland single token adornments. case tok::kw___pascal: - DS.AddAttributes(ParseBorlandTypeAttributes()); + ParseBorlandTypeAttributes(DS.getAttributes()); + continue; + + // OpenCL single token adornments. + case tok::kw___kernel: + ParseOpenCLAttributes(DS.getAttributes()); continue; // storage-class-specifier case tok::kw_typedef: isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec, - DiagID); + DiagID, getLang()); break; case tok::kw_extern: if (DS.isThreadSpecified()) Diag(Tok, diag::ext_thread_before) << "extern"; isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec, - DiagID); + DiagID, getLang()); break; case tok::kw___private_extern__: isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc, - PrevSpec, DiagID); + PrevSpec, DiagID, getLang()); break; case tok::kw_static: if (DS.isThreadSpecified()) Diag(Tok, diag::ext_thread_before) << "static"; isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec, - DiagID); + DiagID, getLang()); break; case tok::kw_auto: if (getLang().CPlusPlus0x) @@ -1250,15 +1249,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DiagID); else isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec, - DiagID); + DiagID, getLang()); break; case tok::kw_register: isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec, - DiagID); + DiagID, getLang()); break; case tok::kw_mutable: isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec, - DiagID); + DiagID, getLang()); break; case tok::kw___thread: isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID); @@ -1354,8 +1353,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, break; case tok::kw_bool: case tok::kw__Bool: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, - DiagID); + if (Tok.is(tok::kw_bool) && + DS.getTypeSpecType() != DeclSpec::TST_unspecified && + DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { + PrevSpec = ""; // Not used by the diagnostic. + DiagID = diag::err_bool_redeclaration; + isInvalid = true; + } else { + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, + DiagID); + } break; case tok::kw__Decimal32: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec, @@ -1432,23 +1439,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DS.hasTypeSpecifier() || !getLang().ObjC1) goto DoneWithDeclSpec; - { - SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector<Decl *, 8> ProtocolDecl; - llvm::SmallVector<SourceLocation, 8> ProtocolLocs; - ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, - LAngleLoc, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), - ProtocolLocs.data(), LAngleLoc); - DS.SetRangeEnd(EndProtoLoc); - + if (!ParseObjCProtocolQualifiers(DS)) Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id) << FixItHint::CreateInsertion(Loc, "id") - << SourceRange(Loc, EndProtoLoc); - // Need to support trailing type qualifiers (e.g. "id<p> const"). - // If a type specifier follows, it will be diagnosed elsewhere. - continue; - } + << 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; } // If the specifier wasn't legal, issue a diagnostic. if (isInvalid) { @@ -1552,7 +1550,8 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, // simple-type-specifier: case tok::annot_typename: { if (ParsedType T = getTypeAnnotation(Tok)) { - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, + Tok.getAnnotationEndLoc(), PrevSpec, DiagID, T); } else DS.SetTypeSpecError(); @@ -1563,18 +1562,9 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an // Objective-C interface. If we don't have Objective-C or a '<', this is // just a normal reference to a typedef name. - if (!Tok.is(tok::less) || !getLang().ObjC1) - return true; - - SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector<Decl *, 8> ProtocolDecl; - llvm::SmallVector<SourceLocation, 8> ProtocolLocs; - ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, - LAngleLoc, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), - ProtocolLocs.data(), LAngleLoc); - - DS.SetRangeEnd(EndProtoLoc); + if (Tok.is(tok::less) && getLang().ObjC1) + ParseObjCProtocolQualifiers(DS); + return true; } @@ -1706,11 +1696,11 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: - DS.AddAttributes(ParseMicrosoftTypeAttributes()); + ParseMicrosoftTypeAttributes(DS.getAttributes()); return true; case tok::kw___pascal: - DS.AddAttributes(ParseBorlandTypeAttributes()); + ParseBorlandTypeAttributes(DS.getAttributes()); return true; default: @@ -1756,7 +1746,6 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { } // Parse the common specifier-qualifiers-list piece. - SourceLocation DSStart = Tok.getLocation(); ParseSpecifierQualifierList(DS); // If there are no declarators, this is a free-standing declaration @@ -1773,11 +1762,8 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { FieldDeclarator DeclaratorInfo(DS); // Attributes are only allowed here on successive declarators. - if (!FirstDeclarator && Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseGNUAttributes(&Loc); - DeclaratorInfo.D.AddAttributes(AttrList, Loc); - } + if (!FirstDeclarator) + MaybeParseGNUAttributes(DeclaratorInfo.D); /// struct-declarator: declarator /// struct-declarator: declarator[opt] ':' constant-expression @@ -1797,11 +1783,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { } // If attributes exist after the declarator, parse them. - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseGNUAttributes(&Loc); - DeclaratorInfo.D.AddAttributes(AttrList, Loc); - } + MaybeParseGNUAttributes(DeclaratorInfo.D); // We're done with this declarator; invoke the callback. Decl *D = Fields.invoke(DeclaratorInfo); @@ -1922,20 +1904,18 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); - llvm::OwningPtr<AttributeList> AttrList; + ParsedAttributes attrs; // If attributes exist after struct contents, parse them. - if (Tok.is(tok::kw___attribute)) - AttrList.reset(ParseGNUAttributes()); + MaybeParseGNUAttributes(attrs); Actions.ActOnFields(getCurScope(), RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(), LBraceLoc, RBraceLoc, - AttrList.get()); + attrs.getList()); StructScope.Exit(); Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, RBraceLoc); } - /// ParseEnumSpecifier /// enum-specifier: [C99 6.7.2.2] /// 'enum' identifier[opt] '{' enumerator-list '}' @@ -1945,6 +1925,21 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, /// 'enum' identifier /// [GNU] 'enum' attributes[opt] identifier /// +/// [C++0x] enum-head '{' enumerator-list[opt] '}' +/// [C++0x] enum-head '{' enumerator-list ',' '}' +/// +/// enum-head: [C++0x] +/// enum-key attributes[opt] identifier[opt] enum-base[opt] +/// enum-key attributes[opt] nested-name-specifier identifier enum-base[opt] +/// +/// enum-key: [C++0x] +/// 'enum' +/// 'enum' 'class' +/// 'enum' 'struct' +/// +/// enum-base: [C++0x] +/// ':' type-specifier-seq +/// /// [C++] elaborated-type-specifier: /// [C++] 'enum' '::'[opt] nested-name-specifier[opt] identifier /// @@ -1958,10 +1953,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, ConsumeCodeCompletionToken(); } - llvm::OwningPtr<AttributeList> Attr; // If attributes exist after tag, parse them. - if (Tok.is(tok::kw___attribute)) - Attr.reset(ParseGNUAttributes()); + ParsedAttributes attrs; + MaybeParseGNUAttributes(attrs); CXXScopeSpec &SS = DS.getTypeSpecScope(); if (getLang().CPlusPlus) { @@ -1979,6 +1973,16 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, } } + bool IsScopedEnum = false; + bool IsScopedUsingClassTag = false; + + if (getLang().CPlusPlus0x && + (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) { + IsScopedEnum = true; + IsScopedUsingClassTag = Tok.is(tok::kw_class); + ConsumeToken(); + } + // Must have either 'enum name' or 'enum {...}'. if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace)) { Diag(Tok, diag::err_expected_ident_lbrace); @@ -1996,6 +2000,69 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, NameLoc = ConsumeToken(); } + if (!Name && IsScopedEnum) { + // C++0x 7.2p2: The optional identifier shall not be omitted in the + // declaration of a scoped enumeration. + Diag(Tok, diag::err_scoped_enum_missing_identifier); + IsScopedEnum = false; + IsScopedUsingClassTag = false; + } + + TypeResult BaseType; + + // Parse the fixed underlying type. + if (getLang().CPlusPlus0x && Tok.is(tok::colon)) { + bool PossibleBitfield = false; + if (getCurScope()->getFlags() & Scope::ClassScope) { + // If we're in class scope, this can either be an enum declaration with + // an underlying type, or a declaration of a bitfield member. We try to + // use a simple disambiguation scheme first to catch the common cases + // (integer literal, sizeof); if it's still ambiguous, we then consider + // anything that's a simple-type-specifier followed by '(' as an + // expression. This suffices because function types are not valid + // underlying types anyway. + TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind()); + // If the next token starts an expression, we know we're parsing a + // bit-field. This is the common case. + if (TPR == TPResult::True()) + PossibleBitfield = true; + // If the next token starts a type-specifier-seq, it may be either a + // a fixed underlying type or the start of a function-style cast in C++; + // lookahead one more token to see if it's obvious that we have a + // fixed underlying type. + else if (TPR == TPResult::False() && + GetLookAheadToken(2).getKind() == tok::semi) { + // Consume the ':'. + ConsumeToken(); + } else { + // We have the start of a type-specifier-seq, so we have to perform + // tentative parsing to determine whether we have an expression or a + // type. + TentativeParsingAction TPA(*this); + + // Consume the ':'. + ConsumeToken(); + + if (isCXXDeclarationSpecifier() != TPResult::True()) { + // We'll parse this as a bitfield later. + PossibleBitfield = true; + TPA.Revert(); + } else { + // We have a type-specifier-seq. + TPA.Commit(); + } + } + } else { + // Consume the ':'. + ConsumeToken(); + } + + if (!PossibleBitfield) { + SourceRange Range; + BaseType = ParseTypeName(&Range); + } + } + // There are three options here. If we have 'enum foo;', then this is a // forward declaration. If we have 'enum foo {...' then this is a // definition. Otherwise we have something like 'enum foo xyz', a reference. @@ -2029,10 +2096,12 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, const char *PrevSpec = 0; unsigned DiagID; Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, - StartLoc, SS, Name, NameLoc, Attr.get(), + StartLoc, SS, Name, NameLoc, attrs.getList(), AS, MultiTemplateParamsArg(Actions), - Owned, IsDependent); + Owned, IsDependent, IsScopedEnum, + IsScopedUsingClassTag, BaseType); + if (IsDependent) { // This enum has a dependent nested-name-specifier. Handle it as a // dependent tag. @@ -2109,6 +2178,10 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { IdentifierInfo *Ident = Tok.getIdentifierInfo(); SourceLocation IdentLoc = ConsumeToken(); + // If attributes exist after the enumerator, parse them. + ParsedAttributes attrs; + MaybeParseGNUAttributes(attrs); + SourceLocation EqualLoc; ExprResult AssignedVal; if (Tok.is(tok::equal)) { @@ -2122,11 +2195,19 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { Decl *EnumConstDecl = Actions.ActOnEnumConstant(getCurScope(), EnumDecl, LastEnumConstDecl, IdentLoc, Ident, - EqualLoc, + attrs.getList(), EqualLoc, AssignedVal.release()); EnumConstantDecls.push_back(EnumConstDecl); LastEnumConstDecl = EnumConstDecl; + if (Tok.is(tok::identifier)) { + // We're missing a comma between enumerators. + SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation); + Diag(Loc, diag::err_enumerator_list_missing_comma) + << FixItHint::CreateInsertion(Loc, ", "); + continue; + } + if (Tok.isNot(tok::comma)) break; SourceLocation CommaLoc = ConsumeToken(); @@ -2141,14 +2222,13 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { // Eat the }. SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); - llvm::OwningPtr<AttributeList> Attr; // If attributes exist after the identifier list, parse them. - if (Tok.is(tok::kw___attribute)) - Attr.reset(ParseGNUAttributes()); // FIXME: where do they do? + ParsedAttributes attrs; + MaybeParseGNUAttributes(attrs); Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl, EnumConstantDecls.data(), EnumConstantDecls.size(), - getCurScope(), Attr.get()); + getCurScope(), attrs.getList()); EnumScope.Exit(); Actions.ActOnTagFinishDefinition(getCurScope(), EnumDecl, RBraceLoc); @@ -2296,7 +2376,10 @@ bool Parser::isTypeSpecifierQualifier() { /// isDeclarationSpecifier() - Return true if the current token is part of a /// declaration specifier. -bool Parser::isDeclarationSpecifier() { +/// +/// \param DisambiguatingWithExpression True to indicate that the purpose of +/// this check is to disambiguate between an expression and a declaration. +bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { switch (Tok.getKind()) { default: return false; @@ -2314,6 +2397,16 @@ bool Parser::isDeclarationSpecifier() { return true; if (Tok.is(tok::identifier)) return false; + + // If we're in Objective-C and we have an Objective-C class type followed + // by an identifier and then either ':' or ']', in a place where an + // expression is permitted, then this is probably a class message send + // missing the initial '['. In this case, we won't consider this to be + // the start of a declaration. + if (DisambiguatingWithExpression && + isStartOfObjCClassMessageMissingOpenBracket()) + return false; + return isDeclarationSpecifier(); case tok::coloncolon: // ::foo::bar @@ -2441,6 +2534,10 @@ bool Parser::isConstructorDeclarator() { if (SS.isSet() && Actions.ShouldEnterDeclaratorScope(getCurScope(), SS)) DeclScopeObj.EnterDeclaratorScope(); + // Optionally skip Microsoft attributes. + ParsedAttributes Attrs; + MaybeParseMicrosoftAttributes(Attrs); + // Check whether the next token(s) are part of a declaration // specifier, in which case we have the start of a parameter and, // therefore, we know that this is a constructor. @@ -2466,9 +2563,10 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool CXX0XAttributesAllowed) { if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { SourceLocation Loc = Tok.getLocation(); - CXX0XAttributeList Attr = ParseCXX0XAttributes(); + ParsedAttributesWithRange attrs; + ParseCXX0XAttributes(attrs); if (CXX0XAttributesAllowed) - DS.AddAttributes(Attr.AttrList); + DS.takeAttributesFrom(attrs); else Diag(Loc, diag::err_attributes_not_allowed); } @@ -2504,19 +2602,19 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, case tok::kw___fastcall: case tok::kw___thiscall: if (VendorAttributesAllowed) { - DS.AddAttributes(ParseMicrosoftTypeAttributes()); + ParseMicrosoftTypeAttributes(DS.getAttributes()); continue; } goto DoneWithTypeQuals; case tok::kw___pascal: if (VendorAttributesAllowed) { - DS.AddAttributes(ParseBorlandTypeAttributes()); + ParseBorlandTypeAttributes(DS.getAttributes()); continue; } goto DoneWithTypeQuals; case tok::kw___attribute: if (VendorAttributesAllowed) { - DS.AddAttributes(ParseGNUAttributes()); + ParseGNUAttributes(DS.getAttributes()); continue; // do *not* consume the next token! } // otherwise, FALL THROUGH! @@ -2602,7 +2700,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // Sema will have to catch (syntactically invalid) pointers into global // scope. It has to catch pointers into namespace scope anyway. D.AddTypeInfo(DeclaratorChunk::getMemberPointer(SS,DS.getTypeQualifiers(), - Loc, DS.TakeAttributes()), + Loc, DS.takeAttributes()), /* Don't replace range end. */SourceLocation()); return; } @@ -2636,12 +2734,12 @@ void Parser::ParseDeclaratorInternal(Declarator &D, if (Kind == tok::star) // Remember that we parsed a pointer type, and remember the type-quals. D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc, - DS.TakeAttributes()), + DS.takeAttributes()), SourceLocation()); else // Remember that we parsed a Block type, and remember the type-quals. D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(), - Loc, DS.TakeAttributes()), + Loc, DS.takeAttributes()), SourceLocation()); } else { // Is a reference @@ -2650,7 +2748,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // Complain about rvalue references in C++03, but then go on and build // the declarator. if (Kind == tok::ampamp && !getLang().CPlusPlus0x) - Diag(Loc, diag::err_rvalue_reference); + Diag(Loc, diag::ext_rvalue_reference); // C++ 8.3.2p1: cv-qualified references are ill-formed except when the // cv-qualifiers are introduced through the use of a typedef or of a @@ -2693,7 +2791,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // Remember that we parsed a reference type. It doesn't have type-quals. D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc, - DS.TakeAttributes(), + DS.takeAttributes(), Kind == tok::amp), SourceLocation()); } @@ -2718,7 +2816,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, /// [C++] declarator-id /// /// declarator-id: [C++ 8] -/// id-expression +/// '...'[opt] id-expression /// '::'[opt] nested-name-specifier[opt] type-name /// /// id-expression: [C++ 5.1] @@ -2748,6 +2846,20 @@ void Parser::ParseDirectDeclarator(Declarator &D) { DeclScopeObj.EnterDeclaratorScope(); } + // C++0x [dcl.fct]p14: + // There is a syntactic ambiguity when an ellipsis occurs at the end + // of a parameter-declaration-clause without a preceding comma. In + // this case, the ellipsis is parsed as part of the + // abstract-declarator if the type of the parameter names a template + // parameter pack that has not been expanded; otherwise, it is parsed + // as part of the parameter-declaration-clause. + if (Tok.is(tok::ellipsis) && + !((D.getContext() == Declarator::PrototypeContext || + D.getContext() == Declarator::BlockLiteralContext) && + NextToken().is(tok::r_paren) && + !Actions.containsUnexpandedParameterPacks(D))) + D.setEllipsisLoc(ConsumeToken()); + if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) { // We found something that indicates the start of an unqualified-id. @@ -2830,12 +2942,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { "Haven't past the location of the identifier yet?"); // Don't parse attributes unless we have an identifier. - if (D.getIdentifier() && getLang().CPlusPlus0x - && isCXX0XAttributeSpecifier(true)) { - SourceLocation AttrEndLoc; - CXX0XAttributeList Attr = ParseCXX0XAttributes(); - D.AddAttributes(Attr.AttrList, AttrEndLoc); - } + if (D.getIdentifier()) + MaybeParseCXX0XAttributes(D); while (1) { if (Tok.is(tok::l_paren)) { @@ -2849,7 +2957,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (!isCXXFunctionDeclarator(warnIfAmbiguous)) break; } - ParseFunctionDeclarator(ConsumeParen(), D); + ParsedAttributes attrs; + ParseFunctionDeclarator(ConsumeParen(), D, attrs); } else if (Tok.is(tok::l_square)) { ParseBracketDeclarator(D); } else { @@ -2885,10 +2994,10 @@ void Parser::ParseParenDeclarator(Declarator &D) { // In either case, we need to eat any attributes to be able to determine what // sort of paren this is. // - llvm::OwningPtr<AttributeList> AttrList; + ParsedAttributes attrs; bool RequiresArg = false; if (Tok.is(tok::kw___attribute)) { - AttrList.reset(ParseGNUAttributes()); + ParseGNUAttributes(attrs); // We require that the argument list (if this is a non-grouping paren) be // present even if the attribute list was empty. @@ -2898,12 +3007,11 @@ void Parser::ParseParenDeclarator(Declarator &D) { if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) || Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr64)) { - AttrList.reset(ParseMicrosoftTypeAttributes(AttrList.take())); + ParseMicrosoftTypeAttributes(attrs); } // Eat any Borland extensions. - if (Tok.is(tok::kw___pascal)) { - AttrList.reset(ParseBorlandTypeAttributes(AttrList.take())); - } + if (Tok.is(tok::kw___pascal)) + ParseBorlandTypeAttributes(attrs); // If we haven't past the identifier yet (or where the identifier would be // stored, if this is an abstract declarator), then this is probably just @@ -2932,15 +3040,15 @@ void Parser::ParseParenDeclarator(Declarator &D) { if (isGrouping) { bool hadGroupingParens = D.hasGroupingParens(); D.setGroupingParens(true); - if (AttrList) - D.AddAttributes(AttrList.take(), SourceLocation()); + if (!attrs.empty()) + D.addAttributes(attrs.getList(), SourceLocation()); ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); // Match the ')'. - SourceLocation Loc = MatchRHSPunctuation(tok::r_paren, StartLoc); + SourceLocation EndLoc = MatchRHSPunctuation(tok::r_paren, StartLoc); + D.AddTypeInfo(DeclaratorChunk::getParen(StartLoc, EndLoc), EndLoc); D.setGroupingParens(hadGroupingParens); - D.SetRangeEnd(Loc); return; } @@ -2950,7 +3058,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { // ParseFunctionDeclarator to handle of argument list. D.SetIdentifier(0, Tok.getLocation()); - ParseFunctionDeclarator(StartLoc, D, AttrList.take(), RequiresArg); + ParseFunctionDeclarator(StartLoc, D, attrs, RequiresArg); } /// ParseFunctionDeclarator - We are after the identifier and have parsed the @@ -2982,37 +3090,51 @@ void Parser::ParseParenDeclarator(Declarator &D) { /// '=' assignment-expression /// [GNU] declaration-specifiers abstract-declarator[opt] attributes /// -/// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]" -/// and "exception-specification[opt]". +/// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]", +/// C++0x "ref-qualifier[opt]" and "exception-specification[opt]". /// void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, - AttributeList *AttrList, + ParsedAttributes &attrs, bool RequiresArg) { // lparen is already consumed! assert(D.isPastIdentifier() && "Should not call before identifier!"); + ParsedType TrailingReturnType; + // This parameter list may be empty. if (Tok.is(tok::r_paren)) { - if (RequiresArg) { + if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); - delete AttrList; - } SourceLocation RParenLoc = ConsumeParen(); // Eat the closing ')'. SourceLocation EndLoc = RParenLoc; // cv-qualifier-seq[opt]. DeclSpec DS; + SourceLocation RefQualifierLoc; + bool RefQualifierIsLValueRef = true; bool hasExceptionSpec = false; SourceLocation ThrowLoc; bool hasAnyExceptionSpec = false; llvm::SmallVector<ParsedType, 2> Exceptions; llvm::SmallVector<SourceRange, 2> ExceptionRanges; if (getLang().CPlusPlus) { + MaybeParseCXX0XAttributes(attrs); + ParseTypeQualifierListOpt(DS, false /*no attributes*/); if (!DS.getSourceRange().getEnd().isInvalid()) EndLoc = DS.getSourceRange().getEnd(); + // Parse ref-qualifier[opt] + if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::ext_ref_qualifier); + + RefQualifierIsLValueRef = Tok.is(tok::amp); + RefQualifierLoc = ConsumeToken(); + EndLoc = RefQualifierLoc; + } + // Parse exception-specification[opt]. if (Tok.is(tok::kw_throw)) { hasExceptionSpec = true; @@ -3022,21 +3144,30 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, assert(Exceptions.size() == ExceptionRanges.size() && "Produced different number of exception types and ranges."); } + + // Parse trailing-return-type. + if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) { + TrailingReturnType = ParseTrailingReturnType().get(); + } } // Remember that we parsed a function type, and remember the attributes. // int() -> no prototype, no '...'. - D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/getLang().CPlusPlus, + D.AddTypeInfo(DeclaratorChunk::getFunction(attrs, + /*prototype*/getLang().CPlusPlus, /*variadic*/ false, SourceLocation(), /*arglist*/ 0, 0, DS.getTypeQualifiers(), + RefQualifierIsLValueRef, + RefQualifierLoc, hasExceptionSpec, ThrowLoc, hasAnyExceptionSpec, Exceptions.data(), ExceptionRanges.data(), Exceptions.size(), - LParenLoc, RParenLoc, D), + LParenLoc, RParenLoc, D, + TrailingReturnType), EndLoc); return; } @@ -3048,10 +3179,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, if (TryAnnotateTypeOrScopeToken() || !Tok.is(tok::annot_typename)) { // K&R identifier lists can't have typedefs as identifiers, per // C99 6.7.5.3p11. - if (RequiresArg) { + if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); - delete AttrList; - } // Identifier list. Note that '(' identifier-list ')' is only allowed for // normal declarators, not for abstract-declarators. Get the first @@ -3101,17 +3230,20 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, break; } - SourceLocation DSStart = Tok.getLocation(); - // Parse the declaration-specifiers. // Just use the ParsingDeclaration "scope" of the declarator. DeclSpec DS; + + // Skip any Microsoft attributes before a param. + if (getLang().Microsoft && Tok.is(tok::l_square)) + ParseMicrosoftAttributes(DS.getAttributes()); + + SourceLocation DSStart = Tok.getLocation(); // If the caller parsed attributes for the first argument, add them now. - if (AttrList) { - DS.AddAttributes(AttrList); - AttrList = 0; // Only apply the attributes to the first parameter. - } + // Take them so that we only apply the attributes to the first parameter. + DS.takeAttributesFrom(attrs); + ParseDeclarationSpecifiers(DS); // Parse the declarator. This is "PrototypeContext", because we must @@ -3120,11 +3252,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, ParseDeclarator(ParmDecl); // Parse GNU attributes, if present. - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseGNUAttributes(&Loc); - ParmDecl.AddAttributes(AttrList, Loc); - } + MaybeParseGNUAttributes(ParmDecl); // Remember this parsed parameter in ParamInfo. IdentifierInfo *ParmII = ParmDecl.getIdentifier(); @@ -3184,6 +3312,11 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Consume the '='. ConsumeToken(); + // The argument isn't actually potentially evaluated unless it is + // used. + EnterExpressionEvaluationContext Eval(Actions, + Sema::PotentiallyEvaluatedIfUsed); + ExprResult DefArgResult(ParseAssignmentExpression()); if (DefArgResult.isInvalid()) { Actions.ActOnParamDefaultArgumentError(Param); @@ -3222,14 +3355,13 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, ConsumeToken(); } - // Leave prototype scope. - PrototypeScope.Exit(); - // If we have the closing ')', eat it. SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); SourceLocation EndLoc = RParenLoc; DeclSpec DS; + SourceLocation RefQualifierLoc; + bool RefQualifierIsLValueRef = true; bool hasExceptionSpec = false; SourceLocation ThrowLoc; bool hasAnyExceptionSpec = false; @@ -3237,11 +3369,23 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, llvm::SmallVector<SourceRange, 2> ExceptionRanges; if (getLang().CPlusPlus) { + MaybeParseCXX0XAttributes(attrs); + // Parse cv-qualifier-seq[opt]. ParseTypeQualifierListOpt(DS, false /*no attributes*/); if (!DS.getSourceRange().getEnd().isInvalid()) EndLoc = DS.getSourceRange().getEnd(); + // Parse ref-qualifier[opt] + if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::ext_ref_qualifier); + + RefQualifierIsLValueRef = Tok.is(tok::amp); + RefQualifierLoc = ConsumeToken(); + EndLoc = RefQualifierLoc; + } + // Parse exception-specification[opt]. if (Tok.is(tok::kw_throw)) { hasExceptionSpec = true; @@ -3251,19 +3395,34 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, assert(Exceptions.size() == ExceptionRanges.size() && "Produced different number of exception types and ranges."); } + + // Parse trailing-return-type. + if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) { + TrailingReturnType = ParseTrailingReturnType().get(); + } } + // FIXME: We should leave the prototype scope before parsing the exception + // specification, and then reenter it when parsing the trailing return type. + + // Leave prototype scope. + PrototypeScope.Exit(); + // Remember that we parsed a function type, and remember the attributes. - D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic, + D.AddTypeInfo(DeclaratorChunk::getFunction(attrs, + /*proto*/true, IsVariadic, EllipsisLoc, ParamInfo.data(), ParamInfo.size(), DS.getTypeQualifiers(), + RefQualifierIsLValueRef, + RefQualifierLoc, hasExceptionSpec, ThrowLoc, hasAnyExceptionSpec, Exceptions.data(), ExceptionRanges.data(), Exceptions.size(), - LParenLoc, RParenLoc, D), + LParenLoc, RParenLoc, D, + TrailingReturnType), EndLoc); } @@ -3333,10 +3492,12 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, // Remember that we parsed a function type, and remember the attributes. This // function type is always a K&R style function type, which is not varargs and // has no prototype. - D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false, + D.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(), + /*proto*/false, /*varargs*/false, SourceLocation(), &ParamInfo[0], ParamInfo.size(), /*TypeQuals*/0, + true, SourceLocation(), /*exception*/false, SourceLocation(), false, 0, 0, 0, LParenLoc, RLoc, D), @@ -3355,15 +3516,12 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // This code does a fast path to handle some of the most obvious cases. if (Tok.getKind() == tok::r_square) { SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); - //FIXME: Use these - CXX0XAttributeList Attr; - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier(true)) { - Attr = ParseCXX0XAttributes(); - } + ParsedAttributes attrs; + MaybeParseCXX0XAttributes(attrs); // Remember that we parsed the empty array type. ExprResult NumElements; - D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, + D.AddTypeInfo(DeclaratorChunk::getArray(0, attrs, false, false, 0, StartLoc, EndLoc), EndLoc); return; @@ -3374,18 +3532,12 @@ void Parser::ParseBracketDeclarator(Declarator &D) { ConsumeToken(); SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); - //FIXME: Use these - CXX0XAttributeList Attr; - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { - Attr = ParseCXX0XAttributes(); - } - - // If there was an error parsing the assignment-expression, recover. - if (ExprRes.isInvalid()) - ExprRes.release(); // Deallocate expr, just use []. + ParsedAttributes attrs; + MaybeParseCXX0XAttributes(attrs); // Remember that we parsed a array type, and remember its features. - D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0, ExprRes.release(), + D.AddTypeInfo(DeclaratorChunk::getArray(0, attrs, false, 0, + ExprRes.release(), StartLoc, EndLoc), EndLoc); return; @@ -3446,14 +3598,11 @@ void Parser::ParseBracketDeclarator(Declarator &D) { SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); - //FIXME: Use these - CXX0XAttributeList Attr; - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { - Attr = ParseCXX0XAttributes(); - } + ParsedAttributes attrs; + MaybeParseCXX0XAttributes(attrs); // Remember that we parsed a array type, and remember its features. - D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), + D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), attrs, StaticLoc.isValid(), isStar, NumElements.release(), StartLoc, EndLoc), diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index b277156..b3ad25b 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -69,16 +69,16 @@ Decl *Parser::ParseNamespace(unsigned Context, } // Read label attributes, if present. - llvm::OwningPtr<AttributeList> AttrList; + ParsedAttributes attrs; if (Tok.is(tok::kw___attribute)) { attrTok = Tok; // FIXME: save these somewhere. - AttrList.reset(ParseGNUAttributes()); + ParseGNUAttributes(attrs); } if (Tok.is(tok::equal)) { - if (AttrList) + if (!attrs.empty()) Diag(attrTok, diag::err_unexpected_namespace_attributes_alias); if (InlineLoc.isValid()) Diag(InlineLoc, diag::err_inline_namespace_alias) @@ -112,16 +112,16 @@ Decl *Parser::ParseNamespace(unsigned Context, Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, IdentLoc, Ident, - LBrace, AttrList.get()); + LBrace, attrs.getList()); PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc, "parsing namespace"); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - CXX0XAttributeList Attr; - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) - Attr = ParseCXX0XAttributes(); - ParseExternalDeclaration(Attr); + ParsedAttributesWithRange attrs; + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + ParseExternalDeclaration(attrs); } // Leave the namespace scope. @@ -181,11 +181,9 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, /// 'extern' string-literal '{' declaration-seq[opt] '}' /// 'extern' string-literal declaration /// -Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, - unsigned Context) { +Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { assert(Tok.is(tok::string_literal) && "Not a string literal!"); llvm::SmallString<8> LangBuffer; - // LangBuffer is guaranteed to be big enough. bool Invalid = false; llvm::StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid); if (Invalid) @@ -201,41 +199,40 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, Tok.is(tok::l_brace)? Tok.getLocation() : SourceLocation()); - CXX0XAttributeList Attr; - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { - Attr = ParseCXX0XAttributes(); - } + ParsedAttributesWithRange attrs; + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); if (Tok.isNot(tok::l_brace)) { DS.setExternInLinkageSpec(true); - ParseExternalDeclaration(Attr, &DS); + ParseExternalDeclaration(attrs, &DS); return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec, SourceLocation()); } DS.abort(); - if (Attr.HasAttr) - Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) - << Attr.Range; + ProhibitAttributes(attrs); SourceLocation LBrace = ConsumeBrace(); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - CXX0XAttributeList Attr; - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) - Attr = ParseCXX0XAttributes(); - ParseExternalDeclaration(Attr); + ParsedAttributesWithRange attrs; + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + ParseExternalDeclaration(attrs); } SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace); - return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec, RBrace); + return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec, + RBrace); } /// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or /// using-directive. Assumes that current token is 'using'. Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, - SourceLocation &DeclEnd, - CXX0XAttributeList Attr) { + const ParsedTemplateInfo &TemplateInfo, + SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs) { assert(Tok.is(tok::kw_using) && "Not using token"); // Eat 'using'. @@ -246,17 +243,24 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, ConsumeCodeCompletionToken(); } - if (Tok.is(tok::kw_namespace)) - // Next token after 'using' is 'namespace' so it must be using-directive - return ParseUsingDirective(Context, UsingLoc, DeclEnd, Attr.AttrList); + // 'using namespace' means this is a using-directive. + if (Tok.is(tok::kw_namespace)) { + // Template parameters are always an error here. + if (TemplateInfo.Kind) { + SourceRange R = TemplateInfo.getSourceRange(); + Diag(UsingLoc, diag::err_templated_using_directive) + << R << FixItHint::CreateRemoval(R); + } + + return ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs); + } + + // Otherwise, it must be a using-declaration. - if (Attr.HasAttr) - Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) - << Attr.Range; + // Using declarations can't have attributes. + ProhibitAttributes(attrs); - // Otherwise, it must be using-declaration. - // Ignore illegal attributes (the caller should already have issued an error. - return ParseUsingDeclaration(Context, UsingLoc, DeclEnd); + return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd); } /// ParseUsingDirective - Parse C++ using-directive, assumes @@ -270,9 +274,9 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, /// namespace-name attributes[opt] ; /// Decl *Parser::ParseUsingDirective(unsigned Context, - SourceLocation UsingLoc, - SourceLocation &DeclEnd, - AttributeList *Attr) { + SourceLocation UsingLoc, + SourceLocation &DeclEnd, + ParsedAttributes &attrs) { assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token"); // Eat 'namespace'. @@ -307,17 +311,18 @@ Decl *Parser::ParseUsingDirective(unsigned Context, bool GNUAttr = false; if (Tok.is(tok::kw___attribute)) { GNUAttr = true; - Attr = addAttributeLists(Attr, ParseGNUAttributes()); + ParseGNUAttributes(attrs); } // Eat ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, - GNUAttr ? diag::err_expected_semi_after_attribute_list : - diag::err_expected_semi_after_namespace_name, "", tok::semi); + GNUAttr ? diag::err_expected_semi_after_attribute_list + : diag::err_expected_semi_after_namespace_name, + "", tok::semi); return Actions.ActOnUsingDirective(getCurScope(), UsingLoc, NamespcLoc, SS, - IdentLoc, NamespcName, Attr); + IdentLoc, NamespcName, attrs.getList()); } /// ParseUsingDeclaration - Parse C++ using-declaration. Assumes that @@ -329,13 +334,18 @@ Decl *Parser::ParseUsingDirective(unsigned Context, /// 'using' :: unqualified-id /// Decl *Parser::ParseUsingDeclaration(unsigned Context, - SourceLocation UsingLoc, - SourceLocation &DeclEnd, - AccessSpecifier AS) { + const ParsedTemplateInfo &TemplateInfo, + SourceLocation UsingLoc, + SourceLocation &DeclEnd, + AccessSpecifier AS) { CXXScopeSpec SS; SourceLocation TypenameLoc; bool IsTypeName; + // TODO: in C++0x, if we have template parameters this must be a + // template alias: + // template <...> using id = type; + // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. if (Tok.is(tok::kw_typename)) { @@ -370,18 +380,30 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, } // Parse (optional) attributes (most likely GNU strong-using extension). - llvm::OwningPtr<AttributeList> AttrList; - if (Tok.is(tok::kw___attribute)) - AttrList.reset(ParseGNUAttributes()); + ParsedAttributes attrs; + MaybeParseGNUAttributes(attrs); // Eat ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, diag::err_expected_semi_after, - AttrList ? "attributes list" : "using declaration", + !attrs.empty() ? "attributes list" : "using declaration", tok::semi); - return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, Name, - AttrList.get(), IsTypeName, TypenameLoc); + // Diagnose an attempt to declare a templated using-declaration. + if (TemplateInfo.Kind) { + SourceRange R = TemplateInfo.getSourceRange(); + Diag(UsingLoc, diag::err_templated_using_declaration) + << R << FixItHint::CreateRemoval(R); + + // Unfortunately, we have to bail out instead of recovering by + // ignoring the parameters, just in case the nested name specifier + // depends on the parameters. + return 0; + } + + return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, + Name, attrs.getList(), + IsTypeName, TypenameLoc); } /// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion. @@ -422,7 +444,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ MatchRHSPunctuation(tok::r_paren, LParenLoc); DeclEnd = Tok.getLocation(); - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_static_assert); + ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert); return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, AssertExpr.take(), @@ -652,20 +674,19 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SuppressingAccessChecks = true; } - AttributeList *AttrList = 0; + ParsedAttributes attrs; // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) - AttrList = ParseGNUAttributes(); + ParseGNUAttributes(attrs); // If declspecs exist after tag, parse them. while (Tok.is(tok::kw___declspec)) - AttrList = ParseMicrosoftDeclSpec(AttrList); + ParseMicrosoftDeclSpec(attrs); // If C++0x attributes exist here, parse them. // FIXME: Are we consistent with the ordering of parsing of different // styles of attributes? - if (isCXX0XAttributeSpecifier()) - AttrList = addAttributeLists(AttrList, ParseCXX0XAttributes().AttrList); + MaybeParseCXX0XAttributes(attrs); if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_pod)) { // GNU libstdc++ 4.2 uses __is_pod as the name of a struct template, but @@ -786,9 +807,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // There are four options here. If we have 'struct foo;', then this // is either a forward declaration or a friend declaration, which - // have to be treated differently. If we have 'struct foo {...' or - // 'struct foo :...' then this is a definition. Otherwise we have - // something like 'struct foo xyz', a reference. + // have to be treated differently. If we have 'struct foo {...', + // 'struct foo :...' or 'struct foo <class-virt-specifier>' then this is a + // definition. Otherwise we have something like 'struct foo xyz', a reference. // However, in some contexts, things look like declarations but are just // references, e.g. // new struct s; @@ -798,7 +819,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Sema::TagUseKind TUK; if (SuppressDeclarations) TUK = Sema::TUK_Reference; - else if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))){ + else if (Tok.is(tok::l_brace) || + (getLang().CPlusPlus && Tok.is(tok::colon)) || + isCXX0XClassVirtSpecifier() != ClassVirtSpecifiers::CVS_None) { if (DS.isFriendSpecified()) { // C++ [class.friend]p2: // A class shall not be defined in a friend declaration. @@ -859,7 +882,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, - AttrList); + attrs.getList()); // Friend template-ids are treated as references unless // they have template headers, in which case they're ill-formed @@ -875,7 +898,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateArgsPtr, TemplateId->RAngleLoc); - TypeResult = Actions.ActOnTagTemplateIdType(TypeResult, TUK, + TypeResult = Actions.ActOnTagTemplateIdType(SS, TypeResult, TUK, TagType, StartLoc); } else { // This is an explicit specialization or a class template @@ -921,7 +944,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, - AttrList, + attrs.getList(), MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); @@ -939,7 +962,16 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, TagType, StartLoc, SS, Name, - NameLoc, AttrList); + NameLoc, attrs.getList()); + } else if (TUK == Sema::TUK_Friend && + TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) { + TagOrTempResult = + Actions.ActOnTemplatedFriendTag(getCurScope(), DS.getFriendSpecLoc(), + TagType, StartLoc, SS, + Name, NameLoc, attrs.getList(), + MultiTemplateParamsArg(Actions, + TemplateParams? &(*TemplateParams)[0] : 0, + TemplateParams? TemplateParams->size() : 0)); } else { if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Sema::TUK_Definition) { @@ -948,25 +980,34 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, bool IsDependent = false; + // Don't pass down template parameter lists if this is just a tag + // reference. For example, we don't need the template parameters here: + // template <class T> class A *makeA(T t); + MultiTemplateParamsArg TParams; + if (TUK != Sema::TUK_Reference && TemplateParams) + TParams = + MultiTemplateParamsArg(&(*TemplateParams)[0], TemplateParams->size()); + // Declaration or definition of a class type - TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc, SS, - Name, NameLoc, AttrList, AS, - MultiTemplateParamsArg(Actions, - TemplateParams? &(*TemplateParams)[0] : 0, - TemplateParams? TemplateParams->size() : 0), - Owned, IsDependent); + TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc, + SS, Name, NameLoc, attrs.getList(), AS, + TParams, Owned, IsDependent, false, + false, clang::TypeResult()); // If ActOnTag said the type was dependent, try again with the // less common call. - if (IsDependent) + if (IsDependent) { + assert(TUK == Sema::TUK_Reference || TUK == Sema::TUK_Friend); TypeResult = Actions.ActOnDependentTag(getCurScope(), TagType, TUK, SS, Name, StartLoc, NameLoc); + } } // If there is a body, parse it and inform the actions module. if (TUK == Sema::TUK_Definition) { assert(Tok.is(tok::l_brace) || - (getLang().CPlusPlus && Tok.is(tok::colon))); + (getLang().CPlusPlus && Tok.is(tok::colon)) || + isCXX0XClassVirtSpecifier() != ClassVirtSpecifiers::CVS_None); if (getLang().CPlusPlus) ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get()); else @@ -1158,13 +1199,20 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { if (BaseType.isInvalid()) return true; + // Parse the optional ellipsis (for a pack expansion). The ellipsis is + // actually part of the base-specifier-list grammar productions, but we + // parse it here for convenience. + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + // Find the complete source range for the base-specifier. SourceRange Range(StartLoc, EndLocation); // Notify semantic analysis that we have parsed a complete // base-specifier. return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access, - BaseType.get(), BaseLoc); + BaseType.get(), BaseLoc, EllipsisLoc); } /// getAccessSpecifierIfPresent - Determine whether the next token is @@ -1189,15 +1237,14 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, // has any default arguments, we'll need to parse them later. LateParsedMethodDeclaration *LateMethod = 0; DeclaratorChunk::FunctionTypeInfo &FTI - = DeclaratorInfo.getTypeObject(0).Fun; + = DeclaratorInfo.getFunctionTypeInfo(); for (unsigned ParamIdx = 0; ParamIdx < FTI.NumArgs; ++ParamIdx) { if (LateMethod || FTI.ArgInfo[ParamIdx].DefaultArgTokens) { if (!LateMethod) { // Push this method onto the stack of late-parsed method // declarations. - getCurrentClass().MethodDecls.push_back( - LateParsedMethodDeclaration(ThisDecl)); - LateMethod = &getCurrentClass().MethodDecls.back(); + LateMethod = new LateParsedMethodDeclaration(this, ThisDecl); + getCurrentClass().LateParsedDeclarations.push_back(LateMethod); LateMethod->TemplateScope = getCurScope()->isTemplateParamScope(); // Add all of the parameters prior to this one (they don't @@ -1217,6 +1264,122 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, } } +/// isCXX0XVirtSpecifier - Determine whether the next token is a C++0x +/// virt-specifier. +/// +/// virt-specifier: +/// override +/// final +/// new +VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier() const { + if (!getLang().CPlusPlus) + return VirtSpecifiers::VS_None; + + if (Tok.is(tok::kw_new)) + return VirtSpecifiers::VS_New; + + if (Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + + // Initialize the contextual keywords. + if (!Ident_final) { + Ident_final = &PP.getIdentifierTable().get("final"); + Ident_override = &PP.getIdentifierTable().get("override"); + } + + if (II == Ident_override) + return VirtSpecifiers::VS_Override; + + if (II == Ident_final) + return VirtSpecifiers::VS_Final; + } + + return VirtSpecifiers::VS_None; +} + +/// ParseOptionalCXX0XVirtSpecifierSeq - Parse a virt-specifier-seq. +/// +/// virt-specifier-seq: +/// virt-specifier +/// virt-specifier-seq virt-specifier +void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) { + while (true) { + VirtSpecifiers::Specifier Specifier = isCXX0XVirtSpecifier(); + if (Specifier == VirtSpecifiers::VS_None) + return; + + // C++ [class.mem]p8: + // A virt-specifier-seq shall contain at most one of each virt-specifier. + const char *PrevSpec = 0; + if (VS.SetSpecifier(Specifier, Tok.getLocation(), PrevSpec)) + Diag(Tok.getLocation(), diag::err_duplicate_virt_specifier) + << PrevSpec + << FixItHint::CreateRemoval(Tok.getLocation()); + + if (!getLang().CPlusPlus0x) + Diag(Tok.getLocation(), diag::ext_override_control_keyword) + << VirtSpecifiers::getSpecifierName(Specifier); + ConsumeToken(); + } +} + +/// isCXX0XClassVirtSpecifier - Determine whether the next token is a C++0x +/// class-virt-specifier. +/// +/// class-virt-specifier: +/// final +/// explicit +ClassVirtSpecifiers::Specifier Parser::isCXX0XClassVirtSpecifier() const { + if (!getLang().CPlusPlus) + return ClassVirtSpecifiers::CVS_None; + + if (Tok.is(tok::kw_explicit)) + return ClassVirtSpecifiers::CVS_Explicit; + + if (Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + + // Initialize the contextual keywords. + if (!Ident_final) { + Ident_final = &PP.getIdentifierTable().get("final"); + Ident_override = &PP.getIdentifierTable().get("override"); + } + + if (II == Ident_final) + return ClassVirtSpecifiers::CVS_Final; + } + + return ClassVirtSpecifiers::CVS_None; +} + +/// ParseOptionalCXX0XClassVirtSpecifierSeq - Parse a class-virt-specifier-seq. +/// +/// class-virt-specifier-seq: +/// class-virt-specifier +/// class-virt-specifier-seq class-virt-specifier +void Parser::ParseOptionalCXX0XClassVirtSpecifierSeq(ClassVirtSpecifiers &CVS) { + while (true) { + ClassVirtSpecifiers::Specifier Specifier = isCXX0XClassVirtSpecifier(); + if (Specifier == ClassVirtSpecifiers::CVS_None) + return; + + // C++ [class]p1: + // A class-virt-specifier-seq shall contain at most one of each + // class-virt-specifier. + const char *PrevSpec = 0; + if (CVS.SetSpecifier(Specifier, Tok.getLocation(), PrevSpec)) + Diag(Tok.getLocation(), diag::err_duplicate_class_virt_specifier) + << PrevSpec + << FixItHint::CreateRemoval(Tok.getLocation()); + + if (!getLang().CPlusPlus0x) + Diag(Tok.getLocation(), diag::ext_override_control_keyword) + << ClassVirtSpecifiers::getSpecifierName(Specifier); + + ConsumeToken(); + } +} + /// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. /// /// member-declaration: @@ -1233,10 +1396,19 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, /// member-declarator-list ',' member-declarator /// /// member-declarator: -/// declarator pure-specifier[opt] +/// declarator virt-specifier-seq[opt] pure-specifier[opt] /// declarator constant-initializer[opt] /// identifier[opt] ':' constant-expression /// +/// virt-specifier-seq: +/// virt-specifier +/// virt-specifier-seq virt-specifier +/// +/// virt-specifier: +/// override +/// final +/// new +/// /// pure-specifier: /// '= 0' /// @@ -1315,17 +1487,15 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // is a bitfield. ColonProtectionRAIIObject X(*this); - CXX0XAttributeList AttrList; + ParsedAttributesWithRange attrs; // Optional C++0x attribute-specifier - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) - AttrList = ParseCXX0XAttributes(); + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); if (Tok.is(tok::kw_using)) { // FIXME: Check for template aliases - if (AttrList.HasAttr) - Diag(AttrList.Range.getBegin(), diag::err_attributes_not_allowed) - << AttrList.Range; + ProhibitAttributes(attrs); // Eat 'using'. SourceLocation UsingLoc = ConsumeToken(); @@ -1336,16 +1506,16 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } else { SourceLocation DeclEnd; // Otherwise, it must be using-declaration. - ParseUsingDeclaration(Declarator::MemberContext, UsingLoc, DeclEnd, AS); + ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo, + UsingLoc, DeclEnd, AS); } return; } - SourceLocation DSStart = Tok.getLocation(); // decl-specifier-seq: // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this, TemplateDiags); - DS.AddAttributes(AttrList.AttrList); + DS.takeAttributesFrom(attrs); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class); MultiTemplateParamsArg TemplateParams(Actions, @@ -1361,6 +1531,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); + VirtSpecifiers VS; if (Tok.isNot(tok::colon)) { // Don't parse FOO:BAR as if it were a typo for FOO::BAR. @@ -1377,12 +1548,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } + ParseOptionalCXX0XVirtSpecifierSeq(VS); + // If attributes exist after the declarator, but before an '{', parse them. - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseGNUAttributes(&Loc); - DeclaratorInfo.AddAttributes(AttrList, Loc); - } + MaybeParseGNUAttributes(DeclaratorInfo); // function-definition: if (Tok.is(tok::l_brace) @@ -1392,6 +1561,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, Diag(Tok, diag::err_func_def_no_params); ConsumeBrace(); SkipUntil(tok::r_brace, true); + + // Consume the optional ';' + if (Tok.is(tok::semi)) + ConsumeToken(); return; } @@ -1402,10 +1575,18 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // assumes the declarator represents a function, not a typedef. ConsumeBrace(); SkipUntil(tok::r_brace, true); + + // Consume the optional ';' + if (Tok.is(tok::semi)) + ConsumeToken(); return; } - ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo); + ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS); + // Consume the optional ';' + if (Tok.is(tok::semi)) + ConsumeToken(); + return; } } @@ -1431,6 +1612,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SkipUntil(tok::comma, true, true); } + ParseOptionalCXX0XVirtSpecifierSeq(VS); + // pure-specifier: // '= 0' // @@ -1442,7 +1625,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // '=' 'delete' if (Tok.is(tok::equal)) { ConsumeToken(); - if (getLang().CPlusPlus0x && Tok.is(tok::kw_delete)) { + if (Tok.is(tok::kw_delete)) { + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::warn_deleted_function_accepted_as_extension); ConsumeToken(); Deleted = true; } else { @@ -1464,11 +1649,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } // If attributes exist after the declarator, parse them. - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseGNUAttributes(&Loc); - DeclaratorInfo.AddAttributes(AttrList, Loc); - } + MaybeParseGNUAttributes(DeclaratorInfo); // NOTE: If Sema is the Action module and declarator is an instance field, // this call will *not* return the created decl; It will return null. @@ -1485,7 +1666,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, DeclaratorInfo, move(TemplateParams), BitfieldSize.release(), - Init.release(), + VS, Init.release(), /*IsDefinition*/Deleted, Deleted); } @@ -1510,16 +1691,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Parse the next declarator. DeclaratorInfo.clear(); + VS.clear(); BitfieldSize = 0; Init = 0; Deleted = false; // Attributes are only allowed on the second declarator. - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseGNUAttributes(&Loc); - DeclaratorInfo.AddAttributes(AttrList, Loc); - } + MaybeParseGNUAttributes(DeclaratorInfo); if (Tok.isNot(tok::colon)) ParseDeclarator(DeclaratorInfo); @@ -1585,6 +1763,9 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (TagDecl) Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); + ClassVirtSpecifiers CVS; + ParseOptionalCXX0XClassVirtSpecifierSeq(CVS); + if (Tok.is(tok::colon)) { ParseBaseClause(TagDecl); @@ -1602,7 +1783,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, SourceLocation LBraceLoc = ConsumeBrace(); if (TagDecl) - Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, LBraceLoc); + Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, CVS, + LBraceLoc); // C++ 11p3: Members of a class defined with the keyword class are private // by default. Members of a class defined with the keywords struct or union @@ -1654,14 +1836,13 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, } // If attributes exist after class contents, parse them. - llvm::OwningPtr<AttributeList> AttrList; - if (Tok.is(tok::kw___attribute)) - AttrList.reset(ParseGNUAttributes()); + ParsedAttributes attrs; + MaybeParseGNUAttributes(attrs); if (TagDecl) Actions.ActOnFinishCXXMemberSpecification(getCurScope(), RecordLoc, TagDecl, LBraceLoc, RBraceLoc, - AttrList.get()); + attrs.getList()); // C++ 9.2p2: Within the class member-specification, the class is regarded as // complete within function bodies, default arguments, @@ -1707,14 +1888,14 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, /// ':' mem-initializer-list /// /// [C++] mem-initializer-list: -/// mem-initializer -/// mem-initializer , mem-initializer-list +/// mem-initializer ...[opt] +/// mem-initializer ...[opt] , mem-initializer-list void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'"); SourceLocation ColonLoc = ConsumeToken(); - llvm::SmallVector<CXXBaseOrMemberInitializer*, 4> MemInitializers; + llvm::SmallVector<CXXCtorInitializer*, 4> MemInitializers; bool AnyErrors = false; do { @@ -1735,7 +1916,13 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { ConsumeToken(); else if (Tok.is(tok::l_brace)) break; - else { + // If the next token looks like a base or member initializer, assume that + // we're just missing a comma. + else if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) { + SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation); + Diag(Loc, diag::err_ctor_init_missing_comma) + << FixItHint::CreateInsertion(Loc, ", "); + } else { // Skip over garbage, until we get to '{'. Don't eat the '{'. Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma); SkipUntil(tok::l_brace, true, true); @@ -1801,11 +1988,15 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, TemplateTypeTy, IdLoc, LParenLoc, ArgExprs.take(), - ArgExprs.size(), CommaLocs.data(), - RParenLoc); + ArgExprs.size(), RParenLoc, + EllipsisLoc); } /// ParseExceptionSpecification - Parse a C++ exception-specification @@ -1816,8 +2007,8 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { /// [MS] 'throw' '(' '...' ')' /// /// type-id-list: -/// type-id -/// type-id-list ',' type-id +/// type-id ... [opt] +/// type-id-list ',' type-id ... [opt] /// bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, llvm::SmallVectorImpl<ParsedType> @@ -1827,7 +2018,7 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, bool &hasAnyExceptionSpec) { assert(Tok.is(tok::kw_throw) && "expected throw"); - SourceLocation ThrowLoc = ConsumeToken(); + ConsumeToken(); if (!Tok.is(tok::l_paren)) { return Diag(Tok, diag::err_expected_lparen_after) << "throw"; @@ -1849,10 +2040,21 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, SourceRange Range; while (Tok.isNot(tok::r_paren)) { TypeResult Res(ParseTypeName(&Range)); + + if (Tok.is(tok::ellipsis)) { + // C++0x [temp.variadic]p5: + // - In a dynamic-exception-specification (15.4); the pattern is a + // type-id. + SourceLocation Ellipsis = ConsumeToken(); + if (!Res.isInvalid()) + Res = Actions.ActOnPackExpansion(Res.get(), Ellipsis); + } + if (!Res.isInvalid()) { Exceptions.push_back(Res.get()); Ranges.push_back(Range); } + if (Tok.is(tok::comma)) ConsumeToken(); else @@ -1863,20 +2065,41 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, return false; } +/// ParseTrailingReturnType - Parse a trailing return type on a new-style +/// function declaration. +TypeResult Parser::ParseTrailingReturnType() { + assert(Tok.is(tok::arrow) && "expected arrow"); + + ConsumeToken(); + + // FIXME: Need to suppress declarations when parsing this typename. + // Otherwise in this function definition: + // + // auto f() -> struct X {} + // + // struct X is parsed as class definition because of the trailing + // brace. + + SourceRange Range; + return ParseTypeName(&Range); +} + /// \brief We have just started parsing the definition of a new class, /// so push that class onto our stack of classes that is currently /// being parsed. -void Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass) { +Sema::ParsingClassState +Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass) { assert((NonNestedClass || !ClassStack.empty()) && "Nested class without outer class"); ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass)); + return Actions.PushParsingClass(); } /// \brief Deallocate the given parsed class and all of its nested /// classes. void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) { - for (unsigned I = 0, N = Class->NestedClasses.size(); I != N; ++I) - DeallocateParsedClasses(Class->NestedClasses[I]); + for (unsigned I = 0, N = Class->LateParsedDeclarations.size(); I != N; ++I) + delete Class->LateParsedDeclarations[I]; delete Class; } @@ -1889,9 +2112,11 @@ void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) { /// /// \returns true if the class we've popped is a top-level class, /// false otherwise. -void Parser::PopParsingClass() { +void Parser::PopParsingClass(Sema::ParsingClassState state) { assert(!ClassStack.empty() && "Mismatched push/pop for class parsing"); + Actions.PopParsingClass(state); + ParsingClass *Victim = ClassStack.top(); ClassStack.pop(); if (Victim->TopLevelClass) { @@ -1902,13 +2127,12 @@ void Parser::PopParsingClass() { } assert(!ClassStack.empty() && "Missing top-level class?"); - if (Victim->MethodDecls.empty() && Victim->MethodDefs.empty() && - Victim->NestedClasses.empty()) { + if (Victim->LateParsedDeclarations.empty()) { // The victim is a nested class, but we will not need to perform // any processing after the definition of this class since it has // no members whose handling was delayed. Therefore, we can just // remove this nested class. - delete Victim; + DeallocateParsedClasses(Victim); return; } @@ -1916,7 +2140,7 @@ void Parser::PopParsingClass() { // after the top-level class is completely defined. Therefore, add // it to the list of nested classes within its parent. assert(getCurScope()->isClassScope() && "Nested class outside of class scope?"); - ClassStack.top()->NestedClasses.push_back(Victim); + ClassStack.top()->LateParsedDeclarations.push_back(new LateParsedClass(this, Victim)); Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope(); } @@ -1955,12 +2179,12 @@ void Parser::PopParsingClass() { /// '[' balanced-token-seq ']' /// '{' balanced-token-seq '}' /// any token but '(', ')', '[', ']', '{', or '}' -CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) { +void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, + SourceLocation *endLoc) { assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) && "Not a C++0x attribute list"); SourceLocation StartLoc = Tok.getLocation(), Loc; - AttributeList *CurrAttr = 0; ConsumeBracket(); ConsumeBracket(); @@ -2004,21 +2228,16 @@ CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) { switch(AttributeList::getKind(AttrName)) { // No arguments - case AttributeList::AT_base_check: case AttributeList::AT_carries_dependency: - case AttributeList::AT_final: - case AttributeList::AT_hiding: - case AttributeList::AT_noreturn: - case AttributeList::AT_override: { + case AttributeList::AT_noreturn: { if (Tok.is(tok::l_paren)) { Diag(Tok.getLocation(), diag::err_cxx0x_attribute_forbids_arguments) << AttrName->getName(); break; } - CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc, 0, - SourceLocation(), 0, 0, CurrAttr, false, - true); + attrs.add(AttrFactory.Create(AttrName, AttrLoc, 0, AttrLoc, 0, + SourceLocation(), 0, 0, false, true)); AttrParsed = true; break; } @@ -2038,9 +2257,9 @@ CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) { ExprVector ArgExprs(Actions); ArgExprs.push_back(ArgExpr.release()); - CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc, - 0, ParamLoc, ArgExprs.take(), 1, CurrAttr, - false, true); + attrs.add(AttrFactory.Create(AttrName, AttrLoc, 0, AttrLoc, + 0, ParamLoc, ArgExprs.take(), 1, + false, true)); AttrParsed = true; break; @@ -2065,8 +2284,7 @@ CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) { if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) SkipUntil(tok::r_square, false); - CXX0XAttributeList Attr (CurrAttr, SourceRange(StartLoc, Loc), true); - return Attr; + attrs.Range = SourceRange(StartLoc, Loc); } /// ParseCXX0XAlignArgument - Parse the argument to C++0x's [[align]] @@ -2088,3 +2306,23 @@ ExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) { } else return ParseConstantExpression(); } + +/// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr] +/// +/// [MS] ms-attribute: +/// '[' token-seq ']' +/// +/// [MS] ms-attribute-seq: +/// ms-attribute[opt] +/// ms-attribute ms-attribute-seq +void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc) { + assert(Tok.is(tok::l_square) && "Not a Microsoft attribute list"); + + while (Tok.is(tok::l_square)) { + ConsumeBracket(); + SkipUntil(tok::r_square, true, true); + if (endLoc) *endLoc = Tok.getLocation(); + ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); + } +} diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index c4beab1..616c251 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -172,13 +172,11 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, /// = *= /= %= += -= <<= >>= &= ^= |= /// /// expression: [C99 6.5.17] -/// assignment-expression -/// expression ',' assignment-expression +/// assignment-expression ...[opt] +/// expression ',' assignment-expression ...[opt] /// ExprResult Parser::ParseExpression() { ExprResult LHS(ParseAssignmentExpression()); - if (LHS.isInvalid()) return move(LHS); - return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); } @@ -190,8 +188,6 @@ ExprResult Parser::ParseExpression() { ExprResult Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { ExprResult LHS(ParseObjCAtExpression(AtLoc)); - if (LHS.isInvalid()) return move(LHS); - return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); } @@ -206,14 +202,13 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { ExtensionRAIIObject O(Diags); LHS = ParseCastExpression(false); - if (LHS.isInvalid()) return move(LHS); } - LHS = Actions.ActOnUnaryOp(getCurScope(), ExtLoc, tok::kw___extension__, - LHS.take()); - if (LHS.isInvalid()) return move(LHS); + if (!LHS.isInvalid()) + LHS = Actions.ActOnUnaryOp(getCurScope(), ExtLoc, tok::kw___extension__, + LHS.take()); - return ParseRHSOfBinaryExpression(LHS.take(), prec::Comma); + return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); } /// ParseAssignmentExpression - Parse an expr that doesn't include commas. @@ -228,9 +223,7 @@ ExprResult Parser::ParseAssignmentExpression() { return ParseThrowExpression(); ExprResult LHS(ParseCastExpression(false)); - if (LHS.isInvalid()) return move(LHS); - - return ParseRHSOfBinaryExpression(LHS.take(), prec::Assignment); + return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment); } /// ParseAssignmentExprWithObjCMessageExprStart - Parse an assignment expression @@ -249,10 +242,8 @@ Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, ExprResult R = ParseObjCMessageExpressionBody(LBracLoc, SuperLoc, ReceiverType, ReceiverExpr); - if (R.isInvalid()) return move(R); - R = ParsePostfixExpressionSuffix(R.take()); - if (R.isInvalid()) return move(R); - return ParseRHSOfBinaryExpression(R.take(), prec::Assignment); + R = ParsePostfixExpressionSuffix(R); + return ParseRHSOfBinaryExpression(R, prec::Assignment); } @@ -264,9 +255,7 @@ ExprResult Parser::ParseConstantExpression() { Sema::Unevaluated); ExprResult LHS(ParseCastExpression(false)); - if (LHS.isInvalid()) return move(LHS); - - return ParseRHSOfBinaryExpression(LHS.take(), prec::Conditional); + return ParseRHSOfBinaryExpression(LHS, prec::Conditional); } /// ParseRHSOfBinaryExpression - Parse a binary expression that starts with @@ -301,8 +290,10 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { // In particular, the RHS of the '?' is 'expression', not // 'logical-OR-expression' as we might expect. TernaryMiddle = ParseExpression(); - if (TernaryMiddle.isInvalid()) - return move(TernaryMiddle); + if (TernaryMiddle.isInvalid()) { + LHS = ExprError(); + TernaryMiddle = 0; + } } else { // Special case handling of "X ? Y : Z" where Y is empty: // logical-OR-expression '?' ':' conditional-expression [GNU] @@ -362,9 +353,10 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { RHS = ParseAssignmentExpression(); else RHS = ParseCastExpression(false); - if (RHS.isInvalid()) - return move(RHS); + if (RHS.isInvalid()) + LHS = ExprError(); + // Remember the precedence of this operator and get the precedence of the // operator immediately to the right of the RHS. prec::Level ThisPrec = NextTokPrec; @@ -384,10 +376,11 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { // is okay, to bind exactly as tightly. For example, compile A=B=C=D as // A=(B=(C=D)), where each paren is a level of recursion here. // The function takes ownership of the RHS. - RHS = ParseRHSOfBinaryExpression(RHS.get(), + RHS = ParseRHSOfBinaryExpression(RHS, static_cast<prec::Level>(ThisPrec + !isRightAssoc)); + if (RHS.isInvalid()) - return move(RHS); + LHS = ExprError(); NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLang().CPlusPlus0x); @@ -426,9 +419,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ParsedType TypeOfCast) { bool NotCastExpr; ExprResult Res = ParseCastExpression(isUnaryExpression, - isAddressOfOperand, - NotCastExpr, - TypeOfCast); + isAddressOfOperand, + NotCastExpr, + TypeOfCast); if (NotCastExpr) Diag(Tok, diag::err_expected_expression); return move(Res); @@ -451,12 +444,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// unary-operator cast-expression /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' +/// [C++0x] 'sizeof' '...' '(' identifier ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' /// [GNU] '&&' identifier /// [C++] new-expression /// [C++] delete-expression +/// [C++0x] 'noexcept' '(' expression ')' /// /// unary-operator: one of /// '&' '*' '+' '-' '~' '!' @@ -542,13 +537,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// '__is_polymorphic' /// '__is_union' /// -/// [GNU] binary-type-trait: -/// '__is_base_of' [TODO] +/// binary-type-trait: +/// [GNU] '__is_base_of' +/// [MS] '__is_convertible_to' /// ExprResult Parser::ParseCastExpression(bool isUnaryExpression, - bool isAddressOfOperand, - bool &NotCastExpr, - ParsedType TypeOfCast) { + bool isAddressOfOperand, + bool &NotCastExpr, + ParsedType TypeOfCast) { ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); NotCastExpr = false; @@ -571,17 +567,15 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ParenParseOption ParenExprType = (isUnaryExpression && !getLang().CPlusPlus)? CompoundLiteral : CastExpr; ParsedType CastTy; - SourceLocation LParenLoc = Tok.getLocation(); SourceLocation RParenLoc; { - // The inside of the parens don't need to be a colon protected scope. + // The inside of the parens don't need to be a colon protected scope, and + // isn't immediately a message send. ColonProtectionRAIIObject X(*this, false); - + Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, TypeOfCast, CastTy, RParenLoc); - if (Res.isInvalid()) - return move(Res); } switch (ParenExprType) { @@ -647,7 +641,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, (Actions.getTypeName(II, ILoc, getCurScope()) || // Allow the base to be 'super' if in an objc-method. (&II == Ident_super && getCurScope()->isInObjcMethodScope()))) { - SourceLocation DotLoc = ConsumeToken(); + ConsumeToken(); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_property_name); @@ -661,6 +655,54 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, break; } + // In an Objective-C method, if we have "super" followed by an identifier, + // the token sequence is ill-formed. However, if there's a ':' or ']' after + // that identifier, this is probably a message send with a missing open + // bracket. Treat it as such. + if (getLang().ObjC1 && &II == Ident_super && !InMessageExpression && + getCurScope()->isInObjcMethodScope() && + ((Tok.is(tok::identifier) && + (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) || + Tok.is(tok::code_completion))) { + Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, ParsedType(), + 0); + break; + } + + // If we have an Objective-C class name followed by an identifier + // and either ':' or ']', this is an Objective-C class message + // send that's missing the opening '['. Recovery + // appropriately. Also take this path if we're performing code + // completion after an Objective-C class name. + if (getLang().ObjC1 && + ((Tok.is(tok::identifier) && !InMessageExpression) || + Tok.is(tok::code_completion))) { + const Token& Next = NextToken(); + if (Tok.is(tok::code_completion) || + Next.is(tok::colon) || Next.is(tok::r_square)) + if (ParsedType Typ = Actions.getTypeName(II, ILoc, getCurScope())) + if (Typ.get()->isObjCObjectOrInterfaceType()) { + // Fake up a Declarator to use with ActOnTypeName. + DeclSpec DS; + DS.SetRangeStart(ILoc); + DS.SetRangeEnd(ILoc); + const char *PrevSpec = 0; + unsigned DiagID; + DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Typ); + + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + TypeResult Ty = Actions.ActOnTypeName(getCurScope(), + DeclaratorInfo); + if (Ty.isInvalid()) + break; + + Res = ParseObjCMessageExpressionBody(SourceLocation(), + SourceLocation(), + Ty.get(), 0); + break; + } + } + // Make sure to pass down the right value for isAddressOfOperand. if (isAddressOfOperand && isPostfixExpressionSuffixStart()) isAddressOfOperand = false; @@ -692,7 +734,6 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___builtin_va_arg: case tok::kw___builtin_offsetof: case tok::kw___builtin_choose_expr: - case tok::kw___builtin_types_compatible_p: return ParseBuiltinPrimaryExpression(); case tok::kw___null: return Actions.ActOnGNUNullExpr(ConsumeToken()); @@ -753,9 +794,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, if (Tok.isNot(tok::identifier)) return ExprError(Diag(Tok, diag::err_expected_ident)); + if (getCurScope()->getFnParent() == 0) + return ExprError(Diag(Tok, diag::err_address_of_label_outside_fn)); + Diag(AmpAmpLoc, diag::ext_gnu_address_of_label); - Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), - Tok.getIdentifierInfo()); + LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(), + Tok.getLocation()); + Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), LD); ConsumeToken(); return move(Res); } @@ -768,10 +813,39 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_typeid: Res = ParseCXXTypeid(); break; + case tok::kw___uuidof: + Res = ParseCXXUuidof(); + break; case tok::kw_this: Res = ParseCXXThis(); break; + case tok::annot_typename: + if (isStartOfObjCClassMessageMissingOpenBracket()) { + ParsedType Type = getTypeAnnotation(Tok); + + // Fake up a Declarator to use with ActOnTypeName. + DeclSpec DS; + DS.SetRangeStart(Tok.getLocation()); + DS.SetRangeEnd(Tok.getLastLoc()); + + const char *PrevSpec = 0; + unsigned DiagID; + DS.SetTypeSpecType(TST_typename, Tok.getAnnotationEndLoc(), + PrevSpec, DiagID, Type); + + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); + if (Ty.isInvalid()) + break; + + ConsumeToken(); + Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), + Ty.get(), 0); + break; + } + // Fall through + case tok::kw_char: case tok::kw_wchar_t: case tok::kw_char16_t: @@ -787,8 +861,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_void: case tok::kw_typename: case tok::kw_typeof: - case tok::kw___vector: - case tok::annot_typename: { + case tok::kw___vector: { if (!getLang().CPlusPlus) { Diag(Tok, diag::err_expected_expression); return ExprError(); @@ -888,6 +961,23 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_delete: // [C++] delete-expression return ParseCXXDeleteExpression(false, Tok.getLocation()); + case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')' + SourceLocation KeyLoc = ConsumeToken(); + SourceLocation LParen = Tok.getLocation(); + if (ExpectAndConsume(tok::l_paren, + diag::err_expected_lparen_after, "noexcept")) + return ExprError(); + // C++ [expr.unary.noexcept]p1: + // The noexcept operator determines whether the evaluation of its operand, + // which is an unevaluated operand, can throw an exception. + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + ExprResult Result = ParseExpression(); + SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); + if (!Result.isInvalid()) + Result = Actions.ActOnNoexceptExpr(KeyLoc, LParen, Result.take(), RParen); + return move(Result); + } + case tok::kw___is_pod: // [GNU] unary-type-trait case tok::kw___is_class: case tok::kw___is_enum: @@ -906,6 +996,11 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___has_virtual_destructor: return ParseUnaryTypeTrait(); + case tok::kw___builtin_types_compatible_p: + case tok::kw___is_base_of: + case tok::kw___is_convertible_to: + return ParseBinaryTypeTrait(); + case tok::at: { SourceLocation AtLoc = ConsumeToken(); return ParseObjCAtExpression(AtLoc); @@ -928,8 +1023,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, } // These can be followed by postfix-expr pieces. - if (Res.isInvalid()) return move(Res); - return ParsePostfixExpressionSuffix(Res.get()); + return ParsePostfixExpressionSuffix(Res); } /// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression @@ -947,8 +1041,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// '(' type-name ')' '{' initializer-list ',' '}' /// /// argument-expression-list: [C99 6.5.2] -/// argument-expression -/// argument-expression-list ',' assignment-expression +/// argument-expression ...[opt] +/// argument-expression-list ',' assignment-expression ...[opt] /// ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { @@ -957,6 +1051,28 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { SourceLocation Loc; while (1) { switch (Tok.getKind()) { + case tok::code_completion: + if (InMessageExpression) + return move(LHS); + + Actions.CodeCompletePostfixExpression(getCurScope(), LHS); + ConsumeCodeCompletionToken(); + LHS = ExprError(); + break; + + case tok::identifier: + // If we see identifier: after an expression, and we're not already in a + // message send, then this is probably a message send with a missing + // opening bracket '['. + if (getLang().ObjC1 && !InMessageExpression && + (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { + LHS = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), + ParsedType(), LHS.get()); + break; + } + + // Fall through; this isn't a message send. + default: // Not a postfix-expression suffix. return move(LHS); case tok::l_square: { // postfix-expression: p-e '[' expression ']' @@ -986,45 +1102,87 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { break; } - case tok::l_paren: { // p-e: p-e '(' argument-expression-list[opt] ')' - ExprVector ArgExprs(Actions); - CommaLocsTy CommaLocs; + case tok::l_paren: // p-e: p-e '(' argument-expression-list[opt] ')' + case tok::lesslessless: { // p-e: p-e '<<<' argument-expression-list '>>>' + // '(' argument-expression-list[opt] ')' + tok::TokenKind OpKind = Tok.getKind(); + InMessageExpressionRAIIObject InMessage(*this, false); + + Expr *ExecConfig = 0; - Loc = ConsumeParen(); + if (OpKind == tok::lesslessless) { + ExprVector ExecConfigExprs(Actions); + CommaLocsTy ExecConfigCommaLocs; + SourceLocation LLLLoc, GGGLoc; - if (LHS.isInvalid()) { - SkipUntil(tok::r_paren); - return ExprError(); + LLLLoc = ConsumeToken(); + + if (ParseExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) { + LHS = ExprError(); + } + + if (LHS.isInvalid()) { + SkipUntil(tok::greatergreatergreater); + } else if (Tok.isNot(tok::greatergreatergreater)) { + MatchRHSPunctuation(tok::greatergreatergreater, LLLLoc); + LHS = ExprError(); + } else { + GGGLoc = ConsumeToken(); + } + + if (!LHS.isInvalid()) { + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen, "")) + LHS = ExprError(); + else + Loc = PrevTokLocation; + } + + if (!LHS.isInvalid()) { + ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(), + LLLLoc, move_arg(ExecConfigExprs), GGGLoc); + if (ECResult.isInvalid()) + LHS = ExprError(); + else + ExecConfig = ECResult.get(); + } + } else { + Loc = ConsumeParen(); } + ExprVector ArgExprs(Actions); + CommaLocsTy CommaLocs; + if (Tok.is(tok::code_completion)) { Actions.CodeCompleteCall(getCurScope(), LHS.get(), 0, 0); ConsumeCodeCompletionToken(); } - - if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs, &Sema::CodeCompleteCall, - LHS.get())) { - SkipUntil(tok::r_paren); - return ExprError(); + + if (OpKind == tok::l_paren || !LHS.isInvalid()) { + if (Tok.isNot(tok::r_paren)) { + if (ParseExpressionList(ArgExprs, CommaLocs, &Sema::CodeCompleteCall, + LHS.get())) { + SkipUntil(tok::r_paren); + LHS = ExprError(); + } } } // Match the ')'. - if (Tok.isNot(tok::r_paren)) { + if (LHS.isInvalid()) { + SkipUntil(tok::r_paren); + } else if (Tok.isNot(tok::r_paren)) { MatchRHSPunctuation(tok::r_paren, Loc); - return ExprError(); - } - - if (!LHS.isInvalid()) { - assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&& + LHS = ExprError(); + } else { + assert((ArgExprs.size() == 0 || + ArgExprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); LHS = Actions.ActOnCallExpr(getCurScope(), LHS.take(), Loc, - move_arg(ArgExprs), CommaLocs.data(), - Tok.getLocation()); + move_arg(ArgExprs), Tok.getLocation(), + ExecConfig); + ConsumeParen(); } - ConsumeParen(); break; } case tok::arrow: @@ -1069,14 +1227,16 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // expression), or we didn't see a '~' in the right place. We // can still parse a destructor name here, but in that case it // names a real destructor. + // Allow explicit constructor calls in Microsoft mode. + // FIXME: Add support for explicit call of template constructor. UnqualifiedId Name; if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, /*AllowDestructorName=*/true, - /*AllowConstructorName=*/false, + /*AllowConstructorName=*/ getLang().Microsoft, ObjectType, Name)) - return ExprError(); + LHS = ExprError(); if (!LHS.isInvalid()) LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.take(), OpLoc, @@ -1189,6 +1349,7 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' +/// [C++0x] 'sizeof' '...' '(' identifier ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' @@ -1199,6 +1360,46 @@ ExprResult Parser::ParseSizeofAlignofExpression() { Token OpTok = Tok; ConsumeToken(); + // [C++0x] 'sizeof' '...' '(' identifier ')' + if (Tok.is(tok::ellipsis) && OpTok.is(tok::kw_sizeof)) { + SourceLocation EllipsisLoc = ConsumeToken(); + SourceLocation LParenLoc, RParenLoc; + IdentifierInfo *Name = 0; + SourceLocation NameLoc; + if (Tok.is(tok::l_paren)) { + LParenLoc = ConsumeParen(); + if (Tok.is(tok::identifier)) { + Name = Tok.getIdentifierInfo(); + NameLoc = ConsumeToken(); + RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + if (RParenLoc.isInvalid()) + RParenLoc = PP.getLocForEndOfToken(NameLoc); + } else { + Diag(Tok, diag::err_expected_parameter_pack); + SkipUntil(tok::r_paren); + } + } else if (Tok.is(tok::identifier)) { + Name = Tok.getIdentifierInfo(); + NameLoc = ConsumeToken(); + LParenLoc = PP.getLocForEndOfToken(EllipsisLoc); + RParenLoc = PP.getLocForEndOfToken(NameLoc); + Diag(LParenLoc, diag::err_paren_sizeof_parameter_pack) + << Name + << FixItHint::CreateInsertion(LParenLoc, "(") + << FixItHint::CreateInsertion(RParenLoc, ")"); + } else { + Diag(Tok, diag::err_sizeof_parameter_pack); + } + + if (!Name) + return ExprError(); + + return Actions.ActOnSizeofParameterPackExpr(getCurScope(), + OpTok.getLocation(), + *Name, NameLoc, + RParenLoc); + } + bool isCastExpr; ParsedType CastTy; SourceRange CastRange; @@ -1256,21 +1457,18 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { default: assert(0 && "Not a builtin primary expression!"); case tok::kw___builtin_va_arg: { ExprResult Expr(ParseAssignmentExpression()); - if (Expr.isInvalid()) { - SkipUntil(tok::r_paren); - return ExprError(); - } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) - return ExprError(); + Expr = ExprError(); TypeResult Ty = ParseTypeName(); if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); - return ExprError(); + Expr = ExprError(); } - if (Ty.isInvalid()) + + if (Expr.isInvalid() || Ty.isInvalid()) Res = ExprError(); else Res = Actions.ActOnVAArg(StartLoc, Expr.take(), Ty.get(), ConsumeParen()); @@ -1378,25 +1576,6 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { Expr2.take(), ConsumeParen()); break; } - case tok::kw___builtin_types_compatible_p: - TypeResult Ty1 = ParseTypeName(); - - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) - return ExprError(); - - TypeResult Ty2 = ParseTypeName(); - - if (Tok.isNot(tok::r_paren)) { - Diag(Tok, diag::err_expected_rparen); - return ExprError(); - } - - if (Ty1.isInvalid() || Ty2.isInvalid()) - Res = ExprError(); - else - Res = Actions.ActOnTypesCompatibleExpr(StartLoc, Ty1.get(), Ty2.get(), - ConsumeParen()); - break; } if (Res.isInvalid()) @@ -1432,9 +1611,18 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, bool isAmbiguousTypeId; CastTy = ParsedType(); + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(getCurScope(), + ExprType >= CompoundLiteral? Sema::PCC_ParenthesizedExpression + : Sema::PCC_Expression); + ConsumeCodeCompletionToken(); + return ExprError(); + } + if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { Diag(Tok, diag::ext_gnu_statement_expr); - StmtResult Stmt(ParseCompoundStatement(0, true)); + ParsedAttributes attrs; + StmtResult Stmt(ParseCompoundStatement(attrs, true)); ExprType = CompoundStmt; // If the substmt parsed correctly, build the AST node. @@ -1455,55 +1643,74 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, return ParseCXXAmbiguousParenExpression(ExprType, CastTy, OpenLoc, RParenLoc); - TypeResult Ty = ParseTypeName(); - - // Match the ')'. - if (Tok.is(tok::r_paren)) - RParenLoc = ConsumeParen(); - else - MatchRHSPunctuation(tok::r_paren, OpenLoc); - - if (Tok.is(tok::l_brace)) { - ExprType = CompoundLiteral; - return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc); + TypeResult Ty; + + { + InMessageExpressionRAIIObject InMessage(*this, false); + Ty = ParseTypeName(); } + + // If our type is followed by an identifier and either ':' or ']', then + // this is probably an Objective-C message send where the leading '[' is + // missing. Recover as if that were the case. + if (!Ty.isInvalid() && Tok.is(tok::identifier) && !InMessageExpression && + getLang().ObjC1 && !Ty.get().get().isNull() && + (NextToken().is(tok::colon) || NextToken().is(tok::r_square)) && + Ty.get().get()->isObjCObjectOrInterfaceType()) { + Result = ParseObjCMessageExpressionBody(SourceLocation(), + SourceLocation(), + Ty.get(), 0); + } else { + // Match the ')'. + if (Tok.is(tok::r_paren)) + RParenLoc = ConsumeParen(); + else + MatchRHSPunctuation(tok::r_paren, OpenLoc); + + if (Tok.is(tok::l_brace)) { + ExprType = CompoundLiteral; + return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc); + } - if (ExprType == CastExpr) { - // We parsed '(' type-name ')' and the thing after it wasn't a '{'. + if (ExprType == CastExpr) { + // We parsed '(' type-name ')' and the thing after it wasn't a '{'. - if (Ty.isInvalid()) - return ExprError(); + if (Ty.isInvalid()) + return ExprError(); - CastTy = Ty.get(); + CastTy = Ty.get(); - // Note that this doesn't parse the subsequent cast-expression, it just - // returns the parsed type to the callee. - if (stopIfCastExpr) - return ExprResult(); - - // Reject the cast of super idiom in ObjC. - if (Tok.is(tok::identifier) && getLang().ObjC1 && - Tok.getIdentifierInfo() == Ident_super && - getCurScope()->isInObjcMethodScope() && - GetLookAheadToken(1).isNot(tok::period)) { - Diag(Tok.getLocation(), diag::err_illegal_super_cast) - << SourceRange(OpenLoc, RParenLoc); - return ExprError(); + // Note that this doesn't parse the subsequent cast-expression, it just + // returns the parsed type to the callee. + if (stopIfCastExpr) + return ExprResult(); + + // Reject the cast of super idiom in ObjC. + if (Tok.is(tok::identifier) && getLang().ObjC1 && + Tok.getIdentifierInfo() == Ident_super && + getCurScope()->isInObjcMethodScope() && + GetLookAheadToken(1).isNot(tok::period)) { + Diag(Tok.getLocation(), diag::err_illegal_super_cast) + << SourceRange(OpenLoc, RParenLoc); + return ExprError(); + } + + // Parse the cast-expression that follows it next. + // TODO: For cast expression with CastTy. + Result = ParseCastExpression(false, false, CastTy); + if (!Result.isInvalid()) + Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, CastTy, + RParenLoc, Result.take()); + return move(Result); } - // Parse the cast-expression that follows it next. - // TODO: For cast expression with CastTy. - Result = ParseCastExpression(false, false, CastTy); - if (!Result.isInvalid()) - Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, CastTy, RParenLoc, - Result.take()); - return move(Result); + Diag(Tok, diag::err_expected_lbrace_in_compound_literal); + return ExprError(); } - - Diag(Tok, diag::err_expected_lbrace_in_compound_literal); - return ExprError(); } else if (TypeOfCast) { // Parse the expression-list. + InMessageExpressionRAIIObject InMessage(*this, false); + ExprVector ArgExprs(Actions); CommaLocsTy CommaLocs; @@ -1513,6 +1720,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, move_arg(ArgExprs), TypeOfCast); } } else { + InMessageExpressionRAIIObject InMessage(*this, false); + Result = ParseExpression(); ExprType = SimpleExpr; if (!Result.isInvalid() && Tok.is(tok::r_paren)) @@ -1582,8 +1791,8 @@ ExprResult Parser::ParseStringLiteralExpression() { /// argument-expression-list , assignment-expression /// /// [C++] expression-list: -/// [C++] assignment-expression -/// [C++] expression-list , assignment-expression +/// [C++] assignment-expression ...[opt] +/// [C++] expression-list , assignment-expression ...[opt] /// bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs, llvm::SmallVectorImpl<SourceLocation> &CommaLocs, @@ -1596,10 +1805,14 @@ bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs, if (Tok.is(tok::code_completion)) { if (Completer) (Actions.*Completer)(getCurScope(), Data, Exprs.data(), Exprs.size()); + else + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); ConsumeCodeCompletionToken(); } ExprResult Expr(ParseAssignmentExpression()); + if (Tok.is(tok::ellipsis)) + Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); if (Expr.isInvalid()) return true; @@ -1618,6 +1831,11 @@ bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs, /// [clang] specifier-qualifier-list block-declarator /// void Parser::ParseBlockId() { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); + ConsumeCodeCompletionToken(); + } + // Parse the specifier-qualifier-list piece. DeclSpec DS; ParseSpecifierQualifierList(DS); @@ -1627,14 +1845,9 @@ void Parser::ParseBlockId() { ParseDeclarator(DeclaratorInfo); // We do this for: ^ __attribute__((noreturn)) {, as DS has the attributes. - DeclaratorInfo.AddAttributes(DS.TakeAttributes(), - SourceLocation()); + DeclaratorInfo.addAttributes(DS.takeAttributes()); - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseGNUAttributes(&Loc); - DeclaratorInfo.AddAttributes(AttrList, Loc); - } + MaybeParseGNUAttributes(DeclaratorInfo); // Inform sema that we are starting a block. Actions.ActOnBlockArguments(DeclaratorInfo, getCurScope()); @@ -1692,11 +1905,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { return ExprError(); } - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseGNUAttributes(&Loc); - ParamInfo.AddAttributes(AttrList, Loc); - } + MaybeParseGNUAttributes(ParamInfo); // Inform sema that we are starting a block. Actions.ActOnBlockArguments(ParamInfo, getCurScope()); @@ -1704,20 +1913,18 @@ ExprResult Parser::ParseBlockLiteralExpression() { ParseBlockId(); } else { // Otherwise, pretend we saw (void). - ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, + ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(), + true, false, SourceLocation(), 0, 0, 0, + true, SourceLocation(), false, SourceLocation(), false, 0, 0, 0, CaretLoc, CaretLoc, ParamInfo), CaretLoc); - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseGNUAttributes(&Loc); - ParamInfo.AddAttributes(AttrList, Loc); - } + MaybeParseGNUAttributes(ParamInfo); // Inform sema that we are starting a block. Actions.ActOnBlockArguments(ParamInfo, getCurScope()); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 5041a21..e73578f 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -13,6 +13,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" +#include "RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "llvm/Support/ErrorHandling.h" @@ -500,9 +501,9 @@ ExprResult Parser::ParseCXXTypeid() { TypeResult Ty = ParseTypeName(); // Match the ')'. - MatchRHSPunctuation(tok::r_paren, LParenLoc); + RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - if (Ty.isInvalid()) + if (Ty.isInvalid() || RParenLoc.isInvalid()) return ExprError(); Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true, @@ -524,8 +525,10 @@ ExprResult Parser::ParseCXXTypeid() { if (Result.isInvalid()) SkipUntil(tok::r_paren); else { - MatchRHSPunctuation(tok::r_paren, LParenLoc); - + RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + if (RParenLoc.isInvalid()) + return ExprError(); + Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false, Result.release(), RParenLoc); } @@ -534,6 +537,54 @@ ExprResult Parser::ParseCXXTypeid() { return move(Result); } +/// ParseCXXUuidof - This handles the Microsoft C++ __uuidof expression. +/// +/// '__uuidof' '(' expression ')' +/// '__uuidof' '(' type-id ')' +/// +ExprResult Parser::ParseCXXUuidof() { + assert(Tok.is(tok::kw___uuidof) && "Not '__uuidof'!"); + + SourceLocation OpLoc = ConsumeToken(); + SourceLocation LParenLoc = Tok.getLocation(); + SourceLocation RParenLoc; + + // __uuidof expressions are always parenthesized. + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, + "__uuidof")) + return ExprError(); + + ExprResult Result; + + if (isTypeIdInParens()) { + TypeResult Ty = ParseTypeName(); + + // Match the ')'. + RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + + if (Ty.isInvalid()) + return ExprError(); + + Result = Actions.ActOnCXXUuidof(OpLoc, LParenLoc, /*isType=*/true, + Ty.get().getAsOpaquePtr(), RParenLoc); + } else { + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + Result = ParseExpression(); + + // Match the ')'. + if (Result.isInvalid()) + SkipUntil(tok::r_paren); + else { + RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + + Result = Actions.ActOnCXXUuidof(OpLoc, LParenLoc, /*isType=*/false, + Result.release(), RParenLoc); + } + } + + return move(Result); +} + /// \brief Parse a C++ pseudo-destructor expression after the base, /// . or -> operator, and nested-name-specifier have already been /// parsed. @@ -670,6 +721,8 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); assert(Tok.is(tok::l_paren) && "Expected '('!"); + GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); + SourceLocation LParenLoc = ConsumeParen(); ExprVector Exprs(Actions); @@ -691,9 +744,8 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); - return Actions.ActOnCXXTypeConstructExpr(DS.getSourceRange(), TypeRep, - LParenLoc, move_arg(Exprs), - CommaLocs.data(), RParenLoc); + return Actions.ActOnCXXTypeConstructExpr(TypeRep, LParenLoc, move_arg(Exprs), + RParenLoc); } /// ParseCXXCondition - if/switch/while condition expression. @@ -761,24 +813,22 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, } // If attributes are present, parse them. - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseGNUAttributes(&Loc); - DeclaratorInfo.AddAttributes(AttrList, Loc); - } + MaybeParseGNUAttributes(DeclaratorInfo); // Type-check the declaration itself. DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(getCurScope(), - DeclaratorInfo); + DeclaratorInfo); DeclOut = Dcl.get(); ExprOut = ExprError(); - + // '=' assignment-expression - if (Tok.is(tok::equal)) { - SourceLocation EqualLoc = ConsumeToken(); + if (isTokenEqualOrMistypedEqualEqual( + diag::err_invalid_equalequal_after_declarator)) { + ConsumeToken(); ExprResult AssignExpr(ParseAssignmentExpression()); if (!AssignExpr.isInvalid()) - Actions.AddInitializerToDecl(DeclOut, AssignExpr.take()); + Actions.AddInitializerToDecl(DeclOut, AssignExpr.take(), false, + DS.getTypeSpecType() == DeclSpec::TST_auto); } else { // FIXME: C++0x allows a braced-init-list Diag(Tok, diag::err_expected_equal_after_declarator); @@ -862,9 +912,24 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { // type-name case tok::annot_typename: { - DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, - getTypeAnnotation(Tok)); - break; + if (getTypeAnnotation(Tok)) + DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, + getTypeAnnotation(Tok)); + else + DS.SetTypeSpecError(); + + DS.SetRangeEnd(Tok.getAnnotationEndLoc()); + ConsumeToken(); + + // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' + // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an + // Objective-C interface. If we don't have Objective-C or a '<', this is + // just a normal reference to a typedef name. + if (Tok.is(tok::less) && getLang().ObjC1) + ParseObjCProtocolQualifiers(DS); + + DS.Finish(Diags, PP); + return; } // builtin types @@ -943,7 +1008,7 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) { // Parse one or more of the type specifiers. if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, ParsedTemplateInfo(), /*SuppressDeclarations*/true)) { - Diag(Tok, diag::err_operator_missing_type_specifier); + Diag(Tok, diag::err_expected_type); return true; } @@ -1667,7 +1732,8 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { first = false; SourceLocation RLoc = MatchRHSPunctuation(tok::r_square, LLoc); - D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false, + D.AddTypeInfo(DeclaratorChunk::getArray(0, ParsedAttributes(), + /*static=*/false, /*star=*/false, Size.release(), LLoc, RLoc), RLoc); @@ -1738,7 +1804,7 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { switch(kind) { - default: assert(false && "Not a known unary type trait."); + default: llvm_unreachable("Not a known unary type trait"); case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign; case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy; case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor; @@ -1758,6 +1824,15 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { } } +static BinaryTypeTrait BinaryTypeTraitFromTokKind(tok::TokenKind kind) { + switch(kind) { + default: llvm_unreachable("Not a known binary type trait"); + case tok::kw___is_base_of: return BTT_IsBaseOf; + case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible; + case tok::kw___is_convertible_to: return BTT_IsConvertibleTo; + } +} + /// ParseUnaryTypeTrait - Parse the built-in unary type-trait /// pseudo-functions that allow implementation of the TR1/C++0x type traits /// templates. @@ -1783,7 +1858,44 @@ ExprResult Parser::ParseUnaryTypeTrait() { if (Ty.isInvalid()) return ExprError(); - return Actions.ActOnUnaryTypeTrait(UTT, Loc, LParen, Ty.get(), RParen); + return Actions.ActOnUnaryTypeTrait(UTT, Loc, Ty.get(), RParen); +} + +/// ParseBinaryTypeTrait - Parse the built-in binary type-trait +/// pseudo-functions that allow implementation of the TR1/C++0x type traits +/// templates. +/// +/// primary-expression: +/// [GNU] binary-type-trait '(' type-id ',' type-id ')' +/// +ExprResult Parser::ParseBinaryTypeTrait() { + BinaryTypeTrait BTT = BinaryTypeTraitFromTokKind(Tok.getKind()); + SourceLocation Loc = ConsumeToken(); + + SourceLocation LParen = Tok.getLocation(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen)) + return ExprError(); + + TypeResult LhsTy = ParseTypeName(); + if (LhsTy.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + TypeResult RhsTy = ParseTypeName(); + if (RhsTy.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); + + return Actions.ActOnBinaryTypeTrait(BTT, Loc, LhsTy.get(), RhsTy.get(), RParen); } /// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 4347294..82dda2b 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -13,6 +13,7 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" +#include "RAIIObjectsForParser.h" #include "clang/Sema/Designator.h" #include "clang/Sema/Scope.h" #include "llvm/ADT/SmallString.h" @@ -136,6 +137,8 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { // [foo ... bar] -> array designator // [4][foo bar] -> obsolete GNU designation with objc message send. // + InMessageExpressionRAIIObject InMessage(*this, true); + SourceLocation StartLoc = ConsumeBracket(); ExprResult Idx; @@ -146,7 +149,8 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { if (getLang().ObjC1 && getLang().CPlusPlus) { // Send to 'super'. if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super && - NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope()) { + NextToken().isNot(tok::period) && + getCurScope()->isInObjcMethodScope()) { CheckArrayDesignatorSyntax(*this, StartLoc, Desig); return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, ConsumeToken(), @@ -306,10 +310,12 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { /// [GNU] '{' '}' /// /// initializer-list: -/// designation[opt] initializer -/// initializer-list ',' designation[opt] initializer +/// designation[opt] initializer ...[opt] +/// initializer-list ',' designation[opt] initializer ...[opt] /// ExprResult Parser::ParseBraceInitializer() { + InMessageExpressionRAIIObject InMessage(*this, false); + SourceLocation LBraceLoc = ConsumeBrace(); /// InitExprs - This is the actual list of expressions contained in the @@ -338,6 +344,9 @@ ExprResult Parser::ParseBraceInitializer() { else SubElt = ParseInitializer(); + if (Tok.is(tok::ellipsis)) + SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken()); + // If we couldn't parse the subelement, bail out. if (!SubElt.isInvalid()) { InitExprs.push_back(SubElt.release()); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 6861ce9..f32a322 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -13,6 +13,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" +#include "RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" @@ -39,10 +40,14 @@ Decl *Parser::ParseObjCAtDirectives() { switch (Tok.getObjCKeywordID()) { case tok::objc_class: return ParseObjCAtClassDeclaration(AtLoc); - case tok::objc_interface: - return ParseObjCAtInterfaceDeclaration(AtLoc); - case tok::objc_protocol: - return ParseObjCAtProtocolDeclaration(AtLoc); + case tok::objc_interface: { + ParsedAttributes attrs; + return ParseObjCAtInterfaceDeclaration(AtLoc, attrs); + } + case tok::objc_protocol: { + ParsedAttributes attrs; + return ParseObjCAtProtocolDeclaration(AtLoc, attrs); + } case tok::objc_implementation: return ParseObjCAtImplementationDeclaration(AtLoc); case tok::objc_end: @@ -123,8 +128,8 @@ Decl *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { /// __attribute__((unavailable)) /// __attribute__((objc_exception)) - used by NSException on 64-bit /// -Decl *Parser::ParseObjCAtInterfaceDeclaration( - SourceLocation atLoc, AttributeList *attrList) { +Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, + ParsedAttributes &attrs) { assert(Tok.isObjCAtKeyword(tok::objc_interface) && "ParseObjCAtInterfaceDeclaration(): Expected @interface"); ConsumeToken(); // the "interface" identifier @@ -145,7 +150,9 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration( SourceLocation nameLoc = ConsumeToken(); if (Tok.is(tok::l_paren) && !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category. - SourceLocation lparenLoc = ConsumeParen(); + // TODO(dgregor): Use the return value from the next line to provide better + // recovery. + ConsumeParen(); SourceLocation categoryLoc, rparenLoc; IdentifierInfo *categoryId = 0; if (Tok.is(tok::code_completion)) { @@ -177,7 +184,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration( LAngleLoc, EndProtoLoc)) return 0; - if (attrList) // categories don't support attributes. + if (!attrs.empty()) // categories don't support attributes. Diag(Tok, diag::err_objc_no_attributes_on_category); Decl *CategoryType = @@ -229,7 +236,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration( superClassId, superClassLoc, ProtocolRefs.data(), ProtocolRefs.size(), ProtocolLocs.data(), - EndProtoLoc, attrList); + EndProtoLoc, attrs.getList()); if (Tok.is(tok::l_brace)) ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, atLoc); @@ -364,7 +371,8 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, // FIXME: as the name implies, this rule allows function definitions. // We could pass a flag or check for functions during semantic analysis. - allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(0)); + ParsedAttributes attrs; + allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs)); continue; } @@ -401,7 +409,13 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, // Skip until we see an '@' or '}' or ';'. SkipUntil(tok::r_brace, tok::at); break; - + + case tok::objc_implementation: + case tok::objc_interface: + Diag(Tok, diag::err_objc_missing_end); + ConsumeToken(); + break; + case tok::objc_required: case tok::objc_optional: // This is only valid on protocols. @@ -414,13 +428,12 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, case tok::objc_property: if (!getLang().ObjC2) - Diag(AtLoc, diag::err_objc_propertoes_require_objc2); + Diag(AtLoc, diag::err_objc_properties_require_objc2); ObjCDeclSpec OCDS; // Parse property attribute list, if any. if (Tok.is(tok::l_paren)) - ParseObjCPropertyAttribute(OCDS, interfaceDecl, - allMethods.data(), allMethods.size()); + ParseObjCPropertyAttribute(OCDS, interfaceDecl); ObjCPropertyCallback Callback(*this, interfaceDecl, allProperties, OCDS, AtLoc, MethodImplKind); @@ -469,9 +482,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, /// copy /// nonatomic /// -void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl, - Decl **Methods, - unsigned NumMethods) { +void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) { assert(Tok.getKind() == tok::l_paren); SourceLocation LHSLoc = ConsumeParen(); // consume '(' @@ -502,32 +513,40 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl, DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy); else if (II->isStr("nonatomic")) DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic); + else if (II->isStr("atomic")) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_atomic); else if (II->isStr("getter") || II->isStr("setter")) { + bool IsSetter = II->getNameStart()[0] == 's'; + // getter/setter require extra treatment. - if (ExpectAndConsume(tok::equal, diag::err_objc_expected_equal, "", - tok::r_paren)) + unsigned DiagID = IsSetter ? diag::err_objc_expected_equal_for_setter : + diag::err_objc_expected_equal_for_getter; + + if (ExpectAndConsume(tok::equal, DiagID, "", tok::r_paren)) return; if (Tok.is(tok::code_completion)) { - if (II->getNameStart()[0] == 's') - Actions.CodeCompleteObjCPropertySetter(getCurScope(), ClassDecl, - Methods, NumMethods); + if (IsSetter) + Actions.CodeCompleteObjCPropertySetter(getCurScope(), ClassDecl); else - Actions.CodeCompleteObjCPropertyGetter(getCurScope(), ClassDecl, - Methods, NumMethods); + Actions.CodeCompleteObjCPropertyGetter(getCurScope(), ClassDecl); ConsumeCodeCompletionToken(); } - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); + + SourceLocation SelLoc; + IdentifierInfo *SelIdent = ParseObjCSelectorPiece(SelLoc); + + if (!SelIdent) { + Diag(Tok, diag::err_objc_expected_selector_for_getter_setter) + << IsSetter; SkipUntil(tok::r_paren); return; } - if (II->getNameStart()[0] == 's') { + if (IsSetter) { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter); - DS.setSetterName(Tok.getIdentifierInfo()); - ConsumeToken(); // consume method name + DS.setSetterName(SelIdent); if (ExpectAndConsume(tok::colon, diag::err_expected_colon_after_setter_name, "", @@ -535,8 +554,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl, return; } else { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter); - DS.setGetterName(Tok.getIdentifierInfo()); - ConsumeToken(); // consume method name + DS.setGetterName(SelIdent); } } else { Diag(AttrName, diag::err_objc_expected_property_attr) << II; @@ -705,7 +723,7 @@ bool Parser::isTokIdentifier_in() const { void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, bool IsParameter) { while (1) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCPassingType(getCurScope(), DS); + Actions.CodeCompleteObjCPassingType(getCurScope(), DS, IsParameter); ConsumeCodeCompletionToken(); } @@ -819,9 +837,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ReturnType = ParseObjCTypeName(DSRet, false); // If attributes exist before the method, parse them. - llvm::OwningPtr<AttributeList> MethodAttrs; - if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - MethodAttrs.reset(ParseGNUAttributes()); + ParsedAttributes attrs; + if (getLang().ObjC2) + MaybeParseGNUAttributes(attrs); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, @@ -845,25 +863,25 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, llvm::SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo; if (Tok.isNot(tok::colon)) { // If attributes exist after the method, parse them. - if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - MethodAttrs.reset(addAttributeLists(MethodAttrs.take(), - ParseGNUAttributes())); + if (getLang().ObjC2) + MaybeParseGNUAttributes(attrs); Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); Decl *Result - = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), + = Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, 0, CParamInfo.data(), CParamInfo.size(), - MethodAttrs.get(), - MethodImplKind); + attrs.getList(), MethodImplKind); PD.complete(Result); return Result; } llvm::SmallVector<IdentifierInfo *, 12> KeyIdents; llvm::SmallVector<Sema::ObjCArgInfo, 12> ArgInfos; - + ParseScope PrototypeScope(this, + Scope::FunctionPrototypeScope|Scope::DeclScope); + while (1) { Sema::ObjCArgInfo ArgInfo; @@ -880,8 +898,11 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, // If attributes exist before the argument name, parse them. ArgInfo.ArgAttrs = 0; - if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - ArgInfo.ArgAttrs = ParseGNUAttributes(); + if (getLang().ObjC2) { + ParsedAttributes attrs; + MaybeParseGNUAttributes(attrs); + ArgInfo.ArgAttrs = attrs.getList(); + } // Code completion for the next piece of the selector. if (Tok.is(tok::code_completion)) { @@ -953,30 +974,30 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, } - // FIXME: Add support for optional parmameter list... + // FIXME: Add support for optional parameter list... // If attributes exist after the method, parse them. - if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - MethodAttrs.reset(addAttributeLists(MethodAttrs.take(), - ParseGNUAttributes())); - - if (KeyIdents.size() == 0) + if (getLang().ObjC2) + MaybeParseGNUAttributes(attrs); + + if (KeyIdents.size() == 0) { + // Leave prototype scope. + PrototypeScope.Exit(); return 0; + } + Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(), &KeyIdents[0]); Decl *Result - = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), + = Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, &ArgInfos[0], CParamInfo.data(), CParamInfo.size(), - MethodAttrs.get(), + attrs.getList(), MethodImplKind, isVariadic); - PD.complete(Result); - - // Delete referenced AttributeList objects. - for (llvm::SmallVectorImpl<Sema::ObjCArgInfo>::iterator - I = ArgInfos.begin(), E = ArgInfos.end(); I != E; ++I) - delete I->ArgAttrs; + // Leave prototype scope. + PrototypeScope.Exit(); + PD.complete(Result); return Result; } @@ -1031,6 +1052,24 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl<Decl *> &Protocols, return false; } +/// \brief Parse the Objective-C protocol qualifiers that follow a typename +/// in a decl-specifier-seq, starting at the '<'. +bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) { + assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'"); + assert(getLang().ObjC1 && "Protocol qualifiers only exist in Objective-C"); + SourceLocation LAngleLoc, EndProtoLoc; + llvm::SmallVector<Decl *, 8> ProtocolDecl; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, + LAngleLoc, EndProtoLoc); + DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), + ProtocolLocs.data(), LAngleLoc); + if (EndProtoLoc.isValid()) + DS.SetRangeEnd(EndProtoLoc); + return Result; +} + + /// objc-class-instance-variables: /// '{' objc-instance-variable-decl-list[opt] '}' /// @@ -1164,7 +1203,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, /// identifier-list ;": objc-interface-decl-list may not start with a /// semicolon in the first alternative if objc-protocol-refs are omitted. Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, - AttributeList *attrList) { + ParsedAttributes &attrs) { assert(Tok.isObjCAtKeyword(tok::objc_protocol) && "ParseObjCAtProtocolDeclaration(): Expected @protocol"); ConsumeToken(); // the "protocol" identifier @@ -1186,7 +1225,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, IdentifierLocPair ProtoInfo(protocolName, nameLoc); ConsumeToken(); return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtoInfo, 1, - attrList); + attrs.getList()); } if (Tok.is(tok::comma)) { // list of forward declarations. @@ -1215,7 +1254,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtocolRefs[0], ProtocolRefs.size(), - attrList); + attrs.getList()); } // Last, and definitely not least, parse a protocol declaration. @@ -1233,7 +1272,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, ProtocolRefs.data(), ProtocolRefs.size(), ProtocolLocs.data(), - EndProtoLoc, attrList); + EndProtoLoc, attrs.getList()); ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol); return ProtoType; } @@ -1270,7 +1309,7 @@ Decl *Parser::ParseObjCAtImplementationDeclaration( if (Tok.is(tok::l_paren)) { // we have a category implementation. - SourceLocation lparenLoc = ConsumeParen(); + ConsumeParen(); SourceLocation categoryLoc, rparenLoc; IdentifierInfo *categoryId = 0; @@ -1370,10 +1409,8 @@ Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { } IdentifierInfo *classId = Tok.getIdentifierInfo(); SourceLocation classLoc = ConsumeToken(); // consume class-name; - if (Tok.isNot(tok::semi)) { - Diag(Tok, diag::err_expected_semi_after) << "@compatibility_alias"; - return 0; - } + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, + "@compatibility_alias"); return Actions.ActOnCompatiblityAlias(atLoc, aliasId, aliasLoc, classId, classLoc); } @@ -1392,7 +1429,7 @@ Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { assert(Tok.isObjCAtKeyword(tok::objc_synthesize) && "ParseObjCPropertyDynamic(): Expected '@synthesize'"); - SourceLocation loc = ConsumeToken(); // consume synthesize + ConsumeToken(); // consume synthesize while (true) { if (Tok.is(tok::code_completion)) { @@ -1409,6 +1446,7 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { IdentifierInfo *propertyIvar = 0; IdentifierInfo *propertyId = Tok.getIdentifierInfo(); SourceLocation propertyLoc = ConsumeToken(); // consume property name + SourceLocation propertyIvarLoc; if (Tok.is(tok::equal)) { // property '=' ivar-name ConsumeToken(); // consume '=' @@ -1424,20 +1462,15 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { break; } propertyIvar = Tok.getIdentifierInfo(); - ConsumeToken(); // consume ivar-name + propertyIvarLoc = ConsumeToken(); // consume ivar-name } Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, true, ObjCImpDecl, - propertyId, propertyIvar); + propertyId, propertyIvar, propertyIvarLoc); if (Tok.isNot(tok::comma)) break; ConsumeToken(); // consume ',' } - if (Tok.isNot(tok::semi)) { - Diag(Tok, diag::err_expected_semi_after) << "@synthesize"; - SkipUntil(tok::semi); - } - else - ConsumeToken(); // consume ';' + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@synthesize"); return 0; } @@ -1451,7 +1484,7 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { assert(Tok.isObjCAtKeyword(tok::objc_dynamic) && "ParseObjCPropertyDynamic(): Expected '@dynamic'"); - SourceLocation loc = ConsumeToken(); // consume dynamic + ConsumeToken(); // consume dynamic while (true) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCPropertyDefinition(getCurScope(), ObjCImpDecl); @@ -1467,18 +1500,13 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { IdentifierInfo *propertyId = Tok.getIdentifierInfo(); SourceLocation propertyLoc = ConsumeToken(); // consume property name Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, false, ObjCImpDecl, - propertyId, 0); + propertyId, 0, SourceLocation()); if (Tok.isNot(tok::comma)) break; ConsumeToken(); // consume ',' } - if (Tok.isNot(tok::semi)) { - Diag(Tok, diag::err_expected_semi_after) << "@dynamic"; - SkipUntil(tok::semi); - } - else - ConsumeToken(); // consume ';' + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@dynamic"); return 0; } @@ -1689,6 +1717,10 @@ Decl *Parser::ParseObjCMethodDefinition() { // specified Declarator for the method. Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl); + if (PP.isCodeCompletionEnabled()) + if (trySkippingFunctionBodyForCodeCompletion()) + return Actions.ActOnFinishFunctionBody(MDecl, 0); + StmtResult FnBody(ParseCompoundStatementBody()); // If the function body could not be parsed, make a bogus compoundstmt. @@ -1731,7 +1763,7 @@ StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { } // Otherwise, eat the semicolon. - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); + ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); return Actions.ActOnExprStmt(Actions.MakeFullExpr(Res.take())); } @@ -1785,6 +1817,8 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { /// simple-type-specifier /// typename-specifier bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { + InMessageExpressionRAIIObject InMessage(*this, true); + if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) TryAnnotateTypeOrScopeToken(); @@ -1859,6 +1893,35 @@ bool Parser::isSimpleObjCMessageExpression() { GetLookAheadToken(2).is(tok::identifier); } +bool Parser::isStartOfObjCClassMessageMissingOpenBracket() { + if (!getLang().ObjC1 || !NextToken().is(tok::identifier) || + InMessageExpression) + return false; + + + ParsedType Type; + + if (Tok.is(tok::annot_typename)) + Type = getTypeAnnotation(Tok); + else if (Tok.is(tok::identifier)) + Type = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), + getCurScope()); + else + return false; + + if (!Type.get().isNull() && Type.get()->isObjCObjectOrInterfaceType()) { + const Token &AfterNext = GetLookAheadToken(2); + if (AfterNext.is(tok::colon) || AfterNext.is(tok::r_square)) { + if (Tok.is(tok::identifier)) + TryAnnotateTypeOrScopeToken(); + + return Tok.is(tok::annot_typename); + } + } + + return false; +} + /// objc-message-expr: /// '[' objc-receiver objc-message-args ']' /// @@ -1879,6 +1942,8 @@ ExprResult Parser::ParseObjCMessageExpression() { return ExprError(); } + InMessageExpressionRAIIObject InMessage(*this, true); + if (getLang().CPlusPlus) { // We completely separate the C and C++ cases because C++ requires // more complicated (read: slower) parsing. @@ -1893,7 +1958,7 @@ ExprResult Parser::ParseObjCMessageExpression() { // Parse the receiver, which is either a type or an expression. bool IsExpr; - void *TypeOrExpr; + void *TypeOrExpr = NULL; if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) { SkipUntil(tok::r_square); return ExprError(); @@ -1992,14 +2057,18 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, SourceLocation SuperLoc, ParsedType ReceiverType, ExprArg ReceiverExpr) { + InMessageExpressionRAIIObject InMessage(*this, true); + if (Tok.is(tok::code_completion)) { if (SuperLoc.isValid()) - Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, 0, 0); + Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, 0, 0, + false); else if (ReceiverType) - Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, 0, 0); + Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, 0, 0, + false); else Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, - 0, 0); + 0, 0, false); ConsumeCodeCompletionToken(); } @@ -2028,6 +2097,29 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, ConsumeToken(); // Eat the ':'. /// Parse the expression after ':' + + if (Tok.is(tok::code_completion)) { + if (SuperLoc.isValid()) + Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, + KeyIdents.data(), + KeyIdents.size(), + /*AtArgumentEpression=*/true); + else if (ReceiverType) + Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, + KeyIdents.data(), + KeyIdents.size(), + /*AtArgumentEpression=*/true); + else + Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, + KeyIdents.data(), + KeyIdents.size(), + /*AtArgumentEpression=*/true); + + ConsumeCodeCompletionToken(); + SkipUntil(tok::r_square); + return ExprError(); + } + ExprResult Res(ParseAssignmentExpression()); if (Res.isInvalid()) { // We must manually skip to a ']', otherwise the expression skipper will @@ -2045,16 +2137,21 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, if (SuperLoc.isValid()) Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, KeyIdents.data(), - KeyIdents.size()); + KeyIdents.size(), + /*AtArgumentEpression=*/false); else if (ReceiverType) Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, KeyIdents.data(), - KeyIdents.size()); + KeyIdents.size(), + /*AtArgumentEpression=*/false); else Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, KeyIdents.data(), - KeyIdents.size()); + KeyIdents.size(), + /*AtArgumentEpression=*/false); ConsumeCodeCompletionToken(); + SkipUntil(tok::r_square); + return ExprError(); } // Check for another keyword selector. diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index ddba09a..dfd0da0 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -17,11 +17,24 @@ #include "clang/Lex/Preprocessor.h" using namespace clang; +/// \brief Handle the annotation token produced for #pragma unused(...) +/// +/// Each annot_pragma_unused is followed by the argument token so e.g. +/// "#pragma unused(x,y)" becomes: +/// annot_pragma_unused 'x' annot_pragma_unused 'y' +void Parser::HandlePragmaUnused() { + assert(Tok.is(tok::annot_pragma_unused)); + SourceLocation UnusedLoc = ConsumeToken(); + Actions.ActOnPragmaUnused(Tok, getCurScope(), UnusedLoc); + ConsumeToken(); // The argument token. +} // #pragma GCC visibility comes in two variants: // 'push' '(' [visibility] ')' // 'pop' -void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, Token &VisTok) { +void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &VisTok) { SourceLocation VisLoc = VisTok.getLocation(); Token Tok; @@ -74,7 +87,9 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, Token &VisTok) { // pack '(' [integer] ')' // pack '(' 'show' ')' // pack '(' ('push' | 'pop') [',' identifier] [, integer] ')' -void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) { +void PragmaPackHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &PackTok) { SourceLocation PackLoc = PackTok.getLocation(); Token Tok; @@ -222,16 +237,22 @@ static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok, Actions.ActOnPragmaOptionsAlign(Kind, FirstTok.getLocation(), KindLoc); } -void PragmaAlignHandler::HandlePragma(Preprocessor &PP, Token &AlignTok) { +void PragmaAlignHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &AlignTok) { ParseAlignPragma(Actions, PP, AlignTok, /*IsOptions=*/false); } -void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, Token &OptionsTok) { +void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &OptionsTok) { ParseAlignPragma(Actions, PP, OptionsTok, /*IsOptions=*/true); } // #pragma unused(identifier) -void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) { +void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &UnusedTok) { // FIXME: Should we be expanding macros here? My guess is no. SourceLocation UnusedLoc = UnusedTok.getLocation(); @@ -291,14 +312,27 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) { assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'"); assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments"); - // Perform the action to handle the pragma. - Actions.ActOnPragmaUnused(Identifiers.data(), Identifiers.size(), - parser.getCurScope(), UnusedLoc, LParenLoc, RParenLoc); + // For each identifier token, insert into the token stream a + // annot_pragma_unused token followed by the identifier token. + // This allows us to cache a "#pragma unused" that occurs inside an inline + // C++ member function. + + Token *Toks = new Token[2*Identifiers.size()]; + for (unsigned i=0; i != Identifiers.size(); i++) { + Token &pragmaUnusedTok = Toks[2*i], &idTok = Toks[2*i+1]; + pragmaUnusedTok.startToken(); + pragmaUnusedTok.setKind(tok::annot_pragma_unused); + pragmaUnusedTok.setLocation(UnusedLoc); + idTok = Identifiers[i]; + } + PP.EnterTokenStream(Toks, 2*Identifiers.size(), /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true); } // #pragma weak identifier // #pragma weak identifier '=' identifier -void PragmaWeakHandler::HandlePragma(Preprocessor &PP, Token &WeakTok) { +void PragmaWeakHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &WeakTok) { // FIXME: Should we be expanding macros here? My guess is no. SourceLocation WeakLoc = WeakTok.getLocation(); @@ -337,3 +371,64 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, Token &WeakTok) { Actions.ActOnPragmaWeakID(WeakName, WeakLoc, WeakNameLoc); } } + +void +PragmaFPContractHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &Tok) { + tok::OnOffSwitch OOS; + if (PP.LexOnOffSwitch(OOS)) + return; + + Actions.ActOnPragmaFPContract(OOS); +} + +void +PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &Tok) { + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << + "OPENCL"; + return; + } + IdentifierInfo *ename = Tok.getIdentifierInfo(); + SourceLocation NameLoc = Tok.getLocation(); + + PP.Lex(Tok); + if (Tok.isNot(tok::colon)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_colon) << ename; + return; + } + + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable); + return; + } + IdentifierInfo *op = Tok.getIdentifierInfo(); + + unsigned state; + if (op->isStr("enable")) { + state = 1; + } else if (op->isStr("disable")) { + state = 0; + } else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable); + return; + } + + OpenCLOptions &f = Actions.getOpenCLOptions(); + if (ename->isStr("all")) { +#define OPENCLEXT(nm) f.nm = state; +#include "clang/Basic/OpenCLExtensions.def" + } +#define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; } +#include "clang/Basic/OpenCLExtensions.def" + else { + PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename; + return; + } +} + diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h index 0feaa99..bee6af3 100644 --- a/lib/Parse/ParsePragma.h +++ b/lib/Parse/ParsePragma.h @@ -25,7 +25,8 @@ class PragmaAlignHandler : public PragmaHandler { public: explicit PragmaAlignHandler(Sema &A) : PragmaHandler("align"), Actions(A) {} - virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); }; class PragmaGCCVisibilityHandler : public PragmaHandler { @@ -34,7 +35,8 @@ public: explicit PragmaGCCVisibilityHandler(Sema &A) : PragmaHandler("visibility"), Actions(A) {} - virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); }; class PragmaOptionsHandler : public PragmaHandler { @@ -43,7 +45,8 @@ public: explicit PragmaOptionsHandler(Sema &A) : PragmaHandler("options"), Actions(A) {} - virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); }; class PragmaPackHandler : public PragmaHandler { @@ -52,7 +55,8 @@ public: explicit PragmaPackHandler(Sema &A) : PragmaHandler("pack"), Actions(A) {} - virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); }; class PragmaUnusedHandler : public PragmaHandler { @@ -62,7 +66,8 @@ public: PragmaUnusedHandler(Sema &A, Parser& p) : PragmaHandler("unused"), Actions(A), parser(p) {} - virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); }; class PragmaWeakHandler : public PragmaHandler { @@ -71,9 +76,32 @@ public: explicit PragmaWeakHandler(Sema &A) : PragmaHandler("weak"), Actions(A) {} - virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); }; +class PragmaOpenCLExtensionHandler : public PragmaHandler { + Sema &Actions; + Parser &parser; +public: + PragmaOpenCLExtensionHandler(Sema &S, Parser& p) : + PragmaHandler("EXTENSION"), Actions(S), parser(p) {} + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + + +class PragmaFPContractHandler : public PragmaHandler { + Sema &Actions; + Parser &parser; +public: + PragmaFPContractHandler(Sema &S, Parser& p) : + PragmaHandler("FP_CONTRACT"), Actions(S), parser(p) {} + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + + } // end namespace clang #endif diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 6c240e6..2d97583 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -75,16 +75,14 @@ using namespace clang; /// [OBC] '@' 'throw' ';' /// StmtResult -Parser::ParseStatementOrDeclaration(bool OnlyStatement) { +Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { const char *SemiError = 0; StmtResult Res; ParenBraceBracketBalancer BalancerRAIIObj(*this); - CXX0XAttributeList Attr; - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) - Attr = ParseCXX0XAttributes(); - llvm::OwningPtr<AttributeList> AttrList(Attr.AttrList); + ParsedAttributesWithRange attrs; + MaybeParseCXX0XAttributes(attrs); // Cases in this switch statement should fall through if the parser expects // the token to end in a semicolon (in which case SemiError should be set), @@ -101,21 +99,20 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { case tok::code_completion: Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement); ConsumeCodeCompletionToken(); - return ParseStatementOrDeclaration(OnlyStatement); + return ParseStatementOrDeclaration(Stmts, OnlyStatement); case tok::identifier: if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement - return ParseLabeledStatement(AttrList.take()); + return ParseLabeledStatement(attrs); } // PASS THROUGH. default: { if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - AttrList.take(); //Passing 'Attr' to ParseDeclaration transfers ownership. - DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd, - Attr); + DeclGroupPtrTy Decl = ParseDeclaration(Stmts, Declarator::BlockContext, + DeclEnd, attrs); return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd); } @@ -137,64 +134,65 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { return StmtError(); } // Otherwise, eat the semicolon. - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); + ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get())); } case tok::kw_case: // C99 6.8.1: labeled-statement - return ParseCaseStatement(AttrList.take()); + return ParseCaseStatement(attrs); case tok::kw_default: // C99 6.8.1: labeled-statement - return ParseDefaultStatement(AttrList.take()); + return ParseDefaultStatement(attrs); case tok::l_brace: // C99 6.8.2: compound-statement - return ParseCompoundStatement(AttrList.take()); - case tok::semi: // C99 6.8.3p3: expression[opt] ';' - return Actions.ActOnNullStmt(ConsumeToken()); + return ParseCompoundStatement(attrs); + case tok::semi: { // C99 6.8.3p3: expression[opt] ';' + bool LeadingEmptyMacro = Tok.hasLeadingEmptyMacro(); + return Actions.ActOnNullStmt(ConsumeToken(), LeadingEmptyMacro); + } case tok::kw_if: // C99 6.8.4.1: if-statement - return ParseIfStatement(AttrList.take()); + return ParseIfStatement(attrs); case tok::kw_switch: // C99 6.8.4.2: switch-statement - return ParseSwitchStatement(AttrList.take()); + return ParseSwitchStatement(attrs); case tok::kw_while: // C99 6.8.5.1: while-statement - return ParseWhileStatement(AttrList.take()); + return ParseWhileStatement(attrs); case tok::kw_do: // C99 6.8.5.2: do-statement - Res = ParseDoStatement(AttrList.take()); + Res = ParseDoStatement(attrs); SemiError = "do/while"; break; case tok::kw_for: // C99 6.8.5.3: for-statement - return ParseForStatement(AttrList.take()); + return ParseForStatement(attrs); case tok::kw_goto: // C99 6.8.6.1: goto-statement - Res = ParseGotoStatement(AttrList.take()); + Res = ParseGotoStatement(attrs); SemiError = "goto"; break; case tok::kw_continue: // C99 6.8.6.2: continue-statement - Res = ParseContinueStatement(AttrList.take()); + Res = ParseContinueStatement(attrs); SemiError = "continue"; break; case tok::kw_break: // C99 6.8.6.3: break-statement - Res = ParseBreakStatement(AttrList.take()); + Res = ParseBreakStatement(attrs); SemiError = "break"; break; case tok::kw_return: // C99 6.8.6.4: return-statement - Res = ParseReturnStatement(AttrList.take()); + Res = ParseReturnStatement(attrs); SemiError = "return"; break; case tok::kw_asm: { - if (Attr.HasAttr) - Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) - << Attr.Range; + ProhibitAttributes(attrs); bool msAsm = false; Res = ParseAsmStatement(msAsm); + Res = Actions.ActOnFinishFullStmt(Res.get()); if (msAsm) return move(Res); SemiError = "asm"; break; } case tok::kw_try: // C++ 15: try-block - return ParseCXXTryBlock(AttrList.take()); + return ParseCXXTryBlock(attrs); } // If we reached this code, the statement must end in a semicolon. @@ -218,11 +216,10 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { /// identifier ':' statement /// [GNU] identifier ':' attributes[opt] statement /// -StmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { +StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) { assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && "Not an identifier!"); - llvm::OwningPtr<AttributeList> AttrList(Attr); Token IdentTok = Tok; // Save the whole token. ConsumeToken(); // eat the identifier. @@ -232,19 +229,21 @@ StmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { SourceLocation ColonLoc = ConsumeToken(); // Read label attributes, if present. - if (Tok.is(tok::kw___attribute)) - AttrList.reset(addAttributeLists(AttrList.take(), ParseGNUAttributes())); + MaybeParseGNUAttributes(attrs); StmtResult SubStmt(ParseStatement()); // Broken substmt shouldn't prevent the label from being added to the AST. if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(ColonLoc); - - // FIXME: use attributes? - return Actions.ActOnLabelStmt(IdentTok.getLocation(), - IdentTok.getIdentifierInfo(), - ColonLoc, SubStmt.get()); + + LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(), + IdentTok.getLocation()); + if (AttributeList *Attrs = attrs.getList()) + Actions.ProcessDeclAttributeList(Actions.CurScope, LD, Attrs); + + return Actions.ActOnLabelStmt(IdentTok.getLocation(), LD, ColonLoc, + SubStmt.get()); } /// ParseCaseStatement @@ -252,10 +251,9 @@ StmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// -StmtResult Parser::ParseCaseStatement(AttributeList *Attr) { +StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) { assert(Tok.is(tok::kw_case) && "Not a case stmt!"); // FIXME: Use attributes? - delete Attr; // It is very very common for code to contain many case statements recursively // nested, as in (but usually without indentation): @@ -316,14 +314,22 @@ StmtResult Parser::ParseCaseStatement(AttributeList *Attr) { ColonProtection.restore(); - if (Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_expected_colon_after) << "'case'"; - SkipUntil(tok::colon); - return StmtError(); - } - - SourceLocation ColonLoc = ConsumeToken(); + SourceLocation ColonLoc; + if (Tok.is(tok::colon)) { + ColonLoc = ConsumeToken(); + // Treat "case blah;" as a typo for "case blah:". + } else if (Tok.is(tok::semi)) { + ColonLoc = ConsumeToken(); + Diag(ColonLoc, diag::err_expected_colon_after) << "'case'" + << FixItHint::CreateReplacement(ColonLoc, ":"); + } else { + SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation); + Diag(ExpectedLoc, diag::err_expected_colon_after) << "'case'" + << FixItHint::CreateInsertion(ExpectedLoc, ":"); + ColonLoc = ExpectedLoc; + } + StmtResult Case = Actions.ActOnCaseStmt(CaseLoc, LHS.get(), DotDotDotLoc, RHS.get(), ColonLoc); @@ -379,21 +385,28 @@ StmtResult Parser::ParseCaseStatement(AttributeList *Attr) { /// 'default' ':' statement /// Note that this does not parse the 'statement' at the end. /// -StmtResult Parser::ParseDefaultStatement(AttributeList *Attr) { +StmtResult Parser::ParseDefaultStatement(ParsedAttributes &attrs) { //FIXME: Use attributes? - delete Attr; assert(Tok.is(tok::kw_default) && "Not a default stmt!"); SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. - if (Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_expected_colon_after) << "'default'"; - SkipUntil(tok::colon); - return StmtError(); - } - - SourceLocation ColonLoc = ConsumeToken(); + SourceLocation ColonLoc; + if (Tok.is(tok::colon)) { + ColonLoc = ConsumeToken(); + // Treat "default;" as a typo for "default:". + } else if (Tok.is(tok::semi)) { + ColonLoc = ConsumeToken(); + Diag(ColonLoc, diag::err_expected_colon_after) << "'default'" + << FixItHint::CreateReplacement(ColonLoc, ":"); + } else { + SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation); + Diag(ExpectedLoc, diag::err_expected_colon_after) << "'default'" + << FixItHint::CreateInsertion(ExpectedLoc, ":"); + ColonLoc = ExpectedLoc; + } + // Diagnose the common error "switch (X) {... default: }", which is not valid. if (Tok.is(tok::r_brace)) { Diag(Tok, diag::err_label_end_of_compound_statement); @@ -436,10 +449,9 @@ StmtResult Parser::ParseDefaultStatement(AttributeList *Attr) { /// [OMP] barrier-directive /// [OMP] flush-directive /// -StmtResult Parser::ParseCompoundStatement(AttributeList *Attr, +StmtResult Parser::ParseCompoundStatement(ParsedAttributes &attrs, bool isStmtExpr) { //FIXME: Use attributes? - delete Attr; assert(Tok.is(tok::l_brace) && "Not a compount stmt!"); @@ -460,18 +472,53 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), Tok.getLocation(), "in compound statement ('{}')"); - + InMessageExpressionRAIIObject InMessage(*this, false); + SourceLocation LBraceLoc = ConsumeBrace(); // eat the '{'. - // TODO: "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are - // only allowed at the start of a compound stmt regardless of the language. + StmtVector Stmts(Actions); - typedef StmtVector StmtsTy; - StmtsTy Stmts(Actions); + // "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are + // only allowed at the start of a compound stmt regardless of the language. + while (Tok.is(tok::kw___label__)) { + SourceLocation LabelLoc = ConsumeToken(); + Diag(LabelLoc, diag::ext_gnu_local_label); + + llvm::SmallVector<Decl *, 8> DeclsInGroup; + while (1) { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + break; + } + + IdentifierInfo *II = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, true)); + + if (!Tok.is(tok::comma)) + break; + ConsumeToken(); + } + + DeclSpec DS; + DeclGroupPtrTy Res = Actions.FinalizeDeclaratorGroup(getCurScope(), DS, + DeclsInGroup.data(), DeclsInGroup.size()); + StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation()); + + ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); + if (R.isUsable()) + Stmts.push_back(R.release()); + } + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + if (Tok.is(tok::annot_pragma_unused)) { + HandlePragmaUnused(); + continue; + } + StmtResult R; if (Tok.isNot(tok::kw___extension__)) { - R = ParseStatementOrDeclaration(false); + R = ParseStatementOrDeclaration(Stmts, false); } else { // __extension__ can start declarations and it can also be a unary // operator for expressions. Consume multiple __extension__ markers here @@ -481,9 +528,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { while (Tok.is(tok::kw___extension__)) ConsumeToken(); - CXX0XAttributeList Attr; - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) - Attr = ParseCXX0XAttributes(); + ParsedAttributesWithRange attrs; + MaybeParseCXX0XAttributes(attrs); // If this is the start of a declaration, parse it as such. if (isDeclarationStatement()) { @@ -492,8 +538,9 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { ExtensionRAIIObject O(Diags); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext, DeclEnd, - Attr); + DeclGroupPtrTy Res = ParseDeclaration(Stmts, + Declarator::BlockContext, DeclEnd, + attrs); R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd); } else { // Otherwise this was a unary __extension__ marker. @@ -507,7 +554,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { // FIXME: Use attributes? // Eat the semicolon at the end of stmt and convert the expr into a // statement. - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); + ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); R = Actions.ActOnExprStmt(Actions.MakeFullExpr(Res.get())); } } @@ -543,12 +590,9 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, Decl *&DeclResult, SourceLocation Loc, bool ConvertToBoolean) { - bool ParseError = false; - SourceLocation LParenLoc = ConsumeParen(); if (getLang().CPlusPlus) - ParseError = ParseCXXCondition(ExprResult, DeclResult, Loc, - ConvertToBoolean); + ParseCXXCondition(ExprResult, DeclResult, Loc, ConvertToBoolean); else { ExprResult = ParseExpression(); DeclResult = 0; @@ -583,9 +627,8 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, /// [C++] 'if' '(' condition ')' statement /// [C++] 'if' '(' condition ')' statement 'else' statement /// -StmtResult Parser::ParseIfStatement(AttributeList *Attr) { +StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) { // FIXME: Use attributes? - delete Attr; assert(Tok.is(tok::kw_if) && "Not an if stmt!"); SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. @@ -706,9 +749,8 @@ StmtResult Parser::ParseIfStatement(AttributeList *Attr) { /// switch-statement: /// 'switch' '(' expression ')' statement /// [C++] 'switch' '(' condition ')' statement -StmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { +StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) { // FIXME: Use attributes? - delete Attr; assert(Tok.is(tok::kw_switch) && "Not a switch stmt!"); SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'. @@ -792,9 +834,8 @@ StmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { /// while-statement: [C99 6.8.5.1] /// 'while' '(' expression ')' statement /// [C++] 'while' '(' condition ')' statement -StmtResult Parser::ParseWhileStatement(AttributeList *Attr) { +StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs) { // FIXME: Use attributes? - delete Attr; assert(Tok.is(tok::kw_while) && "Not a while stmt!"); SourceLocation WhileLoc = Tok.getLocation(); @@ -867,9 +908,8 @@ StmtResult Parser::ParseWhileStatement(AttributeList *Attr) { /// do-statement: [C99 6.8.5.2] /// 'do' statement 'while' '(' expression ')' ';' /// Note: this lets the caller parse the end ';'. -StmtResult Parser::ParseDoStatement(AttributeList *Attr) { +StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) { // FIXME: Use attributes? - delete Attr; assert(Tok.is(tok::kw_do) && "Not a do stmt!"); SourceLocation DoLoc = ConsumeToken(); // eat the 'do'. @@ -944,9 +984,8 @@ StmtResult Parser::ParseDoStatement(AttributeList *Attr) { /// [C++] expression-statement /// [C++] simple-declaration /// -StmtResult Parser::ParseForStatement(AttributeList *Attr) { +StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { // FIXME: Use attributes? - delete Attr; assert(Tok.is(tok::kw_for) && "Not a for stmt!"); SourceLocation ForLoc = ConsumeToken(); // eat the 'for'. @@ -1010,13 +1049,13 @@ StmtResult Parser::ParseForStatement(AttributeList *Attr) { if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode? Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); - AttributeList *AttrList = 0; - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) - AttrList = ParseCXX0XAttributes().AttrList; + ParsedAttributesWithRange attrs; + MaybeParseCXX0XAttributes(attrs); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd, - AttrList, false); + StmtVector Stmts(Actions); + DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext, + DeclEnd, attrs, false); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); if (Tok.is(tok::semi)) { // for (int x = 4; @@ -1033,18 +1072,23 @@ StmtResult Parser::ParseForStatement(AttributeList *Attr) { Collection = ParseExpression(); } else { Diag(Tok, diag::err_expected_semi_for); - SkipUntil(tok::semi); } } else { Value = ParseExpression(); + ForEach = isTokIdentifier_in(); + // Turn the expression into a stmt. - if (!Value.isInvalid()) - FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value.get())); + if (!Value.isInvalid()) { + if (ForEach) + FirstPart = Actions.ActOnForEachLValueExpr(Value.get()); + else + FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value.get())); + } if (Tok.is(tok::semi)) { ConsumeToken(); - } else if ((ForEach = isTokIdentifier_in())) { + } else if (ForEach) { ConsumeToken(); // consume 'in' if (Tok.is(tok::code_completion)) { @@ -1053,8 +1097,14 @@ StmtResult Parser::ParseForStatement(AttributeList *Attr) { } Collection = ParseExpression(); } else { - if (!Value.isInvalid()) Diag(Tok, diag::err_expected_semi_for); - SkipUntil(tok::semi); + if (!Value.isInvalid()) { + Diag(Tok, diag::err_expected_semi_for); + } else { + // Skip until semicolon or rparen, don't consume it. + SkipUntil(tok::r_paren, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + } } } if (!ForEach) { @@ -1062,6 +1112,8 @@ StmtResult Parser::ParseForStatement(AttributeList *Attr) { // Parse the second part of the for specifier. if (Tok.is(tok::semi)) { // for (...;; // no second part. + } else if (Tok.is(tok::r_paren)) { + // missing both semicolons. } else { ExprResult Second; if (getLang().CPlusPlus) @@ -1076,12 +1128,16 @@ StmtResult Parser::ParseForStatement(AttributeList *Attr) { SecondPart = Actions.MakeFullExpr(Second.get()); } + if (Tok.isNot(tok::semi)) { + if (!SecondPartIsInvalid || SecondVar) + Diag(Tok, diag::err_expected_semi_for); + else + // Skip until semicolon or rparen, don't consume it. + SkipUntil(tok::r_paren, true, true); + } + if (Tok.is(tok::semi)) { ConsumeToken(); - } else { - if (!SecondPartIsInvalid || SecondVar) - Diag(Tok, diag::err_expected_semi_for); - SkipUntil(tok::semi); } // Parse the third part of the for specifier. @@ -1137,17 +1193,17 @@ StmtResult Parser::ParseForStatement(AttributeList *Attr) { /// /// Note: this lets the caller parse the end ';'. /// -StmtResult Parser::ParseGotoStatement(AttributeList *Attr) { +StmtResult Parser::ParseGotoStatement(ParsedAttributes &attrs) { // FIXME: Use attributes? - delete Attr; assert(Tok.is(tok::kw_goto) && "Not a goto stmt!"); SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'. StmtResult Res; if (Tok.is(tok::identifier)) { - Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(), - Tok.getIdentifierInfo()); + LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(), + Tok.getLocation()); + Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(), LD); ConsumeToken(); } else if (Tok.is(tok::star)) { // GNU indirect goto extension. @@ -1173,9 +1229,8 @@ StmtResult Parser::ParseGotoStatement(AttributeList *Attr) { /// /// Note: this lets the caller parse the end ';'. /// -StmtResult Parser::ParseContinueStatement(AttributeList *Attr) { +StmtResult Parser::ParseContinueStatement(ParsedAttributes &attrs) { // FIXME: Use attributes? - delete Attr; SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'. return Actions.ActOnContinueStmt(ContinueLoc, getCurScope()); @@ -1187,9 +1242,8 @@ StmtResult Parser::ParseContinueStatement(AttributeList *Attr) { /// /// Note: this lets the caller parse the end ';'. /// -StmtResult Parser::ParseBreakStatement(AttributeList *Attr) { +StmtResult Parser::ParseBreakStatement(ParsedAttributes &attrs) { // FIXME: Use attributes? - delete Attr; SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. return Actions.ActOnBreakStmt(BreakLoc, getCurScope()); @@ -1198,9 +1252,8 @@ StmtResult Parser::ParseBreakStatement(AttributeList *Attr) { /// ParseReturnStatement /// jump-statement: /// 'return' expression[opt] ';' -StmtResult Parser::ParseReturnStatement(AttributeList *Attr) { +StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) { // FIXME: Use attributes? - delete Attr; assert(Tok.is(tok::kw_return) && "Not a return stmt!"); SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'. @@ -1225,10 +1278,12 @@ StmtResult Parser::ParseReturnStatement(AttributeList *Attr) { /// FuzzyParseMicrosoftAsmStatement. When -fms-extensions is enabled, this /// routine is called to skip/ignore tokens that comprise the MS asm statement. -StmtResult Parser::FuzzyParseMicrosoftAsmStatement() { +StmtResult Parser::FuzzyParseMicrosoftAsmStatement(SourceLocation AsmLoc) { + SourceLocation EndLoc; if (Tok.is(tok::l_brace)) { unsigned short savedBraceCount = BraceCount; do { + EndLoc = Tok.getLocation(); ConsumeAnyToken(); } while (BraceCount > savedBraceCount && Tok.isNot(tok::eof)); } else { @@ -1238,6 +1293,7 @@ StmtResult Parser::FuzzyParseMicrosoftAsmStatement() { SourceLocation TokLoc = Tok.getLocation(); unsigned LineNo = SrcMgr.getInstantiationLineNumber(TokLoc); do { + EndLoc = TokLoc; ConsumeAnyToken(); TokLoc = Tok.getLocation(); } while ((SrcMgr.getInstantiationLineNumber(TokLoc) == LineNo) && @@ -1253,10 +1309,10 @@ StmtResult Parser::FuzzyParseMicrosoftAsmStatement() { ExprVector Constraints(Actions); ExprVector Exprs(Actions); ExprVector Clobbers(Actions); - return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, 0, + return Actions.ActOnAsmStmt(AsmLoc, true, true, 0, 0, 0, move_arg(Constraints), move_arg(Exprs), AsmString.take(), move_arg(Clobbers), - Tok.getLocation(), true); + EndLoc, true); } /// ParseAsmStatement - Parse a GNU extended asm statement. @@ -1292,7 +1348,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { if (getLang().Microsoft && Tok.isNot(tok::l_paren) && !isTypeQualifier()) { msAsm = true; - return FuzzyParseMicrosoftAsmStatement(); + return FuzzyParseMicrosoftAsmStatement(AsmLoc); } DeclSpec DS; SourceLocation Loc = Tok.getLocation(); @@ -1470,6 +1526,10 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl) { assert(Tok.is(tok::l_brace)); SourceLocation LBraceLoc = Tok.getLocation(); + if (PP.isCodeCompletionEnabled()) + if (trySkippingFunctionBodyForCodeCompletion()) + return Actions.ActOnFinishFunctionBody(Decl, 0); + PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc, "parsing function body"); @@ -1502,6 +1562,10 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { if (Tok.is(tok::colon)) ParseConstructorInitializer(Decl); + if (PP.isCodeCompletionEnabled()) + if (trySkippingFunctionBodyForCodeCompletion()) + return Actions.ActOnFinishFunctionBody(Decl, 0); + SourceLocation LBraceLoc = Tok.getLocation(); StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc)); // If we failed to parse the try-catch, we just give the function an empty @@ -1513,14 +1577,32 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); } +bool Parser::trySkippingFunctionBodyForCodeCompletion() { + assert(Tok.is(tok::l_brace)); + assert(PP.isCodeCompletionEnabled() && + "Should only be called when in code-completion mode"); + + // We're in code-completion mode. Skip parsing for all function bodies unless + // the body contains the code-completion point. + TentativeParsingAction PA(*this); + ConsumeBrace(); + if (SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false, + /*StopAtCodeCompletion=*/true)) { + PA.Commit(); + return true; + } + + PA.Revert(); + return false; +} + /// ParseCXXTryBlock - Parse a C++ try-block. /// /// try-block: /// 'try' compound-statement handler-seq /// -StmtResult Parser::ParseCXXTryBlock(AttributeList* Attr) { +StmtResult Parser::ParseCXXTryBlock(ParsedAttributes &attrs) { // FIXME: Add attributes? - delete Attr; assert(Tok.is(tok::kw_try) && "Expected 'try'"); @@ -1544,16 +1626,15 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? - StmtResult TryBlock(ParseCompoundStatement(0)); + ParsedAttributesWithRange attrs; + StmtResult TryBlock(ParseCompoundStatement(attrs)); if (TryBlock.isInvalid()) return move(TryBlock); StmtVector Handlers(Actions); - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { - CXX0XAttributeList Attr = ParseCXX0XAttributes(); - Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) - << Attr.Range; - } + MaybeParseCXX0XAttributes(attrs); + ProhibitAttributes(attrs); + if (Tok.isNot(tok::kw_catch)) return StmtError(Diag(Tok, diag::err_expected_catch)); while (Tok.is(tok::kw_catch)) { @@ -1614,7 +1695,8 @@ StmtResult Parser::ParseCXXCatchBlock() { return StmtError(Diag(Tok, diag::err_expected_lbrace)); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? - StmtResult Block(ParseCompoundStatement(0)); + ParsedAttributes attrs; + StmtResult Block(ParseCompoundStatement(attrs)); if (Block.isInvalid()) return move(Block); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index dfb4785..8387c88 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -196,12 +196,18 @@ Parser::ParseSingleDeclarationAfterTemplate( return 0; } + ParsedAttributesWithRange prefixAttrs; + MaybeParseCXX0XAttributes(prefixAttrs); + + if (Tok.is(tok::kw_using)) + return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, + prefixAttrs); + // Parse the declaration specifiers, stealing the accumulated // diagnostics from the template parameters. ParsingDeclSpec DS(DiagsFromTParams); - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) - DS.AddAttributes(ParseCXX0XAttributes().AttrList); + DS.takeAttributesFrom(prefixAttrs); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, getDeclSpecContextFromDeclaratorContext(Context)); @@ -240,7 +246,7 @@ Parser::ParseSingleDeclarationAfterTemplate( // Eat the semi colon after the declaration. ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); - DS.complete(ThisDecl); + DeclaratorInfo.complete(ThisDecl); return ThisDecl; } @@ -337,7 +343,7 @@ Parser::ParseTemplateParameterList(unsigned Depth, // subsumed by whatever goes on in ParseTemplateParameter. // TODO: This could match >>, and it would be nice to avoid those // silly errors with template <vec<T>>. - // Diag(Tok.getLocation(), diag::err_expected_comma_greater); + Diag(Tok.getLocation(), diag::err_expected_comma_greater); SkipUntil(tok::greater, true, true); return false; } @@ -415,12 +421,14 @@ bool Parser::isStartOfTemplateTypeParameter() { /// parameter-declaration /// /// type-parameter: (see below) -/// 'class' ...[opt][C++0x] identifier[opt] +/// 'class' ...[opt] identifier[opt] /// 'class' identifier[opt] '=' type-id -/// 'typename' ...[opt][C++0x] identifier[opt] +/// 'typename' ...[opt] identifier[opt] /// 'typename' identifier[opt] '=' type-id -/// 'template' ...[opt][C++0x] '<' template-parameter-list '>' 'class' identifier[opt] -/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression +/// 'template' '<' template-parameter-list '>' +/// 'class' ...[opt] identifier[opt] +/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] +/// = id-expression Decl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { if (isStartOfTemplateTypeParameter()) return ParseTypeParameter(Depth, Position); @@ -459,7 +467,7 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { EllipsisLoc = ConsumeToken(); if (!getLang().CPlusPlus0x) - Diag(EllipsisLoc, diag::err_variadic_templates); + Diag(EllipsisLoc, diag::ext_variadic_templates); } // Grab the template parameter name (if given) @@ -496,8 +504,10 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { /// template parameters. /// /// type-parameter: [C++ temp.param] -/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] -/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression +/// 'template' '<' template-parameter-list '>' 'class' +/// ...[opt] identifier[opt] +/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] +/// = id-expression Decl * Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { assert(Tok.is(tok::kw_template) && "Expected 'template' keyword"); @@ -521,8 +531,17 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { << PP.getSpelling(Tok); return 0; } - SourceLocation ClassLoc = ConsumeToken(); + ConsumeToken(); + // Parse the ellipsis, if given. + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) { + EllipsisLoc = ConsumeToken(); + + if (!getLang().CPlusPlus0x) + Diag(EllipsisLoc, diag::ext_variadic_templates); + } + // Get the identifier, if given. SourceLocation NameLoc; IdentifierInfo* ParamName = 0; @@ -540,7 +559,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { TemplateParamsTy *ParamList = Actions.ActOnTemplateParameterList(Depth, SourceLocation(), TemplateLoc, LAngleLoc, - &TemplateParams[0], + TemplateParams.data(), TemplateParams.size(), RAngleLoc); @@ -563,9 +582,9 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { } return Actions.ActOnTemplateTemplateParameter(getCurScope(), TemplateLoc, - ParamList, ParamName, - NameLoc, Depth, Position, - EqualLoc, DefaultArg); + ParamList, EllipsisLoc, + ParamName, NameLoc, Depth, + Position, EqualLoc, DefaultArg); } /// ParseNonTypeTemplateParameter - Handle the parsing of non-type @@ -576,8 +595,6 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { /// parameter-declaration Decl * Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { - SourceLocation StartLoc = Tok.getLocation(); - // Parse the declaration-specifiers (i.e., the type). // FIXME: The type should probably be restricted in some way... Not all // declarators (parts of declarators?) are accepted for parameters. @@ -658,7 +675,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, bool Invalid = false; { GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); - if (Tok.isNot(tok::greater)) + if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater)) Invalid = ParseTemplateArgumentList(TemplateArgs); if (Invalid) { @@ -888,7 +905,7 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { // We parse an id-expression that refers to a class template or template // alias. The grammar we parse is: // - // nested-name-specifier[opt] template[opt] identifier + // nested-name-specifier[opt] template[opt] identifier ...[opt] // // followed by a token that terminates a template argument, such as ',', // '>', or (in some cases) '>>'. @@ -896,6 +913,8 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + ParsedTemplateArgument Result; + SourceLocation EllipsisLoc; if (SS.isSet() && Tok.is(tok::kw_template)) { // Parse the optional 'template' keyword following the // nested-name-specifier. @@ -907,6 +926,10 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); // the identifier + // Parse the ellipsis. + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + // If the next token signals the end of a template argument, // then we have a dependent template name that could be a template // template argument. @@ -917,7 +940,7 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { /*ObjectType=*/ ParsedType(), /*EnteringContext=*/false, Template)) - return ParsedTemplateArgument(SS, Template, Name.StartLocation); + Result = ParsedTemplateArgument(SS, Template, Name.StartLocation); } } else if (Tok.is(tok::identifier)) { // We may have a (non-dependent) template name. @@ -926,6 +949,10 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); // the identifier + // Parse the ellipsis. + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + if (isEndOfTemplateArgument(Tok)) { bool MemberOfUnknownSpecialization; TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, @@ -938,13 +965,16 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) { // We have an id-expression that refers to a class template or // (C++0x) template alias. - return ParsedTemplateArgument(SS, Template, Name.StartLocation); + Result = ParsedTemplateArgument(SS, Template, Name.StartLocation); } } } - // We don't have a template template argument. - return ParsedTemplateArgument(); + // If this is a pack expansion, build it as such. + if (EllipsisLoc.isValid() && !Result.isInvalid()) + Result = Actions.ActOnPackExpansion(Result, EllipsisLoc); + + return Result; } /// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]). @@ -962,7 +992,8 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { // Therefore, we initially try to parse a type-id. if (isCXXTypeId(TypeIdAsTemplateArgument)) { SourceLocation Loc = Tok.getLocation(); - TypeResult TypeArg = ParseTypeName(); + TypeResult TypeArg = ParseTypeName(/*Range=*/0, + Declarator::TemplateTypeArgContext); if (TypeArg.isInvalid()) return ParsedTemplateArgument(); @@ -1037,6 +1068,11 @@ bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { while (true) { ParsedTemplateArgument Arg = ParseTemplateArgument(); + if (Tok.is(tok::ellipsis)) { + SourceLocation EllipsisLoc = ConsumeToken(); + Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc); + } + if (Arg.isInvalid()) { SkipUntil(tok::comma, tok::greater, true, true); return true; @@ -1075,3 +1111,14 @@ Decl *Parser::ParseExplicitInstantiation(SourceLocation ExternLoc, ParsingTemplateParams, DeclEnd, AS_none); } + +SourceRange Parser::ParsedTemplateInfo::getSourceRange() const { + if (TemplateParams) + return getTemplateParamsRange(TemplateParams->data(), + TemplateParams->size()); + + SourceRange R(TemplateLoc); + if (ExternLoc.isValid()) + R.setBegin(ExternLoc); + return R; +} diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index c22d99f..a603c37 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -111,10 +111,7 @@ bool Parser::isCXXSimpleDeclaration() { // We need tentative parsing... TentativeParsingAction PA(*this); - TPR = TryParseSimpleDeclaration(); - SourceLocation TentativeParseLoc = Tok.getLocation(); - PA.Revert(); // In case of an error, let the declaration parsing code handle it. @@ -139,9 +136,13 @@ Parser::TPResult Parser::TryParseSimpleDeclaration() { if (Tok.is(tok::kw_typeof)) TryParseTypeofSpecifier(); - else + else { ConsumeToken(); - + + if (getLang().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } + assert(Tok.is(tok::l_paren) && "Expected '('"); TPResult TPR = TryParseInitDeclaratorList(); @@ -242,8 +243,12 @@ bool Parser::isCXXConditionDeclaration() { // type-specifier-seq if (Tok.is(tok::kw_typeof)) TryParseTypeofSpecifier(); - else + else { ConsumeToken(); + + if (getLang().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } assert(Tok.is(tok::l_paren) && "Expected '('"); // declarator @@ -313,8 +318,13 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { // type-specifier-seq if (Tok.is(tok::kw_typeof)) TryParseTypeofSpecifier(); - else + else { ConsumeToken(); + + if (getLang().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } + assert(Tok.is(tok::l_paren) && "Expected '('"); // declarator @@ -448,6 +458,7 @@ bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing, /// abstract-declarator: /// ptr-operator abstract-declarator[opt] /// direct-abstract-declarator +/// ... /// /// direct-abstract-declarator: /// direct-abstract-declarator[opt] @@ -470,7 +481,7 @@ bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing, /// 'volatile' /// /// declarator-id: -/// id-expression +/// '...'[opt] id-expression /// /// id-expression: /// unqualified-id @@ -495,6 +506,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, return TPResult::Error(); if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) || + Tok.is(tok::ampamp) || (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { // ptr-operator ConsumeToken(); @@ -509,7 +521,9 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // direct-declarator: // direct-abstract-declarator: - + if (Tok.is(tok::ellipsis)) + ConsumeToken(); + if ((Tok.is(tok::identifier) || (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) && mayHaveIdentifier) { @@ -532,7 +546,12 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // '(' declarator ')' // '(' attributes declarator ')' // '(' abstract-declarator ')' - if (Tok.is(tok::kw___attribute)) + if (Tok.is(tok::kw___attribute) || + Tok.is(tok::kw___declspec) || + Tok.is(tok::kw___cdecl) || + Tok.is(tok::kw___stdcall) || + Tok.is(tok::kw___fastcall) || + Tok.is(tok::kw___thiscall)) return TPResult::True(); // attributes indicate declaration TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier); if (TPR != TPResult::Ambiguous()) @@ -548,6 +567,10 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, while (1) { TPResult TPR(TPResult::Ambiguous()); + // abstract-declarator: ... + if (Tok.is(tok::ellipsis)) + ConsumeToken(); + if (Tok.is(tok::l_paren)) { // Check whether we have a function declarator or a possible ctor-style // initializer that follows the declarator. Note that ctor-style @@ -575,6 +598,118 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, return TPResult::Ambiguous(); } +Parser::TPResult +Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { + switch (Kind) { + // Obviously starts an expression. + case tok::numeric_constant: + case tok::char_constant: + case tok::string_literal: + case tok::wide_string_literal: + case tok::l_square: + case tok::l_paren: + case tok::amp: + case tok::ampamp: + case tok::star: + case tok::plus: + case tok::plusplus: + case tok::minus: + case tok::minusminus: + case tok::tilde: + case tok::exclaim: + case tok::kw_sizeof: + case tok::kw___func__: + case tok::kw_const_cast: + case tok::kw_delete: + case tok::kw_dynamic_cast: + case tok::kw_false: + case tok::kw_new: + case tok::kw_operator: + case tok::kw_reinterpret_cast: + case tok::kw_static_cast: + case tok::kw_this: + case tok::kw_throw: + case tok::kw_true: + case tok::kw_typeid: + case tok::kw_alignof: + case tok::kw_noexcept: + case tok::kw_nullptr: + case tok::kw___null: + case tok::kw___alignof: + case tok::kw___builtin_choose_expr: + case tok::kw___builtin_offsetof: + case tok::kw___builtin_types_compatible_p: + case tok::kw___builtin_va_arg: + case tok::kw___imag: + case tok::kw___real: + case tok::kw___FUNCTION__: + case tok::kw___PRETTY_FUNCTION__: + case tok::kw___has_nothrow_assign: + case tok::kw___has_nothrow_copy: + case tok::kw___has_nothrow_constructor: + case tok::kw___has_trivial_assign: + case tok::kw___has_trivial_copy: + case tok::kw___has_trivial_constructor: + case tok::kw___has_trivial_destructor: + case tok::kw___has_virtual_destructor: + case tok::kw___is_abstract: + case tok::kw___is_base_of: + case tok::kw___is_class: + case tok::kw___is_convertible_to: + case tok::kw___is_empty: + case tok::kw___is_enum: + case tok::kw___is_pod: + case tok::kw___is_polymorphic: + case tok::kw___is_union: + case tok::kw___is_literal: + case tok::kw___uuidof: + return TPResult::True(); + + // Obviously starts a type-specifier-seq: + case tok::kw_char: + case tok::kw_const: + case tok::kw_double: + case tok::kw_enum: + case tok::kw_float: + case tok::kw_int: + case tok::kw_long: + case tok::kw_restrict: + case tok::kw_short: + case tok::kw_signed: + case tok::kw_struct: + case tok::kw_union: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_volatile: + case tok::kw__Bool: + case tok::kw__Complex: + case tok::kw_class: + case tok::kw_typename: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_decltype: + case tok::kw_thread_local: + case tok::kw__Decimal32: + case tok::kw__Decimal64: + case tok::kw__Decimal128: + case tok::kw___thread: + case tok::kw_typeof: + case tok::kw___cdecl: + case tok::kw___stdcall: + case tok::kw___fastcall: + case tok::kw___thiscall: + case tok::kw___vector: + case tok::kw___pixel: + return TPResult::False(); + + default: + break; + } + + return TPResult::Ambiguous(); +} + /// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration /// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could /// be either a decl-specifier or a function-style cast, and TPResult::Error() @@ -803,6 +938,28 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { // simple-type-specifier: + case tok::annot_typename: + case_typename: + // In Objective-C, we might have a protocol-qualified type. + if (getLang().ObjC1 && NextToken().is(tok::less)) { + // Tentatively parse the + TentativeParsingAction PA(*this); + ConsumeToken(); // The type token + + TPResult TPR = TryParseProtocolQualifiers(); + bool isFollowedByParen = Tok.is(tok::l_paren); + + PA.Revert(); + + if (TPR == TPResult::Error()) + return TPResult::Error(); + + if (isFollowedByParen) + return TPResult::Ambiguous(); + + return TPResult::True(); + } + case tok::kw_char: case tok::kw_wchar_t: case tok::kw_char16_t: @@ -816,11 +973,12 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw_float: case tok::kw_double: case tok::kw_void: - case tok::annot_typename: - case_typename: if (NextToken().is(tok::l_paren)) return TPResult::Ambiguous(); + if (isStartOfObjCClassMessageMissingOpenBracket()) + return TPResult::False(); + return TPResult::True(); // GNU typeof support. @@ -870,6 +1028,30 @@ Parser::TPResult Parser::TryParseTypeofSpecifier() { return TPResult::Ambiguous(); } +/// [ObjC] protocol-qualifiers: +//// '<' identifier-list '>' +Parser::TPResult Parser::TryParseProtocolQualifiers() { + assert(Tok.is(tok::less) && "Expected '<' for qualifier list"); + ConsumeToken(); + do { + if (Tok.isNot(tok::identifier)) + return TPResult::Error(); + ConsumeToken(); + + if (Tok.is(tok::comma)) { + ConsumeToken(); + continue; + } + + if (Tok.is(tok::greater)) { + ConsumeToken(); + return TPResult::Ambiguous(); + } + } while (false); + + return TPResult::Error(); +} + Parser::TPResult Parser::TryParseDeclarationSpecifier() { TPResult TPR = isCXXDeclarationSpecifier(); if (TPR != TPResult::Ambiguous()) @@ -877,8 +1059,12 @@ Parser::TPResult Parser::TryParseDeclarationSpecifier() { if (Tok.is(tok::kw_typeof)) TryParseTypeofSpecifier(); - else + else { ConsumeToken(); + + if (getLang().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } assert(Tok.is(tok::l_paren) && "Expected '('!"); return TPResult::Ambiguous(); @@ -940,10 +1126,11 @@ bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) { /// parameter-declaration-list ',' parameter-declaration /// /// parameter-declaration: -/// decl-specifier-seq declarator -/// decl-specifier-seq declarator '=' assignment-expression -/// decl-specifier-seq abstract-declarator[opt] -/// decl-specifier-seq abstract-declarator[opt] '=' assignment-expression +/// decl-specifier-seq declarator attributes[opt] +/// decl-specifier-seq declarator attributes[opt] '=' assignment-expression +/// decl-specifier-seq abstract-declarator[opt] attributes[opt] +/// decl-specifier-seq abstract-declarator[opt] attributes[opt] +/// '=' assignment-expression /// Parser::TPResult Parser::TryParseParameterDeclarationClause() { @@ -964,6 +1151,9 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() { return TPResult::True(); // '...' is a sign of a function declarator. } + ParsedAttributes attrs; + MaybeParseMicrosoftAttributes(attrs); + // decl-specifier-seq TPResult TPR = TryParseDeclarationSpecifier(); if (TPR != TPResult::Ambiguous()) @@ -975,11 +1165,15 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() { if (TPR != TPResult::Ambiguous()) return TPR; + // [GNU] attributes[opt] + if (Tok.is(tok::kw___attribute)) + return TPResult::True(); + if (Tok.is(tok::equal)) { // '=' assignment-expression // Parse through assignment-expression. - tok::TokenKind StopToks[3] ={ tok::comma, tok::ellipsis, tok::r_paren }; - if (!SkipUntil(StopToks, 3, true/*StopAtSemi*/, true/*DontConsume*/)) + tok::TokenKind StopToks[2] ={ tok::comma, tok::r_paren }; + if (!SkipUntil(StopToks, 2, true/*StopAtSemi*/, true/*DontConsume*/)) return TPResult::Error(); } @@ -1029,6 +1223,10 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() { Tok.is(tok::kw_restrict) ) ConsumeToken(); + // ref-qualifier[opt] + if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) + ConsumeToken(); + // exception-specification if (Tok.is(tok::kw_throw)) { ConsumeToken(); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 44bd0fb..a50763a 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -23,8 +23,8 @@ using namespace clang; Parser::Parser(Preprocessor &pp, Sema &actions) : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()), - GreaterThanIsOperator(true), ColonIsSacred(false), - TemplateParameterDepth(0) { + GreaterThanIsOperator(true), ColonIsSacred(false), + InMessageExpression(false), TemplateParameterDepth(0) { Tok.setKind(tok::eof); Actions.CurScope = 0; NumCachedScopes = 0; @@ -50,6 +50,17 @@ Parser::Parser(Preprocessor &pp, Sema &actions) WeakHandler.reset(new PragmaWeakHandler(actions)); PP.AddPragmaHandler(WeakHandler.get()); + + FPContractHandler.reset(new PragmaFPContractHandler(actions, *this)); + PP.AddPragmaHandler("STDC", FPContractHandler.get()); + + if (getLang().OpenCL) { + OpenCLExtensionHandler.reset( + new PragmaOpenCLExtensionHandler(actions, *this)); + PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get()); + + PP.AddPragmaHandler("OPENCL", FPContractHandler.get()); + } PP.setCodeCompletionHandler(*this); } @@ -78,7 +89,7 @@ void PrettyStackTraceParserEntry::print(llvm::raw_ostream &OS) const { DiagnosticBuilder Parser::Diag(SourceLocation Loc, unsigned DiagID) { - return Diags.Report(FullSourceLoc(Loc, PP.getSourceManager()), DiagID); + return Diags.Report(Loc, DiagID); } DiagnosticBuilder Parser::Diag(const Token &Tok, unsigned DiagID) { @@ -126,6 +137,8 @@ SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok, case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break; case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break; case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break; + case tok::greatergreatergreater: + LHSName = "<<<"; DID = diag::err_expected_ggg; break; } Diag(Tok, DID); Diag(LHSLoc, diag::note_matching) << LHSName; @@ -133,6 +146,13 @@ SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok, return R; } +static bool IsCommonTypo(tok::TokenKind ExpectedTok, const Token &Tok) { + switch (ExpectedTok) { + case tok::semi: return Tok.is(tok::colon); // : for ; + default: return false; + } +} + /// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the /// input. If so, it is consumed and false is returned. /// @@ -146,6 +166,19 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, return false; } + // Detect common single-character typos and resume. + if (IsCommonTypo(ExpectedTok, Tok)) { + SourceLocation Loc = Tok.getLocation(); + Diag(Loc, DiagID) + << Msg + << FixItHint::CreateReplacement(SourceRange(Loc), + getTokenSimpleSpelling(ExpectedTok)); + ConsumeAnyToken(); + + // Pretend there wasn't a problem. + return false; + } + const char *Spelling = 0; SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation); if (EndLoc.isValid() && @@ -162,6 +195,25 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, return true; } +bool Parser::ExpectAndConsumeSemi(unsigned DiagID) { + if (Tok.is(tok::semi) || Tok.is(tok::code_completion)) { + ConsumeAnyToken(); + return false; + } + + if ((Tok.is(tok::r_paren) || Tok.is(tok::r_square)) && + NextToken().is(tok::semi)) { + Diag(Tok, diag::err_extraneous_token_before_semi) + << PP.getSpelling(Tok) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeAnyToken(); // The ')' or ']'. + ConsumeToken(); // The ';'. + return false; + } + + return ExpectAndConsume(tok::semi, DiagID); +} + //===----------------------------------------------------------------------===// // Error recovery. //===----------------------------------------------------------------------===// @@ -175,7 +227,8 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, /// If SkipUntil finds the specified token, it returns true, otherwise it /// returns false. bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks, - bool StopAtSemi, bool DontConsume) { + bool StopAtSemi, bool DontConsume, + bool StopAtCodeCompletion) { // We always want this function to skip at least one token if the first token // isn't T and if not at EOF. bool isFirstTokenSkipped = true; @@ -198,23 +251,24 @@ bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks, return false; case tok::code_completion: - ConsumeToken(); + if (!StopAtCodeCompletion) + ConsumeToken(); return false; case tok::l_paren: // Recursively skip properly-nested parens. ConsumeParen(); - SkipUntil(tok::r_paren, false); + SkipUntil(tok::r_paren, false, false, StopAtCodeCompletion); break; case tok::l_square: // Recursively skip properly-nested square brackets. ConsumeBracket(); - SkipUntil(tok::r_square, false); + SkipUntil(tok::r_square, false, false, StopAtCodeCompletion); break; case tok::l_brace: // Recursively skip properly-nested braces. ConsumeBrace(); - SkipUntil(tok::r_brace, false); + SkipUntil(tok::r_brace, false, false, StopAtCodeCompletion); break; // Okay, we found a ']' or '}' or ')', which we think should be balanced. @@ -266,9 +320,8 @@ void Parser::EnterScope(unsigned ScopeFlags) { N->Init(getCurScope(), ScopeFlags); Actions.CurScope = N; } else { - Actions.CurScope = new Scope(getCurScope(), ScopeFlags); + Actions.CurScope = new Scope(getCurScope(), ScopeFlags, Diags); } - getCurScope()->setNumErrorsAtStart(Diags.getNumErrors()); } /// ExitScope - Pop a scope off the scope stack. @@ -318,6 +371,15 @@ Parser::~Parser() { UnusedHandler.reset(); PP.RemovePragmaHandler(WeakHandler.get()); WeakHandler.reset(); + + if (getLang().OpenCL) { + PP.RemovePragmaHandler("OPENCL", OpenCLExtensionHandler.get()); + OpenCLExtensionHandler.reset(); + PP.RemovePragmaHandler("OPENCL", FPContractHandler.get()); + } + + PP.RemovePragmaHandler("STDC", FPContractHandler.get()); + FPContractHandler.reset(); PP.clearCodeCompletionHandler(); } @@ -347,6 +409,9 @@ void Parser::Initialize() { ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref"); } + Ident_final = 0; + Ident_override = 0; + Ident_super = &PP.getIdentifierTable().get("super"); if (getLang().AltiVec) { @@ -358,16 +423,21 @@ void Parser::Initialize() { /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the /// action tells us to. This returns true if the EOF was encountered. bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { + + while (Tok.is(tok::annot_pragma_unused)) + HandlePragmaUnused(); + Result = DeclGroupPtrTy(); if (Tok.is(tok::eof)) { Actions.ActOnEndOfTranslationUnit(); return true; } - CXX0XAttributeList Attr; - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) - Attr = ParseCXX0XAttributes(); - Result = ParseExternalDeclaration(Attr); + ParsedAttributesWithRange attrs; + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + + Result = ParseExternalDeclaration(attrs); return false; } @@ -408,8 +478,9 @@ void Parser::ParseTranslationUnit() { /// ';' /// /// [C++0x/GNU] 'extern' 'template' declaration -Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr, - ParsingDeclSpec *DS) { +Parser::DeclGroupPtrTy +Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, + ParsingDeclSpec *DS) { ParenBraceBracketBalancer BalancerRAIIObj(*this); Decl *SingleDecl = 0; @@ -433,12 +504,10 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr, // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); - return ParseExternalDeclaration(Attr); + return ParseExternalDeclaration(attrs); } case tok::kw_asm: { - if (Attr.HasAttr) - Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) - << Attr.Range; + ProhibitAttributes(attrs); ExprResult Result(ParseSimpleAsm()); @@ -470,7 +539,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr, ObjCImpDecl? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace); ConsumeCodeCompletionToken(); - return ParseExternalDeclaration(Attr); + return ParseExternalDeclaration(attrs); case tok::kw_using: case tok::kw_namespace: case tok::kw_typedef: @@ -480,14 +549,42 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr, // A function definition cannot start with a these keywords. { SourceLocation DeclEnd; - return ParseDeclaration(Declarator::FileContext, DeclEnd, Attr); + StmtVector Stmts(Actions); + return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs); } + case tok::kw_static: + // Parse (then ignore) 'static' prior to a template instantiation. This is + // a GCC extension that we intentionally do not support. + if (getLang().CPlusPlus && NextToken().is(tok::kw_template)) { + Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored) + << 0; + SourceLocation DeclEnd; + StmtVector Stmts(Actions); + return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs); + } + goto dont_know; + case tok::kw_inline: - if (getLang().CPlusPlus && NextToken().is(tok::kw_namespace)) { + if (getLang().CPlusPlus) { + tok::TokenKind NextKind = NextToken().getKind(); + // Inline namespaces. Allowed as an extension even in C++03. - SourceLocation DeclEnd; - return ParseDeclaration(Declarator::FileContext, DeclEnd, Attr); + if (NextKind == tok::kw_namespace) { + SourceLocation DeclEnd; + StmtVector Stmts(Actions); + return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs); + } + + // Parse (then ignore) 'inline' prior to a template instantiation. This is + // a GCC extension that we intentionally do not support. + if (NextKind == tok::kw_template) { + Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored) + << 1; + SourceLocation DeclEnd; + StmtVector Stmts(Actions); + return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs); + } } goto dont_know; @@ -506,10 +603,12 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr, default: dont_know: // We can't tell whether this is a function-definition or declaration yet. - if (DS) - return ParseDeclarationOrFunctionDefinition(*DS, Attr.AttrList); - else - return ParseDeclarationOrFunctionDefinition(Attr.AttrList); + if (DS) { + DS->takeAttributesFrom(attrs); + return ParseDeclarationOrFunctionDefinition(*DS); + } else { + return ParseDeclarationOrFunctionDefinition(attrs); + } } // This routine returns a DeclGroup, if the thing we parsed only contains a @@ -532,14 +631,13 @@ bool Parser::isDeclarationAfterDeclarator() const { /// \brief Determine whether the current token, if it occurs after a /// declarator, indicates the start of a function definition. bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) { - assert(Declarator.getTypeObject(0).Kind == DeclaratorChunk::Function && - "Isn't a function declarator"); + assert(Declarator.isFunctionDeclarator() && "Isn't a function declarator"); if (Tok.is(tok::l_brace)) // int X() {} return true; // Handle K&R C argument lists: int X(f) int f; {} if (!getLang().CPlusPlus && - Declarator.getTypeObject(0).Fun.isKNRPrototype()) + Declarator.getFunctionTypeInfo().isKNRPrototype()) return isDeclarationSpecifier(); return Tok.is(tok::colon) || // X() : Base() {} (used for ctors) @@ -564,12 +662,8 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) { /// Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, - AttributeList *Attr, AccessSpecifier AS) { // Parse the common declaration-specifiers piece. - if (Attr) - DS.AddAttributes(Attr); - ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" @@ -622,10 +716,11 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, } Parser::DeclGroupPtrTy -Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr, +Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs, AccessSpecifier AS) { ParsingDeclSpec DS(*this); - return ParseDeclarationOrFunctionDefinition(DS, Attr, AS); + DS.takeAttributesFrom(attrs); + return ParseDeclarationOrFunctionDefinition(DS, AS); } /// ParseFunctionDefinition - We parsed and verified that the specified @@ -643,11 +738,8 @@ Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr, /// decl-specifier-seq[opt] declarator function-try-block /// Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, - const ParsedTemplateInfo &TemplateInfo) { - const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0); - assert(FnTypeInfo.Kind == DeclaratorChunk::Function && - "This isn't a function declarator!"); - const DeclaratorChunk::FunctionTypeInfo &FTI = FnTypeInfo.Fun; + const ParsedTemplateInfo &TemplateInfo) { + const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); // If this is C90 and the declspecs were completely missing, fudge in an // implicit int. We do this here because this is the only place where @@ -669,8 +761,9 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // We should have either an opening brace or, in a C++ constructor, // we may have a colon. - if (Tok.isNot(tok::l_brace) && Tok.isNot(tok::colon) && - Tok.isNot(tok::kw_try)) { + if (Tok.isNot(tok::l_brace) && + (!getLang().CPlusPlus || + (Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try)))) { Diag(Tok, diag::err_expected_fn_body); // Skip over garbage, until we get to '{'. Don't eat the '{'. @@ -724,7 +817,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, /// types for a function with a K&R-style identifier list for arguments. void Parser::ParseKNRParamDeclarations(Declarator &D) { // We know that the top-level of this declarator is a function. - DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); // Enter function-declaration scope, limiting any declarators to the // function prototype scope, including parameter declarators. @@ -770,11 +863,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { // Handle the full declarator list. while (1) { // If attributes are present, parse them. - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseGNUAttributes(&Loc); - ParmDeclarator.AddAttributes(AttrList, Loc); - } + MaybeParseGNUAttributes(ParmDeclarator); // Ask the actions module to compute the type for this declarator. Decl *Param = @@ -994,7 +1083,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { // Determine whether the identifier is a type name. if (ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), - &SS)) { + &SS, false, + NextToken().is(tok::period))) { // This is a typename. Replace the current token in-place with an // annotation type token. Tok.setKind(tok::annot_typename); @@ -1115,6 +1205,20 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { return false; } +bool Parser::isTokenEqualOrMistypedEqualEqual(unsigned DiagID) { + if (Tok.is(tok::equalequal)) { + // We have '==' in a context that we would expect a '='. + // The user probably made a typo, intending to type '='. Emit diagnostic, + // fixit hint to turn '==' -> '=' and continue as if the user typed '='. + Diag(Tok, DiagID) + << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), + getTokenSimpleSpelling(tok::equal)); + return true; + } + + return Tok.is(tok::equal); +} + void Parser::CodeCompletionRecovery() { for (Scope *S = getCurScope(); S; S = S->getParent()) { if (S->getFlags() & Scope::FnScope) { diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h index addc795..583f184 100644 --- a/lib/Parse/RAIIObjectsForParser.h +++ b/lib/Parse/RAIIObjectsForParser.h @@ -80,6 +80,22 @@ namespace clang { } }; + class InMessageExpressionRAIIObject { + bool &InMessageExpression; + bool OldValue; + + public: + InMessageExpressionRAIIObject(Parser &P, bool Value) + : InMessageExpression(P.InMessageExpression), + OldValue(P.InMessageExpression) { + InMessageExpression = Value; + } + + ~InMessageExpressionRAIIObject() { + InMessageExpression = OldValue; + } + }; + /// \brief RAII object that makes sure paren/bracket/brace count is correct /// after declaration/statement parsing, even when there's a parsing error. class ParenBraceBracketBalancer { |