diff options
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/AttributeList.cpp | 24 | ||||
-rw-r--r-- | lib/Parse/MinimalAction.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 3 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 126 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 270 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 29 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 113 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 8 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 187 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 50 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 88 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 27 |
12 files changed, 722 insertions, 205 deletions
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index dde4bc8..df48e3a 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -17,11 +17,13 @@ using namespace clang; AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, + IdentifierInfo *sName, SourceLocation sLoc, IdentifierInfo *pName, SourceLocation pLoc, ActionBase::ExprTy **ExprList, unsigned numArgs, - AttributeList *n, bool declspec) - : AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc), - NumArgs(numArgs), Next(n), DeclspecAttribute(declspec) { + AttributeList *n, bool declspec, bool cxx0x) + : AttrName(aName), AttrLoc(aLoc), ScopeName(sName), ScopeLoc(sLoc), + ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n), + DeclspecAttribute(declspec), CXX0XAttribute(cxx0x) { if (numArgs == 0) Args = 0; @@ -59,13 +61,16 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("mode", AT_mode) .Case("used", AT_used) .Case("alias", AT_alias) + .Case("align", AT_aligned) + .Case("final", AT_final) .Case("cdecl", AT_cdecl) .Case("const", AT_const) - .Case("packed", AT_packed) - .Case("malloc", AT_malloc) + .Case("blocks", AT_blocks) .Case("format", AT_format) + .Case("hiding", AT_hiding) + .Case("malloc", AT_malloc) + .Case("packed", AT_packed) .Case("unused", AT_unused) - .Case("blocks", AT_blocks) .Case("aligned", AT_aligned) .Case("cleanup", AT_cleanup) .Case("nodebug", AT_nodebug) @@ -76,15 +81,17 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("section", AT_section) .Case("stdcall", AT_stdcall) .Case("annotate", AT_annotate) - .Case("noreturn", AT_noreturn) - .Case("noinline", AT_noinline) .Case("fastcall", AT_fastcall) .Case("iboutlet", AT_IBOutlet) + .Case("noreturn", AT_noreturn) + .Case("noinline", AT_noinline) + .Case("override", AT_override) .Case("sentinel", AT_sentinel) .Case("NSObject", AT_nsobject) .Case("dllimport", AT_dllimport) .Case("dllexport", AT_dllexport) .Case("may_alias", IgnoredAttribute) // FIXME: TBAA + .Case("base_check", AT_base_check) .Case("deprecated", AT_deprecated) .Case("visibility", AT_visibility) .Case("destructor", AT_destructor) @@ -103,6 +110,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("transparent_union", AT_transparent_union) .Case("analyzer_noreturn", AT_analyzer_noreturn) .Case("warn_unused_result", AT_warn_unused_result) + .Case("carries_dependency", AT_carries_dependency) .Case("ns_returns_retained", AT_ns_returns_retained) .Case("cf_returns_retained", AT_cf_returns_retained) .Case("reqd_work_group_size", AT_reqd_wg_size) diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 7681eac..aa0b89b 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -144,7 +144,7 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { Action::TypeTy * MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc, Scope *S, const CXXScopeSpec *SS, - bool isClassName) { + bool isClassName, TypeTy *ObjectType) { if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>()) if (TI->isTypeName) return TI; diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index c34653e..b9314d2 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -37,7 +37,8 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, move(TemplateParams)); else // FIXME: pass template information through FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, - move(TemplateParams), 0, 0); + move(TemplateParams), 0, 0, + /*IsDefinition*/true); HandleMemberFunctionDefaultArgs(D, FnD); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 2bfda30..b13dc73 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1,3 +1,4 @@ + //===--- ParseDecl.cpp - Declaration Parsing ------------------------------===// // // The LLVM Compiler Infrastructure @@ -45,7 +46,7 @@ Action::TypeResult Parser::ParseTypeName(SourceRange *Range) { return Actions.ActOnTypeName(CurScope, DeclaratorInfo); } -/// ParseAttributes - Parse a non-empty attributes list. +/// ParseGNUAttributes - Parse a non-empty attributes list. /// /// [GNU] attributes: /// attribute @@ -81,8 +82,8 @@ Action::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::ParseAttributes(SourceLocation *EndLoc) { - assert(Tok.is(tok::kw___attribute) && "Not an attribute list!"); +AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { + assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); AttributeList *CurrAttr = 0; @@ -121,7 +122,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { if (Tok.is(tok::r_paren)) { // __attribute__(( mode(byte) )) ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, ParmName, ParmLoc, 0, 0, CurrAttr); } else if (Tok.is(tok::comma)) { ConsumeToken(); @@ -145,8 +146,10 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { } if (ArgExprsOk && Tok.is(tok::r_paren)) { ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName, - ParmLoc, ArgExprs.take(), ArgExprs.size(), CurrAttr); + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, + AttrNameLoc, ParmName, ParmLoc, + ArgExprs.take(), ArgExprs.size(), + CurrAttr); } } } else { // not an identifier @@ -155,7 +158,7 @@ AttributeList *Parser::ParseAttributes(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, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0, CurrAttr); break; case tok::kw_char: @@ -175,7 +178,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { // If it's a builtin type name, eat it and expect a rparen // __attribute__(( vec_type_hint(char) )) ConsumeToken(); - CurrAttr = new AttributeList(AttrName, AttrNameLoc, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0, CurrAttr); if (Tok.is(tok::r_paren)) ConsumeParen(); @@ -203,20 +206,21 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { if (ArgExprsOk && Tok.is(tok::r_paren)) { ConsumeParen(); // ignore the right paren loc for now CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, - SourceLocation(), ArgExprs.take(), ArgExprs.size(), + AttrNameLoc, 0, SourceLocation(), ArgExprs.take(), + ArgExprs.size(), CurrAttr); } break; } } } else { - CurrAttr = new AttributeList(AttrName, AttrNameLoc, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0, CurrAttr); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) SkipUntil(tok::r_paren, false); - SourceLocation Loc = Tok.getLocation();; + SourceLocation Loc = Tok.getLocation(); if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { SkipUntil(tok::r_paren, false); } @@ -254,15 +258,15 @@ AttributeList* Parser::ParseMicrosoftDeclSpec(AttributeList *CurrAttr) { OwningExprResult ArgExpr(ParseAssignmentExpression()); if (!ArgExpr.isInvalid()) { ExprTy* ExprList = ArgExpr.take(); - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), &ExprList, 1, CurrAttr, true); } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) SkipUntil(tok::r_paren, false); } else { - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, SourceLocation(), - 0, 0, CurrAttr, true); + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0, CurrAttr, true); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) @@ -281,7 +285,7 @@ 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, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0, CurrAttr, true); } return CurrAttr; @@ -304,26 +308,36 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) { /// others... [FIXME] /// Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, - SourceLocation &DeclEnd) { + SourceLocation &DeclEnd, + CXX0XAttributeList Attr) { DeclPtrTy SingleDecl; 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; SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd); break; case tok::kw_namespace: + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; SingleDecl = ParseNamespace(Context, DeclEnd); break; case tok::kw_using: - SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd); + SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd, Attr); break; case tok::kw_static_assert: + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; SingleDecl = ParseStaticAssertDeclaration(DeclEnd); break; default: - return ParseSimpleDeclaration(Context, DeclEnd); + return ParseSimpleDeclaration(Context, DeclEnd, Attr.AttrList); } - + // This routine returns a DeclGroup, if the thing we parsed only contains a // single decl, convert it now. return Actions.ConvertDeclToDeclGroup(SingleDecl); @@ -337,9 +351,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, /// If RequireSemi is false, this does not check for a ';' at the end of the /// declaration. Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, - SourceLocation &DeclEnd) { + SourceLocation &DeclEnd, + AttributeList *Attr) { // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); + if (Attr) + DS.AddAttributes(Attr); ParseDeclarationSpecifiers(DS); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" @@ -422,7 +439,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // short x, __attribute__((common)) var; -> declarator if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); D.AddAttributes(AttrList, Loc); } @@ -491,7 +508,7 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, // If attributes are present, parse them. if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); D.AddAttributes(AttrList, Loc); } @@ -988,7 +1005,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // GNU attributes support. case tok::kw___attribute: - DS.AddAttributes(ParseAttributes()); + DS.AddAttributes(ParseGNUAttributes()); continue; // Microsoft declspec support. @@ -1522,7 +1539,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { // Attributes are only allowed here on successive declarators. if (!FirstDeclarator && Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.D.AddAttributes(AttrList, Loc); } @@ -1543,7 +1560,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { // If attributes exist after the declarator, parse them. if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.D.AddAttributes(AttrList, Loc); } @@ -1667,7 +1684,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, AttributeList *AttrList = 0; // If attributes exist after struct contents, parse them. if (Tok.is(tok::kw___attribute)) - AttrList = ParseAttributes(); + AttrList = ParseGNUAttributes(); Actions.ActOnFields(CurScope, RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(), @@ -1702,7 +1719,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, AttributeList *Attr = 0; // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) - Attr = ParseAttributes(); + Attr = ParseGNUAttributes(); CXXScopeSpec SS; if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) { @@ -1833,7 +1850,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { AttributeList *Attr = 0; // If attributes exist after the identifier list, parse them. if (Tok.is(tok::kw___attribute)) - Attr = ParseAttributes(); + Attr = ParseGNUAttributes(); // FIXME: where do they do? Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl, EnumConstantDecls.data(), EnumConstantDecls.size(), @@ -2049,8 +2066,20 @@ bool Parser::isDeclarationSpecifier() { /// [GNU] attributes [ only if AttributesAllowed=true ] /// type-qualifier-list type-qualifier /// [GNU] type-qualifier-list attributes [ only if AttributesAllowed=true ] +/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq +/// if CXX0XAttributesAllowed = true /// -void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) { +void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed, + bool CXX0XAttributesAllowed) { + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + SourceLocation Loc = Tok.getLocation(); + CXX0XAttributeList Attr = ParseCXX0XAttributes(); + if (CXX0XAttributesAllowed) + DS.AddAttributes(Attr.AttrList); + else + Diag(Loc, diag::err_attributes_not_allowed); + } + while (1) { bool isInvalid = false; const char *PrevSpec = 0; @@ -2075,14 +2104,14 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) { case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: - if (AttributesAllowed) { + if (GNUAttributesAllowed) { DS.AddAttributes(ParseMicrosoftTypeAttributes()); continue; } goto DoneWithTypeQuals; case tok::kw___attribute: - if (AttributesAllowed) { - DS.AddAttributes(ParseAttributes()); + if (GNUAttributesAllowed) { + DS.AddAttributes(ParseGNUAttributes()); continue; // do *not* consume the next token! } // otherwise, FALL THROUGH! @@ -2221,7 +2250,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // // [GNU] Retricted references are allowed. // [GNU] Attributes on references are allowed. - ParseTypeQualifierListOpt(DS); + // [C++0x] Attributes on references are not allowed. + ParseTypeQualifierListOpt(DS, true, false); D.ExtendWithDeclSpec(DS); if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) { @@ -2362,6 +2392,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) { assert(D.isPastIdentifier() && "Haven't past the location of the identifier yet?"); + // Don't parse attributes unless we have an identifier. + if (D.getIdentifier() && getLang().CPlusPlus + && isCXX0XAttributeSpecifier(true)) { + SourceLocation AttrEndLoc; + CXX0XAttributeList Attr = ParseCXX0XAttributes(); + D.AddAttributes(Attr.AttrList, AttrEndLoc); + } + while (1) { if (Tok.is(tok::l_paren)) { // The paren may be part of a C++ direct initializer, eg. "int x(1);". @@ -2413,7 +2451,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { AttributeList *AttrList = 0; bool RequiresArg = false; if (Tok.is(tok::kw___attribute)) { - AttrList = ParseAttributes(); + AttrList = ParseGNUAttributes(); // We require that the argument list (if this is a non-grouping paren) be // present even if the attribute list was empty. @@ -2618,7 +2656,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Parse GNU attributes, if present. if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); ParmDecl.AddAttributes(AttrList, Loc); } @@ -2722,6 +2760,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, bool hasAnyExceptionSpec = false; llvm::SmallVector<TypeTy*, 2> Exceptions; llvm::SmallVector<SourceRange, 2> ExceptionRanges; + if (getLang().CPlusPlus) { // Parse cv-qualifier-seq[opt]. ParseTypeQualifierListOpt(DS, false /*no attributes*/); @@ -2842,6 +2881,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(); + } + // Remember that we parsed the empty array type. OwningExprResult NumElements(Actions); D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, @@ -2855,6 +2900,11 @@ 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()) @@ -2922,6 +2972,12 @@ void Parser::ParseBracketDeclarator(Declarator &D) { SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); + //FIXME: Use these + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + Attr = ParseCXX0XAttributes(); + } + // Remember that we parsed a array type, and remember its features. D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), StaticLoc.isValid(), isStar, diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 914bfc9..505a4d8 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -69,7 +69,7 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, attrTok = Tok; // FIXME: save these somewhere. - AttrList = ParseAttributes(); + AttrList = ParseGNUAttributes(); } if (Tok.is(tok::equal)) { @@ -97,8 +97,12 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, PP.getSourceManager(), "parsing namespace"); - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) - ParseExternalDeclaration(); + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + ParseExternalDeclaration(Attr); + } // Leave the namespace scope. NamespaceScope.Exit(); @@ -175,15 +179,27 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) { Tok.is(tok::l_brace)? Tok.getLocation() : SourceLocation()); + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + Attr = ParseCXX0XAttributes(); + } + if (Tok.isNot(tok::l_brace)) { - ParseDeclarationOrFunctionDefinition(); + ParseDeclarationOrFunctionDefinition(Attr.AttrList); return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec, SourceLocation()); } + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + SourceLocation LBrace = ConsumeBrace(); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - ParseExternalDeclaration(); + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + ParseExternalDeclaration(Attr); } SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace); @@ -193,7 +209,8 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) { /// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or /// using-directive. Assumes that current token is 'using'. Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, - SourceLocation &DeclEnd) { + SourceLocation &DeclEnd, + CXX0XAttributeList Attr) { assert(Tok.is(tok::kw_using) && "Not using token"); // Eat 'using'. @@ -206,9 +223,14 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, if (Tok.is(tok::kw_namespace)) // Next token after 'using' is 'namespace' so it must be using-directive - return ParseUsingDirective(Context, UsingLoc, DeclEnd); + return ParseUsingDirective(Context, UsingLoc, DeclEnd, Attr.AttrList); + + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; // Otherwise, it must be using-declaration. + // Ignore illegal attributes (the caller should already have issued an error. return ParseUsingDeclaration(Context, UsingLoc, DeclEnd); } @@ -224,7 +246,8 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, /// Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, SourceLocation UsingLoc, - SourceLocation &DeclEnd) { + SourceLocation &DeclEnd, + AttributeList *Attr) { assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token"); // Eat 'namespace'. @@ -239,7 +262,6 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, // Parse (optional) nested-name-specifier. ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); - AttributeList *AttrList = 0; IdentifierInfo *NamespcName = 0; SourceLocation IdentLoc = SourceLocation(); @@ -257,17 +279,20 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, IdentLoc = ConsumeToken(); // Parse (optional) attributes (most likely GNU strong-using extension). - if (Tok.is(tok::kw___attribute)) - AttrList = ParseAttributes(); + bool GNUAttr = false; + if (Tok.is(tok::kw___attribute)) { + GNUAttr = true; + Attr = addAttributeLists(Attr, ParseGNUAttributes()); + } // Eat ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, - AttrList ? diag::err_expected_semi_after_attribute_list : + GNUAttr ? diag::err_expected_semi_after_attribute_list : diag::err_expected_semi_after_namespace_name, "", tok::semi); return Actions.ActOnUsingDirective(CurScope, UsingLoc, NamespcLoc, SS, - IdentLoc, NamespcName, AttrList); + IdentLoc, NamespcName, Attr); } /// ParseUsingDeclaration - Parse C++ using-declaration. Assumes that @@ -323,7 +348,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, // Parse (optional) attributes (most likely GNU strong-using extension). if (Tok.is(tok::kw___attribute)) - AttrList = ParseAttributes(); + AttrList = ParseGNUAttributes(); // Eat ';'. DeclEnd = Tok.getLocation(); @@ -538,14 +563,20 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, ConsumeToken(); } - AttributeList *Attr = 0; + AttributeList *AttrList = 0; // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) - Attr = ParseAttributes(); + AttrList = ParseGNUAttributes(); // If declspecs exist after tag, parse them. if (Tok.is(tok::kw___declspec)) - Attr = ParseMicrosoftDeclSpec(Attr); + AttrList = ParseMicrosoftDeclSpec(AttrList); + + // 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); 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 @@ -683,7 +714,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Diag(StartLoc, diag::err_anon_type_definition) << DeclSpec::getSpecifierName(TagType); - // Skip the rest of this declarator, up until the comma or semicolon. SkipUntil(tok::comma, true); if (TemplateId) @@ -720,7 +750,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, - Attr); + AttrList); } else if (TUK == Action::TUK_Reference) { TypeResult = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), @@ -775,7 +805,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, - Attr, + AttrList, Action::MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); @@ -793,7 +823,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, TagType, StartLoc, SS, Name, - NameLoc, Attr); + NameLoc, AttrList); } else { if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Action::TUK_Definition) { @@ -804,7 +834,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Declaration or definition of a class type TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TUK, StartLoc, SS, - Name, NameLoc, Attr, AS, + Name, NameLoc, AttrList, AS, Action::MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0), @@ -1055,8 +1085,18 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return ParseCXXClassMemberDeclaration(AS, TemplateInfo); } + CXX0XAttributeList AttrList; + // Optional C++0x attribute-specifier + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + AttrList = ParseCXX0XAttributes(); + } + 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; // Eat 'using'. SourceLocation UsingLoc = ConsumeToken(); @@ -1077,6 +1117,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // decl-specifier-seq: // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); + DS.AddAttributes(AttrList.AttrList); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class); Action::MultiTemplateParamsArg TemplateParams(Actions, @@ -1103,6 +1144,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } + // 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); + } + // function-definition: if (Tok.is(tok::l_brace) || (DeclaratorInfo.isFunctionDeclarator() && @@ -1139,7 +1187,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, bool Deleted = false; while (1) { - // member-declarator: // declarator pure-specifier[opt] // declarator constant-initializer[opt] @@ -1177,7 +1224,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // If attributes exist after the declarator, parse them. if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.AddAttributes(AttrList, Loc); } @@ -1197,6 +1244,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, move(TemplateParams), BitfieldSize.release(), Init.release(), + /*IsDefinition*/Deleted, Deleted); } if (ThisDecl) @@ -1227,7 +1275,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Attributes are only allowed on the second declarator. if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.AddAttributes(AttrList, Loc); } @@ -1326,7 +1374,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, AttributeList *AttrList = 0; // If attributes exist after class contents, parse them. if (Tok.is(tok::kw___attribute)) - AttrList = ParseAttributes(); // FIXME: where should I put them? + AttrList = ParseGNUAttributes(); // FIXME: where should I put them? Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl, LBraceLoc, RBraceLoc); @@ -1573,3 +1621,173 @@ void Parser::PopParsingClass() { ClassStack.top()->NestedClasses.push_back(Victim); Victim->TemplateScope = CurScope->getParent()->isTemplateParamScope(); } + +/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier. Currently only +/// parses standard attributes. +/// +/// [C++0x] attribute-specifier: +/// '[' '[' attribute-list ']' ']' +/// +/// [C++0x] attribute-list: +/// attribute[opt] +/// attribute-list ',' attribute[opt] +/// +/// [C++0x] attribute: +/// attribute-token attribute-argument-clause[opt] +/// +/// [C++0x] attribute-token: +/// identifier +/// attribute-scoped-token +/// +/// [C++0x] attribute-scoped-token: +/// attribute-namespace '::' identifier +/// +/// [C++0x] attribute-namespace: +/// identifier +/// +/// [C++0x] attribute-argument-clause: +/// '(' balanced-token-seq ')' +/// +/// [C++0x] balanced-token-seq: +/// balanced-token +/// balanced-token-seq balanced-token +/// +/// [C++0x] balanced-token: +/// '(' balanced-token-seq ')' +/// '[' balanced-token-seq ']' +/// '{' balanced-token-seq '}' +/// any token but '(', ')', '[', ']', '{', or '}' +CXX0XAttributeList Parser::ParseCXX0XAttributes(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(); + + if (Tok.is(tok::comma)) { + Diag(Tok.getLocation(), diag::err_expected_ident); + ConsumeToken(); + } + + while (Tok.is(tok::identifier) || Tok.is(tok::comma)) { + // attribute not present + if (Tok.is(tok::comma)) { + ConsumeToken(); + continue; + } + + IdentifierInfo *ScopeName = 0, *AttrName = Tok.getIdentifierInfo(); + SourceLocation ScopeLoc, AttrLoc = ConsumeToken(); + + // scoped attribute + if (Tok.is(tok::coloncolon)) { + ConsumeToken(); + + if (!Tok.is(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_expected_ident); + SkipUntil(tok::r_square, tok::comma, true, true); + continue; + } + + ScopeName = AttrName; + ScopeLoc = AttrLoc; + + AttrName = Tok.getIdentifierInfo(); + AttrLoc = ConsumeToken(); + } + + bool AttrParsed = false; + // No scoped names are supported; ideally we could put all non-standard + // attributes into namespaces. + if (!ScopeName) { + switch(AttributeList::getKind(AttrName)) + { + // No arguments + case AttributeList::AT_base_check: + case AttributeList::AT_carries_dependency: + case AttributeList::AT_final: + case AttributeList::AT_hiding: + case AttributeList::AT_noreturn: + case AttributeList::AT_override: { + 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); + AttrParsed = true; + break; + } + + // One argument; must be a type-id or assignment-expression + case AttributeList::AT_aligned: { + if (Tok.isNot(tok::l_paren)) { + Diag(Tok.getLocation(), diag::err_cxx0x_attribute_requires_arguments) + << AttrName->getName(); + break; + } + SourceLocation ParamLoc = ConsumeParen(); + + OwningExprResult ArgExpr = ParseCXX0XAlignArgument(ParamLoc); + + MatchRHSPunctuation(tok::r_paren, ParamLoc); + + ExprVector ArgExprs(Actions); + ArgExprs.push_back(ArgExpr.release()); + CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc, + 0, ParamLoc, ArgExprs.take(), 1, CurrAttr, + false, true); + + AttrParsed = true; + break; + } + + // Silence warnings + default: break; + } + } + + // Skip the entire parameter clause, if any + if (!AttrParsed && Tok.is(tok::l_paren)) { + ConsumeParen(); + // SkipUntil maintains the balancedness of tokens. + SkipUntil(tok::r_paren, false); + } + } + + if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) + SkipUntil(tok::r_square, false); + Loc = Tok.getLocation(); + if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) + SkipUntil(tok::r_square, false); + + CXX0XAttributeList Attr (CurrAttr, SourceRange(StartLoc, Loc), true); + return Attr; +} + +/// ParseCXX0XAlignArgument - Parse the argument to C++0x's [[align]] +/// attribute. +/// +/// FIXME: Simply returns an alignof() expression if the argument is a +/// type. Ideally, the type should be propagated directly into Sema. +/// +/// [C++0x] 'align' '(' type-id ')' +/// [C++0x] 'align' '(' assignment-expression ')' +Parser::OwningExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) { + if (isTypeIdInParens()) { + EnterExpressionEvaluationContext Unevaluated(Actions, + Action::Unevaluated); + SourceLocation TypeLoc = Tok.getLocation(); + TypeTy *Ty = ParseTypeName().get(); + SourceRange TypeRange(Start, Tok.getLocation()); + return Actions.ActOnSizeOfAlignOfExpr(TypeLoc, false, true, Ty, + TypeRange); + } else + return ParseConstantExpression(); +} diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index d2b3b84..f780cf1 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -413,12 +413,12 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { /// Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, - bool parseParenAsExprList){ + TypeTy *TypeOfCast) { bool NotCastExpr; OwningExprResult Res = ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, - parseParenAsExprList); + TypeOfCast); if (NotCastExpr) Diag(Tok, diag::err_expected_expression); return move(Res); @@ -538,7 +538,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, - bool parseParenAsExprList){ + TypeTy *TypeOfCast) { OwningExprResult Res(Actions); tok::TokenKind SavedKind = Tok.getKind(); NotCastExpr = false; @@ -563,7 +563,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, SourceLocation LParenLoc = Tok.getLocation(); SourceLocation RParenLoc; Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, - parseParenAsExprList, CastTy, RParenLoc); + TypeOfCast, CastTy, RParenLoc); if (Res.isInvalid()) return move(Res); switch (ParenExprType) { @@ -1047,7 +1047,8 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, // operands. EnterExpressionEvaluationContext Unevaluated(Actions, Action::Unevaluated); - Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, false, + Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, + 0/*TypeOfCast*/, CastTy, RParenLoc); CastRange = SourceRange(LParenLoc, RParenLoc); @@ -1304,7 +1305,7 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { /// Parser::OwningExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, - bool parseAsExprList, TypeTy *&CastTy, + TypeTy *TypeOfCast, TypeTy *&CastTy, SourceLocation &RParenLoc) { assert(Tok.is(tok::l_paren) && "Not a paren expr!"); GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); @@ -1315,7 +1316,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { Diag(Tok, diag::ext_gnu_statement_expr); - OwningStmtResult Stmt(ParseCompoundStatement(true)); + OwningStmtResult Stmt(ParseCompoundStatement(0, true)); ExprType = CompoundStmt; // If the substmt parsed correctly, build the AST node. @@ -1365,7 +1366,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // Parse the cast-expression that follows it next. // TODO: For cast expression with CastTy. - Result = ParseCastExpression(false, false, true); + Result = ParseCastExpression(false, false, CastTy); if (!Result.isInvalid()) Result = Actions.ActOnCastExpr(CurScope, OpenLoc, CastTy, RParenLoc, move(Result)); @@ -1374,15 +1375,15 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Diag(Tok, diag::err_expected_lbrace_in_compound_literal); return ExprError(); - } else if (parseAsExprList) { + } else if (TypeOfCast) { // Parse the expression-list. ExprVector ArgExprs(Actions); CommaLocsTy CommaLocs; if (!ParseExpressionList(ArgExprs, CommaLocs)) { ExprType = SimpleExpr; - Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), - move_arg(ArgExprs)); + Result = Actions.ActOnParenOrParenListExpr(OpenLoc, Tok.getLocation(), + move_arg(ArgExprs), TypeOfCast); } } else { Result = ParseExpression(); @@ -1503,7 +1504,7 @@ void Parser::ParseBlockId() { if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.AddAttributes(AttrList, Loc); } @@ -1565,7 +1566,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); ParamInfo.AddAttributes(AttrList, Loc); } @@ -1586,7 +1587,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); ParamInfo.AddAttributes(AttrList, Loc); } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index b2ecc9e..52003e6 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -124,7 +124,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, break; } - if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId) { + if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId && + TemplateName.getKind() != UnqualifiedId::IK_LiteralOperatorId) { Diag(TemplateName.getSourceRange().getBegin(), diag::err_id_after_template_in_nested_name_spec) << TemplateName.getSourceRange(); @@ -148,7 +149,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, TPA.Commit(); TemplateTy Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName, - ObjectType); + ObjectType, EnteringContext); if (!Template) break; if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, @@ -326,6 +327,24 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { /*ObjectType=*/0, Name)) return ExprError(); + + // This is only the direct operand of an & operator if it is not + // followed by a postfix-expression suffix. + if (isAddressOfOperand) { + switch (Tok.getKind()) { + case tok::l_square: + case tok::l_paren: + case tok::arrow: + case tok::period: + case tok::plusplus: + case tok::minusminus: + isAddressOfOperand = false; + break; + + default: + break; + } + } return Actions.ActOnIdExpression(CurScope, SS, Name, Tok.is(tok::l_paren), isAddressOfOperand); @@ -531,7 +550,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { CommaLocs.data(), RParenLoc); } -/// ParseCXXCondition - if/switch/while/for condition expression. +/// ParseCXXCondition - if/switch/while condition expression. /// /// condition: /// expression @@ -539,11 +558,20 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression /// -Parser::OwningExprResult Parser::ParseCXXCondition() { - if (!isCXXConditionDeclaration()) - return ParseExpression(); // expression - - SourceLocation StartLoc = Tok.getLocation(); +/// \param ExprResult if the condition was parsed as an expression, the +/// parsed expression. +/// +/// \param DeclResult if the condition was parsed as a declaration, the +/// parsed declaration. +/// +/// \returns true if there was a parsing, false otherwise. +bool Parser::ParseCXXCondition(OwningExprResult &ExprResult, + DeclPtrTy &DeclResult) { + if (!isCXXConditionDeclaration()) { + ExprResult = ParseExpression(); // expression + DeclResult = DeclPtrTy(); + return ExprResult.isInvalid(); + } // type-specifier-seq DeclSpec DS; @@ -559,7 +587,7 @@ Parser::OwningExprResult Parser::ParseCXXCondition() { OwningExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) { SkipUntil(tok::semi); - return ExprError(); + return true; } DeclaratorInfo.setAsmLabel(AsmLabel.release()); DeclaratorInfo.SetRangeEnd(Loc); @@ -568,21 +596,28 @@ Parser::OwningExprResult Parser::ParseCXXCondition() { // If attributes are present, parse them. if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.AddAttributes(AttrList, Loc); } + // Type-check the declaration itself. + Action::DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(CurScope, + DeclaratorInfo); + DeclResult = Dcl.get(); + ExprResult = ExprError(); + // '=' assignment-expression - if (Tok.isNot(tok::equal)) - return ExprError(Diag(Tok, diag::err_expected_equal_after_declarator)); - SourceLocation EqualLoc = ConsumeToken(); - OwningExprResult AssignExpr(ParseAssignmentExpression()); - if (AssignExpr.isInvalid()) - return ExprError(); - - return Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc, - DeclaratorInfo,EqualLoc, - move(AssignExpr)); + if (Tok.is(tok::equal)) { + SourceLocation EqualLoc = ConsumeToken(); + OwningExprResult AssignExpr(ParseAssignmentExpression()); + if (!AssignExpr.isInvalid()) + Actions.AddInitializerToDecl(DeclResult, move(AssignExpr)); + } else { + // FIXME: C++0x allows a braced-init-list + Diag(Tok, diag::err_expected_equal_after_declarator); + } + + return false; } /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. @@ -757,6 +792,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, switch (Id.getKind()) { case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: + case UnqualifiedId::IK_LiteralOperatorId: TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, EnteringContext, Template); break; @@ -774,7 +810,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, TemplateName.setIdentifier(Name, NameLoc); if (ObjectType) { Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS, - TemplateName, ObjectType); + TemplateName, ObjectType, + EnteringContext); TNK = TNK_Dependent_template_name; if (!Template.get()) return true; @@ -813,7 +850,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, return true; if (Id.getKind() == UnqualifiedId::IK_Identifier || - Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) { + Id.getKind() == UnqualifiedId::IK_OperatorFunctionId || + Id.getKind() == UnqualifiedId::IK_LiteralOperatorId) { // Form a parsed representation of the template-id to be stored in the // UnqualifiedId. TemplateIdAnnotation *TemplateId @@ -996,6 +1034,26 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations); return false; } + + // Parse a literal-operator-id. + // + // literal-operator-id: [C++0x 13.5.8] + // operator "" identifier + + if (getLang().CPlusPlus0x && Tok.is(tok::string_literal)) { + if (Tok.getLength() != 2) + Diag(Tok.getLocation(), diag::err_operator_string_not_empty); + ConsumeStringToken(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_expected_ident); + return true; + } + + IdentifierInfo *II = Tok.getIdentifierInfo(); + Result.setLiteralOperatorId(II, KeywordLoc, ConsumeToken()); + return false; + } // Parse a conversion-function-id. // @@ -1010,7 +1068,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, // Parse the type-specifier-seq. DeclSpec DS; - if (ParseCXXTypeSpecifierSeq(DS)) + if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType? return true; // Parse the conversion-declarator, which is merely a sequence of @@ -1111,12 +1169,13 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result)) return true; - // If we have an operator-function-id and the next token is a '<', we may - // have a + // If we have an operator-function-id or a literal-operator-id and the next + // token is a '<', we may have a // // template-id: // operator-function-id < template-argument-list[opt] > - if (Result.getKind() == UnqualifiedId::IK_OperatorFunctionId && + if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId || + Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) && Tok.is(tok::less)) return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(), EnteringContext, ObjectType, @@ -1152,7 +1211,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, // Note that this is a destructor name. Action::TypeTy *Ty = Actions.getTypeName(*ClassName, ClassNameLoc, - CurScope, &SS); + CurScope, &SS, false, ObjectType); if (!Ty) { if (ObjectType) Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 5ba1dd1..295625a 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -282,7 +282,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy 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()); + allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(0)); continue; } @@ -759,7 +759,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, // If attributes exist after the method, parse them. AttributeList *MethodAttrs = 0; if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - MethodAttrs = ParseAttributes(); + MethodAttrs = ParseGNUAttributes(); Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); DeclPtrTy Result @@ -791,7 +791,7 @@ Parser::DeclPtrTy 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 = ParseAttributes(); + ArgInfo.ArgAttrs = ParseGNUAttributes(); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing argument name. @@ -835,7 +835,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, // If attributes exist after the method, parse them. AttributeList *MethodAttrs = 0; if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - MethodAttrs = ParseAttributes(); + MethodAttrs = ParseGNUAttributes(); if (KeyIdents.size() == 0) return DeclPtrTy(); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 7637382..c87010e 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -78,6 +78,10 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { const char *SemiError = 0; OwningStmtResult Res(Actions); + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + // Cases in this switch statement should fall through if the parser expects // the token to end in a semicolon (in which case SemiError should be set), // or they directly 'return;' if not. @@ -98,14 +102,15 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { case tok::identifier: if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement - return ParseLabeledStatement(); + return ParseLabeledStatement(Attr.AttrList); } // PASS THROUGH. default: { if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd); + DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd, + Attr); return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd); } @@ -114,6 +119,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { return StmtError(); } + // FIXME: Use the attributes // expression[opt] ';' OwningExprResult Expr(ParseExpression()); if (Expr.isInvalid()) { @@ -129,47 +135,50 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { } case tok::kw_case: // C99 6.8.1: labeled-statement - return ParseCaseStatement(); + return ParseCaseStatement(Attr.AttrList); case tok::kw_default: // C99 6.8.1: labeled-statement - return ParseDefaultStatement(); + return ParseDefaultStatement(Attr.AttrList); case tok::l_brace: // C99 6.8.2: compound-statement - return ParseCompoundStatement(); + return ParseCompoundStatement(Attr.AttrList); case tok::semi: // C99 6.8.3p3: expression[opt] ';' return Actions.ActOnNullStmt(ConsumeToken()); case tok::kw_if: // C99 6.8.4.1: if-statement - return ParseIfStatement(); + return ParseIfStatement(Attr.AttrList); case tok::kw_switch: // C99 6.8.4.2: switch-statement - return ParseSwitchStatement(); + return ParseSwitchStatement(Attr.AttrList); case tok::kw_while: // C99 6.8.5.1: while-statement - return ParseWhileStatement(); + return ParseWhileStatement(Attr.AttrList); case tok::kw_do: // C99 6.8.5.2: do-statement - Res = ParseDoStatement(); + Res = ParseDoStatement(Attr.AttrList); SemiError = "do/while"; break; case tok::kw_for: // C99 6.8.5.3: for-statement - return ParseForStatement(); + return ParseForStatement(Attr.AttrList); case tok::kw_goto: // C99 6.8.6.1: goto-statement - Res = ParseGotoStatement(); + Res = ParseGotoStatement(Attr.AttrList); SemiError = "goto"; break; case tok::kw_continue: // C99 6.8.6.2: continue-statement - Res = ParseContinueStatement(); + Res = ParseContinueStatement(Attr.AttrList); SemiError = "continue"; break; case tok::kw_break: // C99 6.8.6.3: break-statement - Res = ParseBreakStatement(); + Res = ParseBreakStatement(Attr.AttrList); SemiError = "break"; break; case tok::kw_return: // C99 6.8.6.4: return-statement - Res = ParseReturnStatement(); + Res = ParseReturnStatement(Attr.AttrList); SemiError = "return"; break; case tok::kw_asm: { + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; bool msAsm = false; Res = ParseAsmStatement(msAsm); if (msAsm) return move(Res); @@ -178,7 +187,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { } case tok::kw_try: // C++ 15: try-block - return ParseCXXTryBlock(); + return ParseCXXTryBlock(Attr.AttrList); } // If we reached this code, the statement must end in a semicolon. @@ -202,7 +211,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { /// identifier ':' statement /// [GNU] identifier ':' attributes[opt] statement /// -Parser::OwningStmtResult Parser::ParseLabeledStatement() { +Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && "Not an identifier!"); @@ -215,10 +224,8 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement() { SourceLocation ColonLoc = ConsumeToken(); // Read label attributes, if present. - Action::AttrTy *AttrList = 0; if (Tok.is(tok::kw___attribute)) - // TODO: save these somewhere. - AttrList = ParseAttributes(); + Attr = addAttributeLists(Attr, ParseGNUAttributes()); OwningStmtResult SubStmt(ParseStatement()); @@ -236,8 +243,9 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement() { /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// -Parser::OwningStmtResult Parser::ParseCaseStatement() { +Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { assert(Tok.is(tok::kw_case) && "Not a case stmt!"); + // FIXME: Use attributes? // It is very very common for code to contain many case statements recursively // nested, as in (but usually without indentation): @@ -354,7 +362,8 @@ Parser::OwningStmtResult Parser::ParseCaseStatement() { /// 'default' ':' statement /// Note that this does not parse the 'statement' at the end. /// -Parser::OwningStmtResult Parser::ParseDefaultStatement() { +Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) { + //FIXME: Use attributes? assert(Tok.is(tok::kw_default) && "Not a default stmt!"); SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. @@ -408,7 +417,9 @@ Parser::OwningStmtResult Parser::ParseDefaultStatement() { /// [OMP] barrier-directive /// [OMP] flush-directive /// -Parser::OwningStmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { +Parser::OwningStmtResult Parser::ParseCompoundStatement(AttributeList *Attr, + bool isStmtExpr) { + //FIXME: Use attributes? assert(Tok.is(tok::l_brace) && "Not a compount stmt!"); // Enter a scope to hold everything within the compound stmt. Compound @@ -449,6 +460,10 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { while (Tok.is(tok::kw___extension__)) ConsumeToken(); + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + // If this is the start of a declaration, parse it as such. if (isDeclarationStatement()) { // __extension__ silences extension warnings in the subdeclaration. @@ -456,7 +471,8 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { ExtensionRAIIObject O(Diags); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext,DeclEnd); + DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext, DeclEnd, + Attr); R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd); } else { // Otherwise this was a unary __extension__ marker. @@ -467,6 +483,7 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { continue; } + // 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); @@ -500,22 +517,22 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { /// should try to recover harder. It returns false if the condition is /// successfully parsed. Note that a successful parse can still have semantic /// errors in the condition. -bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp, - bool OnlyAllowCondition, - SourceLocation *LParenLocPtr, - SourceLocation *RParenLocPtr) { +bool Parser::ParseParenExprOrCondition(OwningExprResult &ExprResult, + DeclPtrTy &DeclResult) { + bool ParseError = false; + SourceLocation LParenLoc = ConsumeParen(); - if (LParenLocPtr) *LParenLocPtr = LParenLoc; - - if (getLang().CPlusPlus) - CondExp = ParseCXXCondition(); - else - CondExp = ParseExpression(); + if (getLang().CPlusPlus) + ParseError = ParseCXXCondition(ExprResult, DeclResult); + else { + ExprResult = ParseExpression(); + DeclResult = DeclPtrTy(); + } // If the parser was confused by the condition and we don't have a ')', try to // recover by skipping ahead to a semi and bailing out. If condexp is // semantically invalid but we have well formed code, keep going. - if (CondExp.isInvalid() && Tok.isNot(tok::r_paren)) { + if (ExprResult.isInvalid() && !DeclResult.get() && Tok.isNot(tok::r_paren)) { SkipUntil(tok::semi); // Skipping may have stopped if it found the containing ')'. If so, we can // continue parsing the if statement. @@ -524,8 +541,7 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp, } // Otherwise the condition is valid or the rparen is present. - SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - if (RParenLocPtr) *RParenLocPtr = RPLoc; + MatchRHSPunctuation(tok::r_paren, LParenLoc); return false; } @@ -537,7 +553,8 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp, /// [C++] 'if' '(' condition ')' statement /// [C++] 'if' '(' condition ')' statement 'else' statement /// -Parser::OwningStmtResult Parser::ParseIfStatement() { +Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_if) && "Not an if stmt!"); SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. @@ -565,7 +582,8 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { // Parse the condition. OwningExprResult CondExp(Actions); - if (ParseParenExprOrCondition(CondExp)) + DeclPtrTy CondVar; + if (ParseParenExprOrCondition(CondExp, CondVar)) return StmtError(); FullExprArg FullCondExp(Actions.FullExpr(CondExp)); @@ -632,7 +650,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { // If the condition was invalid, discard the if statement. We could recover // better by replacing it with a valid expr, but don't do that yet. - if (CondExp.isInvalid()) + if (CondExp.isInvalid() && !CondVar.get()) return StmtError(); // If the then or else stmt is invalid and the other is valid (and present), @@ -651,7 +669,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { if (ElseStmt.isInvalid()) ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); - return Actions.ActOnIfStmt(IfLoc, FullCondExp, move(ThenStmt), + return Actions.ActOnIfStmt(IfLoc, FullCondExp, CondVar, move(ThenStmt), ElseLoc, move(ElseStmt)); } @@ -659,7 +677,8 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { /// switch-statement: /// 'switch' '(' expression ')' statement /// [C++] 'switch' '(' condition ')' statement -Parser::OwningStmtResult Parser::ParseSwitchStatement() { +Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_switch) && "Not a switch stmt!"); SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'. @@ -690,12 +709,13 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() { // Parse the condition. OwningExprResult Cond(Actions); - if (ParseParenExprOrCondition(Cond)) + DeclPtrTy CondVar; + if (ParseParenExprOrCondition(Cond, CondVar)) return StmtError(); - OwningStmtResult Switch(Actions); - if (!Cond.isInvalid()) - Switch = Actions.ActOnStartOfSwitchStmt(move(Cond)); + FullExprArg FullCond(Actions.FullExpr(Cond)); + + OwningStmtResult Switch = Actions.ActOnStartOfSwitchStmt(FullCond, CondVar); // C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this @@ -724,7 +744,7 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() { SwitchScope.Exit(); - if (Cond.isInvalid()) + if (Cond.isInvalid() && !CondVar.get()) return StmtError(); return Actions.ActOnFinishSwitchStmt(SwitchLoc, move(Switch), move(Body)); @@ -734,7 +754,8 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() { /// while-statement: [C99 6.8.5.1] /// 'while' '(' expression ')' statement /// [C++] 'while' '(' condition ')' statement -Parser::OwningStmtResult Parser::ParseWhileStatement() { +Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_while) && "Not a while stmt!"); SourceLocation WhileLoc = Tok.getLocation(); ConsumeToken(); // eat the 'while'. @@ -769,7 +790,8 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() { // Parse the condition. OwningExprResult Cond(Actions); - if (ParseParenExprOrCondition(Cond)) + DeclPtrTy CondVar; + if (ParseParenExprOrCondition(Cond, CondVar)) return StmtError(); FullExprArg FullCond(Actions.FullExpr(Cond)); @@ -795,17 +817,18 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() { InnerScope.Exit(); WhileScope.Exit(); - if (Cond.isInvalid() || Body.isInvalid()) + if ((Cond.isInvalid() && !CondVar.get()) || Body.isInvalid()) return StmtError(); - return Actions.ActOnWhileStmt(WhileLoc, FullCond, move(Body)); + return Actions.ActOnWhileStmt(WhileLoc, FullCond, CondVar, move(Body)); } /// ParseDoStatement /// do-statement: [C99 6.8.5.2] /// 'do' statement 'while' '(' expression ')' ';' /// Note: this lets the caller parse the end ';'. -Parser::OwningStmtResult Parser::ParseDoStatement() { +Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_do) && "Not a do stmt!"); SourceLocation DoLoc = ConsumeToken(); // eat the 'do'. @@ -854,10 +877,9 @@ Parser::OwningStmtResult Parser::ParseDoStatement() { } // Parse the parenthesized condition. - OwningExprResult Cond(Actions); - SourceLocation LPLoc, RPLoc; - ParseParenExprOrCondition(Cond, true, &LPLoc, &RPLoc); - + SourceLocation LPLoc = ConsumeParen(); + OwningExprResult Cond = ParseExpression(); + SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LPLoc); DoScope.Exit(); if (Cond.isInvalid() || Body.isInvalid()) @@ -880,7 +902,8 @@ Parser::OwningStmtResult Parser::ParseDoStatement() { /// [C++] expression-statement /// [C++] simple-declaration /// -Parser::OwningStmtResult Parser::ParseForStatement() { +Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_for) && "Not a for stmt!"); SourceLocation ForLoc = ConsumeToken(); // eat the 'for'. @@ -922,7 +945,8 @@ Parser::OwningStmtResult Parser::ParseForStatement() { bool ForEach = false; OwningStmtResult FirstPart(Actions); OwningExprResult SecondPart(Actions), ThirdPart(Actions); - + DeclPtrTy SecondVar; + if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(CurScope); ConsumeToken(); @@ -937,13 +961,19 @@ Parser::OwningStmtResult Parser::ParseForStatement() { 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; + SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd); + DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd, + AttrList); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); if (Tok.is(tok::semi)) { // for (int x = 4; ConsumeToken(); } else if ((ForEach = isTokIdentifier_in())) { + Actions.ActOnForEachDeclStmt(DG); // ObjC: for (id x in expr) ConsumeToken(); // consume 'in' SecondPart = ParseExpression(); @@ -974,13 +1004,17 @@ Parser::OwningStmtResult Parser::ParseForStatement() { if (Tok.is(tok::semi)) { // for (...;; // no second part. } else { - SecondPart =getLang().CPlusPlus ? ParseCXXCondition() : ParseExpression(); + if (getLang().CPlusPlus) + ParseCXXCondition(SecondPart, SecondVar); + else + SecondPart = ParseExpression(); } if (Tok.is(tok::semi)) { ConsumeToken(); } else { - if (!SecondPart.isInvalid()) Diag(Tok, diag::err_expected_semi_for); + if (!SecondPart.isInvalid() || SecondVar.get()) + Diag(Tok, diag::err_expected_semi_for); SkipUntil(tok::semi); } @@ -1019,8 +1053,9 @@ Parser::OwningStmtResult Parser::ParseForStatement() { if (!ForEach) return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart), - move(SecondPart), move(ThirdPart), - RParenLoc, move(Body)); + Actions.FullExpr(SecondPart), SecondVar, + Actions.FullExpr(ThirdPart), RParenLoc, + move(Body)); return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, move(FirstPart), @@ -1035,7 +1070,8 @@ Parser::OwningStmtResult Parser::ParseForStatement() { /// /// Note: this lets the caller parse the end ';'. /// -Parser::OwningStmtResult Parser::ParseGotoStatement() { +Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_goto) && "Not a goto stmt!"); SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'. @@ -1068,7 +1104,8 @@ Parser::OwningStmtResult Parser::ParseGotoStatement() { /// /// Note: this lets the caller parse the end ';'. /// -Parser::OwningStmtResult Parser::ParseContinueStatement() { +Parser::OwningStmtResult Parser::ParseContinueStatement(AttributeList *Attr) { + // FIXME: Use attributes? SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'. return Actions.ActOnContinueStmt(ContinueLoc, CurScope); } @@ -1079,7 +1116,8 @@ Parser::OwningStmtResult Parser::ParseContinueStatement() { /// /// Note: this lets the caller parse the end ';'. /// -Parser::OwningStmtResult Parser::ParseBreakStatement() { +Parser::OwningStmtResult Parser::ParseBreakStatement(AttributeList *Attr) { + // FIXME: Use attributes? SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. return Actions.ActOnBreakStmt(BreakLoc, CurScope); } @@ -1087,7 +1125,8 @@ Parser::OwningStmtResult Parser::ParseBreakStatement() { /// ParseReturnStatement /// jump-statement: /// 'return' expression[opt] ';' -Parser::OwningStmtResult Parser::ParseReturnStatement() { +Parser::OwningStmtResult Parser::ParseReturnStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_return) && "Not a return stmt!"); SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'. @@ -1163,7 +1202,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { } DeclSpec DS; SourceLocation Loc = Tok.getLocation(); - ParseTypeQualifierListOpt(DS); + ParseTypeQualifierListOpt(DS, true, false); // GNU asms accept, but warn, about type-qualifiers other than volatile. if (DS.getTypeQualifiers() & DeclSpec::TQ_const) @@ -1371,7 +1410,8 @@ Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) { /// try-block: /// 'try' compound-statement handler-seq /// -Parser::OwningStmtResult Parser::ParseCXXTryBlock() { +Parser::OwningStmtResult Parser::ParseCXXTryBlock(AttributeList* Attr) { + // FIXME: Add attributes? assert(Tok.is(tok::kw_try) && "Expected 'try'"); SourceLocation TryLoc = ConsumeToken(); @@ -1393,11 +1433,17 @@ Parser::OwningStmtResult Parser::ParseCXXTryBlock() { Parser::OwningStmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); - OwningStmtResult TryBlock(ParseCompoundStatement()); + // FIXME: Possible draft standard bug: attribute-specifier should be allowed? + OwningStmtResult TryBlock(ParseCompoundStatement(0)); 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; + } if (Tok.isNot(tok::kw_catch)) return StmtError(Diag(Tok, diag::err_expected_catch)); while (Tok.is(tok::kw_catch)) { @@ -1457,7 +1503,8 @@ Parser::OwningStmtResult Parser::ParseCXXCatchBlock() { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); - OwningStmtResult Block(ParseCompoundStatement()); + // FIXME: Possible draft standard bug: attribute-specifier should be allowed? + OwningStmtResult Block(ParseCompoundStatement(0)); if (Block.isInvalid()) return move(Block); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 16b1c80..0dbf37c 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -16,7 +16,6 @@ #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" #include "clang/Parse/Template.h" -#include "llvm/Support/Compiler.h" using namespace clang; /// \brief Parse a template declaration, explicit instantiation, or @@ -34,7 +33,7 @@ Parser::ParseDeclarationStartingWithTemplate(unsigned Context, /// \brief RAII class that manages the template parameter depth. namespace { - class VISIBILITY_HIDDEN TemplateParameterDepthCounter { + class TemplateParameterDepthCounter { unsigned &Depth; unsigned AddedLevels; @@ -192,6 +191,10 @@ Parser::ParseSingleDeclarationAfterTemplate( // Parse the declaration specifiers. ParsingDeclSpec DS(*this); + + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + DS.AddAttributes(ParseCXX0XAttributes().AttrList); + ParseDeclarationSpecifiers(DS, TemplateInfo, AS); if (Tok.is(tok::semi)) { @@ -333,6 +336,40 @@ Parser::ParseTemplateParameterList(unsigned Depth, return true; } +/// \brief Determine whether the parser is at the start of a template +/// type parameter. +bool Parser::isStartOfTemplateTypeParameter() { + if (Tok.is(tok::kw_class)) + return true; + + if (Tok.isNot(tok::kw_typename)) + return false; + + // C++ [temp.param]p2: + // There is no semantic difference between class and typename in a + // template-parameter. typename followed by an unqualified-id + // names a template type parameter. typename followed by a + // qualified-id denotes the type in a non-type + // parameter-declaration. + Token Next = NextToken(); + + // If we have an identifier, skip over it. + if (Next.getKind() == tok::identifier) + Next = GetLookAheadToken(2); + + switch (Next.getKind()) { + case tok::equal: + case tok::comma: + case tok::greater: + case tok::greatergreater: + case tok::ellipsis: + return true; + + default: + return false; + } +} + /// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]). /// /// template-parameter: [C++ temp.param] @@ -348,12 +385,8 @@ Parser::ParseTemplateParameterList(unsigned Depth, /// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression Parser::DeclPtrTy Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { - if (Tok.is(tok::kw_class) || - (Tok.is(tok::kw_typename) && - // FIXME: Next token has not been annotated! - NextToken().isNot(tok::annot_typename))) { + if (isStartOfTemplateTypeParameter()) return ParseTypeParameter(Depth, Position); - } if (Tok.is(tok::kw_template)) return ParseTemplateTemplateParameter(Depth, Position); @@ -851,7 +884,8 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { if (isEndOfTemplateArgument(Tok)) { TemplateTy Template = Actions.ActOnDependentTemplateName(TemplateLoc, SS, Name, - /*ObjectType=*/0); + /*ObjectType=*/0, + /*EnteringContext=*/false); if (Template.get()) return ParsedTemplateArgument(SS, Template, Name.StartLocation); } diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 7ac2977..dabd065 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -55,12 +55,11 @@ bool Parser::isCXXDeclarationStatement() { // using-declaration // using-directive case tok::kw_using: - return true; - case tok::kw_static_assert: // static_assert-declaration + case tok::kw_static_assert: return true; - default: // simple-declaration + default: return isCXXSimpleDeclaration(); } } @@ -351,6 +350,89 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { return TPR == TPResult::True(); } +/// isCXX0XAttributeSpecifier - returns true if this is a C++0x +/// attribute-specifier. By default, unless in Obj-C++, only a cursory check is +/// performed that will simply return true if a [[ is seen. Currently C++ has no +/// syntactical ambiguities from this check, but it may inhibit error recovery. +/// If CheckClosing is true, a check is made for closing ]] brackets. +/// +/// If given, After is set to the token after the attribute-specifier so that +/// appropriate parsing decisions can be made; it is left untouched if false is +/// returned. +/// +/// FIXME: If an error is in the closing ]] brackets, the program assumes +/// the absence of an attribute-specifier, which can cause very yucky errors +/// to occur. +/// +/// [C++0x] attribute-specifier: +/// '[' '[' attribute-list ']' ']' +/// +/// [C++0x] attribute-list: +/// attribute[opt] +/// attribute-list ',' attribute[opt] +/// +/// [C++0x] attribute: +/// attribute-token attribute-argument-clause[opt] +/// +/// [C++0x] attribute-token: +/// identifier +/// attribute-scoped-token +/// +/// [C++0x] attribute-scoped-token: +/// attribute-namespace '::' identifier +/// +/// [C++0x] attribute-namespace: +/// identifier +/// +/// [C++0x] attribute-argument-clause: +/// '(' balanced-token-seq ')' +/// +/// [C++0x] balanced-token-seq: +/// balanced-token +/// balanced-token-seq balanced-token +/// +/// [C++0x] balanced-token: +/// '(' balanced-token-seq ')' +/// '[' balanced-token-seq ']' +/// '{' balanced-token-seq '}' +/// any token but '(', ')', '[', ']', '{', or '}' +bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing, + tok::TokenKind *After) { + if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) + return false; + + // No tentative parsing if we don't need to look for ]] + if (!CheckClosing && !getLang().ObjC1) + return true; + + struct TentativeReverter { + TentativeParsingAction PA; + + TentativeReverter (Parser& P) + : PA(P) + {} + ~TentativeReverter () { + PA.Revert(); + } + } R(*this); + + // Opening brackets were checked for above. + ConsumeBracket(); + ConsumeBracket(); + + // SkipUntil will handle balanced tokens, which are guaranteed in attributes. + SkipUntil(tok::r_square, false); + + if (Tok.isNot(tok::r_square)) + return false; + ConsumeBracket(); + + if (After) + *After = Tok.getKind(); + + return true; +} + /// declarator: /// direct-declarator /// ptr-operator declarator diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index a915274..e321564 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -355,7 +355,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { return true; } - Result = ParseExternalDeclaration(); + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + Result = ParseExternalDeclaration(Attr); return false; } @@ -396,7 +399,7 @@ void Parser::ParseTranslationUnit() { /// ';' /// /// [C++0x/GNU] 'extern' 'template' declaration -Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { +Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) { DeclPtrTy SingleDecl; switch (Tok.getKind()) { case tok::semi: @@ -418,9 +421,13 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); - return ParseExternalDeclaration(); + return ParseExternalDeclaration(Attr); } case tok::kw_asm: { + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + OwningExprResult Result(ParseSimpleAsm()); ExpectAndConsume(tok::semi, diag::err_expected_semi_after, @@ -449,7 +456,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { case tok::code_completion: Actions.CodeCompleteOrdinaryName(CurScope); ConsumeToken(); - return ParseExternalDeclaration(); + return ParseExternalDeclaration(Attr); case tok::kw_using: case tok::kw_namespace: case tok::kw_typedef: @@ -459,7 +466,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { // A function definition cannot start with a these keywords. { SourceLocation DeclEnd; - return ParseDeclaration(Declarator::FileContext, DeclEnd); + return ParseDeclaration(Declarator::FileContext, DeclEnd, Attr); } case tok::kw_extern: if (getLang().CPlusPlus && NextToken().is(tok::kw_template)) { @@ -477,7 +484,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { default: // We can't tell whether this is a function-definition or declaration yet. - return ParseDeclarationOrFunctionDefinition(); + return ParseDeclarationOrFunctionDefinition(Attr.AttrList); } // This routine returns a DeclGroup, if the thing we parsed only contains a @@ -525,9 +532,13 @@ bool Parser::isStartOfFunctionDefinition() { /// [OMP] threadprivate-directive [TODO] /// Parser::DeclGroupPtrTy -Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { +Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr, + AccessSpecifier AS) { // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); + if (Attr) + DS.AddAttributes(Attr); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" @@ -719,7 +730,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { // If attributes are present, parse them. if (Tok.is(tok::kw___attribute)) // FIXME: attach attributes too. - AttrList = ParseAttributes(); + AttrList = ParseGNUAttributes(); // Ask the actions module to compute the type for this declarator. Action::DeclPtrTy Param = |