diff options
Diffstat (limited to 'lib/Parse/ParseDecl.cpp')
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 1611 |
1 files changed, 837 insertions, 774 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 7b8093408bfd..62d43768bff4 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -13,10 +13,12 @@ #include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/Attributes.h" #include "clang/Basic/CharInfo.h" -#include "clang/Basic/OpenCL.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" @@ -51,7 +53,7 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, DS.addAttributes(Attrs->getList()); ParseSpecifierQualifierList(DS, AS, DSC); if (OwnedType) - *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0; + *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : nullptr; // Parse the abstract-declarator, if present. Declarator DeclaratorInfo(DS, Context); @@ -69,9 +71,11 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, /// isAttributeLateParsed - Return true if the attribute has arguments that /// require late parsing. static bool isAttributeLateParsed(const IdentifierInfo &II) { +#define CLANG_ATTR_LATE_PARSED_LIST return llvm::StringSwitch<bool>(II.getName()) -#include "clang/Parse/AttrLateParsed.inc" +#include "clang/Parse/AttrParserStringSwitches.inc" .Default(false); +#undef CLANG_ATTR_LATE_PARSED_LIST } /// ParseGNUAttributes - Parse a non-empty attributes list. @@ -117,7 +121,8 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) { /// We follow the C++ model, but don't allow junk after the identifier. void Parser::ParseGNUAttributes(ParsedAttributes &attrs, SourceLocation *endLoc, - LateParsedAttrList *LateAttrs) { + LateParsedAttrList *LateAttrs, + Declarator *D) { assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); while (Tok.is(tok::kw___attribute)) { @@ -132,49 +137,54 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, return; } // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") )) - while (Tok.is(tok::identifier) || isDeclarationSpecifier() || - Tok.is(tok::comma)) { - if (Tok.is(tok::comma)) { - // allows for empty/non-empty attributes. ((__vector_size__(16),,,,)) - ConsumeToken(); + while (true) { + // Allow empty/non-empty attributes. ((__vector_size__(16),,,,)) + if (TryConsumeToken(tok::comma)) continue; - } - // we have an identifier or declaration specifier (const, int, etc.) + + // Expect an identifier or declaration specifier (const, int, etc.) + if (Tok.isNot(tok::identifier) && !isDeclarationSpecifier()) + break; + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - if (Tok.is(tok::l_paren)) { - // handle "parameterized" attributes - if (LateAttrs && isAttributeLateParsed(*AttrName)) { - LateParsedAttribute *LA = - new LateParsedAttribute(this, *AttrName, AttrNameLoc); - LateAttrs->push_back(LA); - - // Attributes in a class are parsed at the end of the class, along - // with other late-parsed declarations. - if (!ClassStack.empty() && !LateAttrs->parseSoon()) - getCurrentClass().LateParsedDeclarations.push_back(LA); - - // consume everything up to and including the matching right parens - ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false); - - Token Eof; - Eof.startToken(); - Eof.setLocation(Tok.getLocation()); - LA->Toks.push_back(Eof); - } else { - ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc, - 0, SourceLocation(), AttributeList::AS_GNU); - } - } else { - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + if (Tok.isNot(tok::l_paren)) { + attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, AttributeList::AS_GNU); + continue; + } + + // Handle "parameterized" attributes + if (!LateAttrs || !isAttributeLateParsed(*AttrName)) { + ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc, nullptr, + SourceLocation(), AttributeList::AS_GNU, D); + continue; } + + // Handle attributes with arguments that require late parsing. + LateParsedAttribute *LA = + new LateParsedAttribute(this, *AttrName, AttrNameLoc); + LateAttrs->push_back(LA); + + // Attributes in a class are parsed at the end of the class, along + // with other late-parsed declarations. + if (!ClassStack.empty() && !LateAttrs->parseSoon()) + getCurrentClass().LateParsedDeclarations.push_back(LA); + + // consume everything up to and including the matching right parens + ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false); + + Token Eof; + Eof.startToken(); + Eof.setLocation(Tok.getLocation()); + LA->Toks.push_back(Eof); } - if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) + + if (ExpectAndConsume(tok::r_paren)) SkipUntil(tok::r_paren, StopAtSemi); SourceLocation Loc = Tok.getLocation(); - if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) + if (ExpectAndConsume(tok::r_paren)) SkipUntil(tok::r_paren, StopAtSemi); if (endLoc) *endLoc = Loc; @@ -190,16 +200,30 @@ static StringRef normalizeAttrName(StringRef Name) { /// \brief Determine whether the given attribute has an identifier argument. static bool attributeHasIdentifierArg(const IdentifierInfo &II) { +#define CLANG_ATTR_IDENTIFIER_ARG_LIST return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) -#include "clang/Parse/AttrIdentifierArg.inc" +#include "clang/Parse/AttrParserStringSwitches.inc" .Default(false); +#undef CLANG_ATTR_IDENTIFIER_ARG_LIST } /// \brief Determine whether the given attribute parses a type argument. static bool attributeIsTypeArgAttr(const IdentifierInfo &II) { +#define CLANG_ATTR_TYPE_ARG_LIST + return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrParserStringSwitches.inc" + .Default(false); +#undef CLANG_ATTR_TYPE_ARG_LIST +} + +/// \brief Determine whether the given attribute requires parsing its arguments +/// in an unevaluated context or not. +static bool attributeParsedArgsUnevaluated(const IdentifierInfo &II) { +#define CLANG_ATTR_ARG_CONTEXT_LIST return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) -#include "clang/Parse/AttrTypeArg.inc" +#include "clang/Parse/AttrParserStringSwitches.inc" .Default(false); +#undef CLANG_ATTR_ARG_CONTEXT_LIST } IdentifierLoc *Parser::ParseIdentifierLoc() { @@ -214,7 +238,10 @@ IdentifierLoc *Parser::ParseIdentifierLoc() { void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, - SourceLocation *EndLoc) { + SourceLocation *EndLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + AttributeList::Syntax Syntax) { BalancedDelimiterTracker Parens(*this, tok::l_paren); Parens.consumeOpen(); @@ -230,61 +257,26 @@ void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName, if (T.isUsable()) Attrs.addNewTypeAttr(&AttrName, - SourceRange(AttrNameLoc, Parens.getCloseLocation()), 0, - AttrNameLoc, T.get(), AttributeList::AS_GNU); + SourceRange(AttrNameLoc, Parens.getCloseLocation()), + ScopeName, ScopeLoc, T.get(), Syntax); else Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()), - 0, AttrNameLoc, 0, 0, AttributeList::AS_GNU); + ScopeName, ScopeLoc, nullptr, 0, Syntax); } -/// Parse the arguments to a parameterized GNU attribute or -/// a C++11 attribute in "gnu" namespace. -void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, - SourceLocation AttrNameLoc, - ParsedAttributes &Attrs, - SourceLocation *EndLoc, - IdentifierInfo *ScopeName, - SourceLocation ScopeLoc, - AttributeList::Syntax Syntax) { - - assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); - - AttributeList::Kind AttrKind = - AttributeList::getKind(AttrName, ScopeName, Syntax); - - // Availability attributes have their own grammar. - // FIXME: All these cases fail to pass in the syntax and scope, and might be - // written as C++11 gnu:: attributes. - if (AttrKind == AttributeList::AT_Availability) { - ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); - return; - } - // Thread safety attributes are parsed in an unevaluated context. - // FIXME: Share the bulk of the parsing code here and just pull out - // the unevaluated context. - if (IsThreadSafetyAttribute(AttrName->getName())) { - ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); - return; - } - // Type safety attributes have their own grammar. - if (AttrKind == AttributeList::AT_TypeTagForDatatype) { - ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); - return; - } - // Some attributes expect solely a type parameter. - if (attributeIsTypeArgAttr(*AttrName)) { - ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, EndLoc); - return; - } - +unsigned Parser::ParseAttributeArgsCommon( + IdentifierInfo *AttrName, SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, AttributeList::Syntax Syntax) { // Ignore the left paren location for now. ConsumeParen(); ArgsVector ArgExprs; - if (Tok.is(tok::identifier)) { // If this attribute wants an 'identifier' argument, make it so. bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName); + AttributeList::Kind AttrKind = + AttributeList::getKind(AttrName, ScopeName, Syntax); // If we don't know how to parse this attribute, but this is the only // token in this argument, assume it's meant to be an identifier. @@ -304,112 +296,117 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, ConsumeToken(); // Parse the non-empty comma-separated list of expressions. - while (1) { + do { + std::unique_ptr<EnterExpressionEvaluationContext> Unevaluated; + if (attributeParsedArgsUnevaluated(*AttrName)) + Unevaluated.reset( + new EnterExpressionEvaluationContext(Actions, Sema::Unevaluated)); + ExprResult ArgExpr(ParseAssignmentExpression()); if (ArgExpr.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); - return; + return 0; } - ArgExprs.push_back(ArgExpr.release()); - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); // Eat the comma, move to the next argument - } + ArgExprs.push_back(ArgExpr.get()); + // Eat the comma, move to the next argument + } while (TryConsumeToken(tok::comma)); } SourceLocation RParen = Tok.getLocation(); - if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { + if (!ExpectAndConsume(tok::r_paren)) { SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc; Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, ArgExprs.data(), ArgExprs.size(), Syntax); } + + if (EndLoc) + *EndLoc = RParen; + + return static_cast<unsigned>(ArgExprs.size()); } -/// \brief Parses a single argument for a declspec, including the -/// surrounding parens. -void Parser::ParseMicrosoftDeclSpecWithSingleArg(IdentifierInfo *AttrName, - SourceLocation AttrNameLoc, - ParsedAttributes &Attrs) -{ - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, - AttrName->getNameStart(), tok::r_paren)) - return; +/// Parse the arguments to a parameterized GNU attribute or +/// a C++11 attribute in "gnu" namespace. +void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + AttributeList::Syntax Syntax, + Declarator *D) { - ExprResult ArgExpr(ParseConstantExpression()); - if (ArgExpr.isInvalid()) { - T.skipToEnd(); + assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); + + AttributeList::Kind AttrKind = + AttributeList::getKind(AttrName, ScopeName, Syntax); + + if (AttrKind == AttributeList::AT_Availability) { + ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, + ScopeLoc, Syntax); + return; + } else if (AttrKind == AttributeList::AT_ObjCBridgeRelated) { + ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, + ScopeName, ScopeLoc, Syntax); + return; + } else if (AttrKind == AttributeList::AT_TypeTagForDatatype) { + ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, + ScopeName, ScopeLoc, Syntax); + return; + } else if (attributeIsTypeArgAttr(*AttrName)) { + ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, + ScopeLoc, Syntax); return; } - ArgsUnion ExprList = ArgExpr.take(); - Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, &ExprList, 1, - AttributeList::AS_Declspec); - T.consumeClose(); -} + // These may refer to the function arguments, but need to be parsed early to + // participate in determining whether it's a redeclaration. + std::unique_ptr<ParseScope> PrototypeScope; + if (AttrName->isStr("enable_if") && D && D->isFunctionDeclarator()) { + DeclaratorChunk::FunctionTypeInfo FTI = D->getFunctionTypeInfo(); + PrototypeScope.reset(new ParseScope(this, Scope::FunctionPrototypeScope | + Scope::FunctionDeclarationScope | + Scope::DeclScope)); + for (unsigned i = 0; i != FTI.NumParams; ++i) { + ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param); + Actions.ActOnReenterCXXMethodParameter(getCurScope(), Param); + } + } -/// \brief Determines whether a declspec is a "simple" one requiring no -/// arguments. -bool Parser::IsSimpleMicrosoftDeclSpec(IdentifierInfo *Ident) { - return llvm::StringSwitch<bool>(Ident->getName()) - .Case("dllimport", true) - .Case("dllexport", true) - .Case("noreturn", true) - .Case("nothrow", true) - .Case("noinline", true) - .Case("naked", true) - .Case("appdomain", true) - .Case("process", true) - .Case("jitintrinsic", true) - .Case("noalias", true) - .Case("restrict", true) - .Case("novtable", true) - .Case("selectany", true) - .Case("thread", true) - .Case("safebuffers", true ) - .Default(false); + ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, + ScopeLoc, Syntax); } -/// \brief Attempts to parse a declspec which is not simple (one that takes -/// parameters). Will return false if we properly handled the declspec, or -/// true if it is an unknown declspec. -void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, - SourceLocation Loc, - ParsedAttributes &Attrs) { - // Try to handle the easy case first -- these declspecs all take a single - // parameter as their argument. - if (llvm::StringSwitch<bool>(Ident->getName()) - .Case("uuid", true) - .Case("align", true) - .Case("allocate", true) - .Default(false)) { - ParseMicrosoftDeclSpecWithSingleArg(Ident, Loc, Attrs); - } else if (Ident->getName() == "deprecated") { - // The deprecated declspec has an optional single argument, so we will - // check for a l-paren to decide whether we should parse an argument or - // not. - if (Tok.getKind() == tok::l_paren) - ParseMicrosoftDeclSpecWithSingleArg(Ident, Loc, Attrs); - else - Attrs.addNew(Ident, Loc, 0, Loc, 0, 0, AttributeList::AS_Declspec); - } else if (Ident->getName() == "property") { +bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs) { + // If the attribute isn't known, we will not attempt to parse any + // arguments. + if (!hasAttribute(AttrSyntax::Declspec, nullptr, AttrName, + getTargetInfo().getTriple(), getLangOpts())) { + // Eat the left paren, then skip to the ending right paren. + ConsumeParen(); + SkipUntil(tok::r_paren); + return false; + } + + SourceLocation OpenParenLoc = Tok.getLocation(); + + if (AttrName->getName() == "property") { // The property declspec is more complex in that it can take one or two // assignment expressions as a parameter, but the lhs of the assignment // must be named get or put. - if (Tok.isNot(tok::l_paren)) { - Diag(Tok.getLocation(), diag::err_expected_lparen_after) - << Ident->getNameStart(); - return; - } + BalancedDelimiterTracker T(*this, tok::l_paren); T.expectAndConsume(diag::err_expected_lparen_after, - Ident->getNameStart(), tok::r_paren); + AttrName->getNameStart(), tok::r_paren); enum AccessorKind { AK_Invalid = -1, - AK_Put = 0, AK_Get = 1 // indices into AccessorNames + AK_Put = 0, + AK_Get = 1 // indices into AccessorNames }; - IdentifierInfo *AccessorNames[] = { 0, 0 }; + IdentifierInfo *AccessorNames[] = {nullptr, nullptr}; bool HasInvalidAccessor = false; // Parse the accessor specifications. @@ -418,8 +415,9 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, if (!Tok.is(tok::identifier)) { // If the user wrote a completely empty list, use a special diagnostic. if (Tok.is(tok::r_paren) && !HasInvalidAccessor && - AccessorNames[AK_Put] == 0 && AccessorNames[AK_Get] == 0) { - Diag(Loc, diag::err_ms_property_no_getter_or_putter); + AccessorNames[AK_Put] == nullptr && + AccessorNames[AK_Get] == nullptr) { + Diag(AttrNameLoc, diag::err_ms_property_no_getter_or_putter); break; } @@ -435,39 +433,38 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, } else if (KindStr == "put") { Kind = AK_Put; - // Recover from the common mistake of using 'set' instead of 'put'. + // Recover from the common mistake of using 'set' instead of 'put'. } else if (KindStr == "set") { Diag(KindLoc, diag::err_ms_property_has_set_accessor) - << FixItHint::CreateReplacement(KindLoc, "put"); + << FixItHint::CreateReplacement(KindLoc, "put"); Kind = AK_Put; - // Handle the mistake of forgetting the accessor kind by skipping - // this accessor. + // Handle the mistake of forgetting the accessor kind by skipping + // this accessor. } else if (NextToken().is(tok::comma) || NextToken().is(tok::r_paren)) { Diag(KindLoc, diag::err_ms_property_missing_accessor_kind); ConsumeToken(); HasInvalidAccessor = true; goto next_property_accessor; - // Otherwise, complain about the unknown accessor kind. + // Otherwise, complain about the unknown accessor kind. } else { Diag(KindLoc, diag::err_ms_property_unknown_accessor); HasInvalidAccessor = true; Kind = AK_Invalid; // Try to keep parsing unless it doesn't look like an accessor spec. - if (!NextToken().is(tok::equal)) break; + if (!NextToken().is(tok::equal)) + break; } // Consume the identifier. ConsumeToken(); // Consume the '='. - if (Tok.is(tok::equal)) { - ConsumeToken(); - } else { + if (!TryConsumeToken(tok::equal)) { Diag(Tok.getLocation(), diag::err_ms_property_expected_equal) - << KindStr; + << KindStr; break; } @@ -479,7 +476,7 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, if (Kind == AK_Invalid) { // Just drop invalid accessors. - } else if (AccessorNames[Kind] != NULL) { + } else if (AccessorNames[Kind] != nullptr) { // Complain about the repeated accessor, ignore it, and keep parsing. Diag(KindLoc, diag::err_ms_property_duplicate_accessor) << KindStr; } else { @@ -489,41 +486,38 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, next_property_accessor: // Keep processing accessors until we run out. - if (Tok.is(tok::comma)) { - ConsumeAnyToken(); + if (TryConsumeToken(tok::comma)) continue; // If we run into the ')', stop without consuming it. - } else if (Tok.is(tok::r_paren)) { + if (Tok.is(tok::r_paren)) break; - } else { - Diag(Tok.getLocation(), diag::err_ms_property_expected_comma_or_rparen); - break; - } + + Diag(Tok.getLocation(), diag::err_ms_property_expected_comma_or_rparen); + break; } // Only add the property attribute if it was well-formed. - if (!HasInvalidAccessor) { - Attrs.addNewPropertyAttr(Ident, Loc, 0, SourceLocation(), + if (!HasInvalidAccessor) + Attrs.addNewPropertyAttr(AttrName, AttrNameLoc, nullptr, SourceLocation(), AccessorNames[AK_Get], AccessorNames[AK_Put], AttributeList::AS_Declspec); - } T.skipToEnd(); - } else { - // We don't recognize this as a valid declspec, but instead of creating the - // attribute and allowing sema to warn about it, we will warn here instead. - // This is because some attributes have multiple spellings, but we need to - // disallow that for declspecs (such as align vs aligned). If we made the - // attribute, we'd have to split the valid declspec spelling logic into - // both locations. - Diag(Loc, diag::warn_ms_declspec_unknown) << Ident; - - // If there's an open paren, we should eat the open and close parens under - // the assumption that this unknown declspec has parameters. - BalancedDelimiterTracker T(*this, tok::l_paren); - if (!T.consumeOpen()) - T.skipToEnd(); + return !HasInvalidAccessor; } + + unsigned NumArgs = + ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, nullptr, nullptr, + SourceLocation(), AttributeList::AS_Declspec); + + // If this attribute's args were parsed, and it was expected to have + // arguments but none were provided, emit a diagnostic. + const AttributeList *Attr = Attrs.getList(); + if (Attr && Attr->getMaxArgs() && !NumArgs) { + Diag(OpenParenLoc, diag::err_attribute_requires_arguments) << AttrName; + return false; + } + return true; } /// [MS] decl-specifier: @@ -543,7 +537,11 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &Attrs) { // An empty declspec is perfectly legal and should not warn. Additionally, // you can specify multiple attributes per declspec. - while (Tok.getKind() != tok::r_paren) { + while (Tok.isNot(tok::r_paren)) { + // Attribute not present. + if (TryConsumeToken(tok::comma)) + continue; + // We expect either a well-known identifier or a generic string. Anything // else is a malformed declspec. bool IsString = Tok.getKind() == tok::string_literal ? true : false; @@ -571,17 +569,19 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &Attrs) { AttrNameLoc = ConsumeToken(); } - if (IsString || IsSimpleMicrosoftDeclSpec(AttrName)) - // If we have a generic string, we will allow it because there is no - // documented list of allowable string declspecs, but we know they exist - // (for instance, SAL declspecs in older versions of MSVC). - // - // Alternatively, if the identifier is a simple one, then it requires no - // arguments and can be turned into an attribute directly. - Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + bool AttrHandled = false; + + // Parse attribute arguments. + if (Tok.is(tok::l_paren)) + AttrHandled = ParseMicrosoftDeclSpecArgs(AttrName, AttrNameLoc, Attrs); + else if (AttrName->getName() == "property") + // The property attribute must have an argument list. + Diag(Tok.getLocation(), diag::err_expected_lparen_after) + << AttrName->getName(); + + if (!AttrHandled) + Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, AttributeList::AS_Declspec); - else - ParseComplexMicrosoftDeclSpec(AttrName, AttrNameLoc, Attrs); } T.consumeClose(); } @@ -595,7 +595,7 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { Tok.is(tok::kw___sptr) || Tok.is(tok::kw___uptr)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, AttributeList::AS_Keyword); } } @@ -605,7 +605,7 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___pascal)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, AttributeList::AS_Keyword); } } @@ -615,61 +615,16 @@ void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___kernel)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, AttributeList::AS_Keyword); } } -void Parser::ParseOpenCLQualifiers(DeclSpec &DS) { - // FIXME: The mapping from attribute spelling to semantics should be - // performed in Sema, not here. - SourceLocation Loc = Tok.getLocation(); - switch(Tok.getKind()) { - // OpenCL qualifiers: - case tok::kw___private: - case tok::kw_private: - DS.getAttributes().addNewInteger( - Actions.getASTContext(), - PP.getIdentifierInfo("address_space"), Loc, 0); - break; - - case tok::kw___global: - DS.getAttributes().addNewInteger( - Actions.getASTContext(), - PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_global); - break; - - case tok::kw___local: - DS.getAttributes().addNewInteger( - Actions.getASTContext(), - PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_local); - break; - - case tok::kw___constant: - DS.getAttributes().addNewInteger( - Actions.getASTContext(), - PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_constant); - break; - - case tok::kw___read_only: - DS.getAttributes().addNewInteger( - Actions.getASTContext(), - PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_only); - break; - - case tok::kw___write_only: - DS.getAttributes().addNewInteger( - Actions.getASTContext(), - PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_write_only); - break; - - case tok::kw___read_write: - DS.getAttributes().addNewInteger( - Actions.getASTContext(), - PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_write); - break; - default: break; - } +void Parser::ParseOpenCLQualifiers(ParsedAttributes &Attrs) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = Tok.getLocation(); + Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + AttributeList::AS_Keyword); } /// \brief Parse a version number. @@ -804,7 +759,10 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, SourceLocation AvailabilityLoc, ParsedAttributes &attrs, - SourceLocation *endLoc) { + SourceLocation *endLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + AttributeList::Syntax Syntax) { enum { Introduced, Deprecated, Obsoleted, Unknown }; AvailabilityChange Changes[Unknown]; ExprResult MessageExpr; @@ -812,7 +770,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, // Opening '('. BalancedDelimiterTracker T(*this, tok::l_paren); if (T.consumeOpen()) { - Diag(Tok, diag::err_expected_lparen); + Diag(Tok, diag::err_expected) << tok::l_paren; return; } @@ -825,8 +783,10 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, IdentifierLoc *Platform = ParseIdentifierLoc(); // Parse the ',' following the platform name. - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::r_paren)) + if (ExpectAndConsume(tok::comma)) { + SkipUntil(tok::r_paren, StopAtSemi); return; + } // If we haven't grabbed the pointers for the identifiers // "introduced", "deprecated", and "obsoleted", do so now. @@ -855,29 +815,34 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, << Keyword << SourceRange(UnavailableLoc); } UnavailableLoc = KeywordLoc; - - if (Tok.isNot(tok::comma)) - break; - - ConsumeToken(); continue; } if (Tok.isNot(tok::equal)) { - Diag(Tok, diag::err_expected_equal_after) - << Keyword; + Diag(Tok, diag::err_expected_after) << Keyword << tok::equal; SkipUntil(tok::r_paren, StopAtSemi); return; } ConsumeToken(); if (Keyword == Ident_message) { - if (Tok.isNot(tok::string_literal)) { // Also reject wide string literals. + if (Tok.isNot(tok::string_literal)) { Diag(Tok, diag::err_expected_string_literal) << /*Source='availability attribute'*/2; SkipUntil(tok::r_paren, StopAtSemi); return; } MessageExpr = ParseStringLiteralExpression(); + // Also reject wide string literals. + if (StringLiteral *MessageStringLiteral = + cast_or_null<StringLiteral>(MessageExpr.get())) { + if (MessageStringLiteral->getCharByteWidth() != 1) { + Diag(MessageStringLiteral->getSourceRange().getBegin(), + diag::err_expected_string_literal) + << /*Source='availability attribute'*/ 2; + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + } break; } @@ -915,11 +880,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, << Keyword << VersionRange; } - if (Tok.isNot(tok::comma)) - break; - - ConsumeToken(); - } while (true); + } while (TryConsumeToken(tok::comma)); // Closing ')'. if (T.consumeClose()) @@ -950,15 +911,97 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, // Record this attribute attrs.addNew(&Availability, SourceRange(AvailabilityLoc, T.getCloseLocation()), - 0, AvailabilityLoc, + ScopeName, ScopeLoc, Platform, Changes[Introduced], Changes[Deprecated], Changes[Obsoleted], - UnavailableLoc, MessageExpr.take(), - AttributeList::AS_GNU); + UnavailableLoc, MessageExpr.get(), + Syntax); } +/// \brief Parse the contents of the "objc_bridge_related" attribute. +/// objc_bridge_related '(' related_class ',' opt-class_method ',' opt-instance_method ')' +/// related_class: +/// Identifier +/// +/// opt-class_method: +/// Identifier: | <empty> +/// +/// opt-instance_method: +/// Identifier | <empty> +/// +void Parser::ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated, + SourceLocation ObjCBridgeRelatedLoc, + ParsedAttributes &attrs, + SourceLocation *endLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + AttributeList::Syntax Syntax) { + // Opening '('. + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { + Diag(Tok, diag::err_expected) << tok::l_paren; + return; + } + + // Parse the related class name. + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_objcbridge_related_expected_related_class); + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + IdentifierLoc *RelatedClass = ParseIdentifierLoc(); + if (ExpectAndConsume(tok::comma)) { + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + + // Parse optional class method name. + IdentifierLoc *ClassMethod = nullptr; + if (Tok.is(tok::identifier)) { + ClassMethod = ParseIdentifierLoc(); + if (!TryConsumeToken(tok::colon)) { + Diag(Tok, diag::err_objcbridge_related_selector_name); + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + } + if (!TryConsumeToken(tok::comma)) { + if (Tok.is(tok::colon)) + Diag(Tok, diag::err_objcbridge_related_selector_name); + else + Diag(Tok, diag::err_expected) << tok::comma; + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + + // Parse optional instance method name. + IdentifierLoc *InstanceMethod = nullptr; + if (Tok.is(tok::identifier)) + InstanceMethod = ParseIdentifierLoc(); + else if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected) << tok::r_paren; + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + + // Closing ')'. + if (T.consumeClose()) + return; + + if (endLoc) + *endLoc = T.getCloseLocation(); + + // Record this attribute + attrs.addNew(&ObjCBridgeRelated, + SourceRange(ObjCBridgeRelatedLoc, T.getCloseLocation()), + ScopeName, ScopeLoc, + RelatedClass, + ClassMethod, + InstanceMethod, + Syntax); +} // Late Parsed Attributes: // See other examples of late parsing in lib/Parse/ParseCXXInlineMethods @@ -1038,13 +1081,6 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); - if (OnDefinition && !IsThreadSafetyAttribute(LA.AttrName.getName())) { - // FIXME: Do not warn on C++11 attributes, once we start supporting - // them here. - Diag(Tok, diag::warn_attribute_on_function_definition) - << LA.AttrName.getName(); - } - ParsedAttributes Attrs(AttrFactory); SourceLocation endLoc; @@ -1071,7 +1107,8 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, Actions.ActOnReenterFunctionContext(Actions.CurScope, D); ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc, - 0, SourceLocation(), AttributeList::AS_GNU); + nullptr, SourceLocation(), AttributeList::AS_GNU, + nullptr); if (HasFunScope) { Actions.ActOnExitFunctionContext(); @@ -1084,15 +1121,21 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, // If there are multiple decls, then the decl cannot be within the // function scope. ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc, - 0, SourceLocation(), AttributeList::AS_GNU); + nullptr, SourceLocation(), AttributeList::AS_GNU, + nullptr); } } else { Diag(Tok, diag::warn_attribute_no_decl) << LA.AttrName.getName(); } - for (unsigned i = 0, ni = LA.Decls.size(); i < ni; ++i) { + const AttributeList *AL = Attrs.getList(); + if (OnDefinition && AL && !AL->isCXX11Attribute() && + AL->isKnownToGCC()) + Diag(Tok, diag::warn_attribute_on_function_definition) + << &LA.AttrName; + + for (unsigned i = 0, ni = LA.Decls.size(); i < ni; ++i) Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.Decls[i], Attrs); - } if (Tok.getLocation() != OrigLoc) { // Due to a parsing error, we either went over the cached tokens or @@ -1106,101 +1149,29 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, } } -/// \brief Wrapper around a case statement checking if AttrName is -/// one of the thread safety attributes -bool Parser::IsThreadSafetyAttribute(StringRef AttrName) { - return llvm::StringSwitch<bool>(AttrName) - .Case("guarded_by", true) - .Case("guarded_var", true) - .Case("pt_guarded_by", true) - .Case("pt_guarded_var", true) - .Case("lockable", true) - .Case("scoped_lockable", true) - .Case("no_thread_safety_analysis", true) - .Case("acquired_after", true) - .Case("acquired_before", true) - .Case("exclusive_lock_function", true) - .Case("shared_lock_function", true) - .Case("exclusive_trylock_function", true) - .Case("shared_trylock_function", true) - .Case("unlock_function", true) - .Case("lock_returned", true) - .Case("locks_excluded", true) - .Case("exclusive_locks_required", true) - .Case("shared_locks_required", true) - .Default(false); -} - -/// \brief Parse the contents of thread safety attributes. These -/// should always be parsed as an expression list. -/// -/// We need to special case the parsing due to the fact that if the first token -/// of the first argument is an identifier, the main parse loop will store -/// that token as a "parameter" and the rest of -/// the arguments will be added to a list of "arguments". However, -/// subsequent tokens in the first argument are lost. We instead parse each -/// argument as an expression and add all arguments to the list of "arguments". -/// In future, we will take advantage of this special case to also -/// deal with some argument scoping issues here (for example, referring to a -/// function parameter in the attribute on that function). -void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, - SourceLocation AttrNameLoc, - ParsedAttributes &Attrs, - SourceLocation *EndLoc) { - assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); - - BalancedDelimiterTracker T(*this, tok::l_paren); - T.consumeOpen(); - - ArgsVector ArgExprs; - bool ArgExprsOk = true; - - // now parse the list of expressions - while (Tok.isNot(tok::r_paren)) { - EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); - ExprResult ArgExpr(ParseAssignmentExpression()); - if (ArgExpr.isInvalid()) { - ArgExprsOk = false; - T.consumeClose(); - break; - } else { - ArgExprs.push_back(ArgExpr.release()); - } - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); // Eat the comma, move to the next argument - } - // Match the ')'. - if (ArgExprsOk && !T.consumeClose()) { - Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, ArgExprs.data(), - ArgExprs.size(), AttributeList::AS_GNU); - } - if (EndLoc) - *EndLoc = T.getCloseLocation(); -} - void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, - SourceLocation *EndLoc) { + SourceLocation *EndLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + AttributeList::Syntax Syntax) { assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); + Diag(Tok, diag::err_expected) << tok::identifier; T.skipToEnd(); return; } IdentifierLoc *ArgumentKind = ParseIdentifierLoc(); - if (Tok.isNot(tok::comma)) { - Diag(Tok, diag::err_expected_comma); + if (ExpectAndConsume(tok::comma)) { T.skipToEnd(); return; } - ConsumeToken(); SourceRange MatchingCTypeRange; TypeResult MatchingCType = ParseTypeName(&MatchingCTypeRange); @@ -1211,10 +1182,9 @@ void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName, bool LayoutCompatible = false; bool MustBeNull = false; - while (Tok.is(tok::comma)) { - ConsumeToken(); + while (TryConsumeToken(tok::comma)) { if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); + Diag(Tok, diag::err_expected) << tok::identifier; T.skipToEnd(); return; } @@ -1232,10 +1202,9 @@ void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName, } if (!T.consumeClose()) { - Attrs.addNewTypeTagForDatatype(&AttrName, AttrNameLoc, 0, AttrNameLoc, - ArgumentKind, MatchingCType.release(), - LayoutCompatible, MustBeNull, - AttributeList::AS_GNU); + Attrs.addNewTypeTagForDatatype(&AttrName, AttrNameLoc, ScopeName, ScopeLoc, + ArgumentKind, MatchingCType.get(), + LayoutCompatible, MustBeNull, Syntax); } if (EndLoc) @@ -1337,8 +1306,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, // parsing c none objective-c decls. ObjCDeclContextSwitch ObjCDC(*this); - Decl *SingleDecl = 0; - Decl *OwnedType = 0; + Decl *SingleDecl = nullptr; + Decl *OwnedType = nullptr; switch (Tok.getKind()) { case tok::kw_template: case tok::kw_export: @@ -1508,8 +1477,7 @@ void Parser::SkipMalformedDecl() { // This declaration isn't over yet. Keep skipping. continue; } - if (Tok.is(tok::semi)) - ConsumeToken(); + TryConsumeToken(tok::semi); return; case tok::l_square: @@ -1562,6 +1530,9 @@ void Parser::SkipMalformedDecl() { break; case tok::eof: + case tok::annot_module_begin: + case tok::annot_module_end: + case tok::annot_module_include: return; default: @@ -1632,7 +1603,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } else { if (Tok.is(tok::l_brace)) { Diag(Tok, diag::err_function_definition_not_allowed); - SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); + SkipMalformedDecl(); + return DeclGroupPtrTy(); } } } @@ -1648,9 +1620,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // don't need to parse the container in advance. if (FRI && (Tok.is(tok::colon) || isTokIdentifier_in())) { bool IsForRangeLoop = false; - if (Tok.is(tok::colon)) { + if (TryConsumeToken(tok::colon, FRI->ColonLoc)) { IsForRangeLoop = true; - FRI->ColonLoc = ConsumeToken(); if (Tok.is(tok::l_brace)) FRI->RangeExpr = ParseBraceInitializer(); else @@ -1666,7 +1637,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } SmallVector<Decl *, 8> DeclsInGroup; - Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D); + Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes( + D, ParsedTemplateInfo(), FRI); if (LateParsedAttrs.size() > 0) ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false); D.complete(FirstDecl); @@ -1677,9 +1649,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // If we don't have a comma, it is either the end of the list (a ';') or an // error, bail out. - while (Tok.is(tok::comma)) { - SourceLocation CommaLoc = ConsumeToken(); - + SourceLocation CommaLoc; + while (TryConsumeToken(tok::comma, CommaLoc)) { if (Tok.isAtStartOfLine() && ExpectSemi && !MightBeDeclarator(Context)) { // This comma was followed by a line-break and something which can't be // the start of a declarator. The comma was probably a typo for a @@ -1724,8 +1695,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // Otherwise things are very confused and we skip to recover. if (!isDeclarationSpecifier()) { SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); - if (Tok.is(tok::semi)) - ConsumeToken(); + TryConsumeToken(tok::semi); } } @@ -1744,7 +1714,7 @@ bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) { return true; } - D.setAsmLabel(AsmLabel.release()); + D.setAsmLabel(AsmLabel.get()); D.SetRangeEnd(Loc); } @@ -1774,18 +1744,18 @@ bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) { /// According to the standard grammar, =default and =delete are function /// definitions, but that definitely doesn't fit with the parser here. /// -Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, - const ParsedTemplateInfo &TemplateInfo) { +Decl *Parser::ParseDeclarationAfterDeclarator( + Declarator &D, const ParsedTemplateInfo &TemplateInfo) { if (ParseAsmAttributesAfterDeclarator(D)) - return 0; + return nullptr; return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo); } -Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, - const ParsedTemplateInfo &TemplateInfo) { +Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( + Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) { // Inform the current actions module that we just parsed this declarator. - Decl *ThisDecl = 0; + Decl *ThisDecl = nullptr; switch (TemplateInfo.Kind) { case ParsedTemplateInfo::NonTemplate: ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); @@ -1808,7 +1778,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, D); if (ThisRes.isInvalid()) { SkipUntil(tok::semi, StopBeforeMatch); - return 0; + return nullptr; } ThisDecl = ThisRes.get(); } else { @@ -1832,8 +1802,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, // Recover as if it were an explicit specialization. TemplateParameterLists FakedParamLists; FakedParamLists.push_back(Actions.ActOnTemplateParameterList( - 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0, - LAngleLoc)); + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, nullptr, + 0, LAngleLoc)); ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D); @@ -1848,7 +1818,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, // Parse declarator '=' initializer. // If a '==' or '+=' is found, suggest a fixit to '='. if (isTokenEqualOrEqualTypo()) { - ConsumeToken(); + SourceLocation EqualLoc = ConsumeToken(); if (Tok.is(tok::kw_delete)) { if (D.isFunctionDeclarator()) @@ -1872,21 +1842,37 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, Actions.CodeCompleteInitializer(getCurScope(), ThisDecl); Actions.FinalizeDeclaration(ThisDecl); cutOffParsing(); - return 0; + return nullptr; } ExprResult Init(ParseInitializer()); + // If this is the only decl in (possibly) range based for statement, + // our best guess is that the user meant ':' instead of '='. + if (Tok.is(tok::r_paren) && FRI && D.isFirstDeclarator()) { + Diag(EqualLoc, diag::err_single_decl_assign_in_for_range) + << FixItHint::CreateReplacement(EqualLoc, ":"); + // We are trying to stop parser from looking for ';' in this for + // statement, therefore preventing spurious errors to be issued. + FRI->ColonLoc = EqualLoc; + Init = ExprError(); + FRI->RangeExpr = Init; + } + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); ExitScope(); } if (Init.isInvalid()) { - SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); + SmallVector<tok::TokenKind, 2> StopTokens; + StopTokens.push_back(tok::comma); + if (D.getContext() == Declarator::ForContext) + StopTokens.push_back(tok::r_paren); + SkipUntil(StopTokens, StopAtSemi | StopBeforeMatch); Actions.ActOnInitializerError(ThisDecl); } else - Actions.AddInitializerToDecl(ThisDecl, Init.take(), + Actions.AddInitializerToDecl(ThisDecl, Init.get(), /*DirectInit=*/false, TypeContainsAuto); } } else if (Tok.is(tok::l_paren)) { @@ -1925,7 +1911,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(), T.getCloseLocation(), Exprs); - Actions.AddInitializerToDecl(ThisDecl, Initializer.take(), + Actions.AddInitializerToDecl(ThisDecl, Initializer.get(), /*DirectInit=*/true, TypeContainsAuto); } } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace) && @@ -1948,7 +1934,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, if (Init.isInvalid()) { Actions.ActOnInitializerError(ThisDecl); } else - Actions.AddInitializerToDecl(ThisDecl, Init.take(), + Actions.AddInitializerToDecl(ThisDecl, Init.get(), /*DirectInit=*/true, TypeContainsAuto); } else { @@ -1975,8 +1961,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, // Validate declspec for type-name. unsigned Specs = DS.getParsedSpecifiers(); - if ((DSC == DSC_type_specifier || DSC == DSC_trailing) && - !DS.hasTypeSpecifier()) { + if (isTypeSpecifier(DSC) && !DS.hasTypeSpecifier()) { Diag(Tok, diag::err_expected_type); DS.SetTypeSpecError(); } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() && @@ -2050,7 +2035,7 @@ static bool isValidAfterIdentifierInDeclarator(const Token &T) { /// bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, const ParsedTemplateInfo &TemplateInfo, - AccessSpecifier AS, DeclSpecContext DSC, + AccessSpecifier AS, DeclSpecContext DSC, ParsedAttributesWithRange &Attrs) { assert(Tok.is(tok::identifier) && "should have identifier"); @@ -2074,8 +2059,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // within a type specifier. Outside of C++, we allow this even if the // language doesn't "officially" support implicit int -- we support // implicit int as an extension in C99 and C11. - if (DSC != DSC_type_specifier && DSC != DSC_trailing && - !getLangOpts().CPlusPlus && + if (!isTypeSpecifier(DSC) && !getLangOpts().CPlusPlus && isValidAfterIdentifierInDeclarator(NextToken())) { // If this token is valid for implicit int, e.g. "static x = 4", then // we just avoid eating the identifier, so it will be parsed as the @@ -2098,8 +2082,8 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // This is a common problem in C (saying 'foo' instead of 'struct foo'). // // C++ doesn't need this, and isTagName doesn't take SS. - if (SS == 0) { - const char *TagName = 0, *FixitTagName = 0; + if (SS == nullptr) { + const char *TagName = nullptr, *FixitTagName = nullptr; tok::TokenKind TagKind = tok::unknown; switch (Actions.isTagName(*Tok.getIdentifierInfo(), getCurScope())) { @@ -2145,7 +2129,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // Determine whether this identifier could plausibly be the name of something // being declared (with a missing type). - if (DSC != DSC_type_specifier && DSC != DSC_trailing && + if (!isTypeSpecifier(DSC) && (!SS || DSC == DSC_top_level || DSC == DSC_class)) { // Look ahead to the next token to try to figure out what this declaration // was supposed to be. @@ -2155,15 +2139,14 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // x(int n); // 'x' is not a type // x (*p)[]; // 'x' is a type // - // Since we're in an error case (or the rare 'implicit int in C++' MS - // extension), we can afford to perform a tentative parse to determine - // which case we're in. + // Since we're in an error case, we can afford to perform a tentative + // parse to determine which case we're in. TentativeParsingAction PA(*this); ConsumeToken(); TPResult TPR = TryParseDeclarator(/*mayBeAbstract*/false); PA.Revert(); - if (TPR != TPResult::False()) { + if (TPR != TPResult::False) { // The identifier is followed by a parenthesized declarator. // It's supposed to be a type. break; @@ -2202,39 +2185,33 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, } } - // This is almost certainly an invalid type name. Let the action emit a - // diagnostic and attempt to recover. + // This is almost certainly an invalid type name. Let Sema emit a diagnostic + // and attempt to recover. ParsedType T; IdentifierInfo *II = Tok.getIdentifierInfo(); - if (Actions.DiagnoseUnknownTypeName(II, Loc, getCurScope(), SS, T)) { - // The action emitted a diagnostic, so we don't have to. - if (T) { - // The action has suggested that the type T could be used. Set that as - // the type in the declaration specifiers, consume the would-be type - // name token, and we're done. - const char *PrevSpec; - unsigned DiagID; - DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T); - DS.SetRangeEnd(Tok.getLocation()); - ConsumeToken(); - // There may be other declaration specifiers after this. - return true; - } else if (II != Tok.getIdentifierInfo()) { - // If no type was suggested, the correction is to a keyword - Tok.setKind(II->getTokenID()); - // There may be other declaration specifiers after this. - return true; - } - - // Fall through; the action had no suggestion for us. - } else { - // The action did not emit a diagnostic, so emit one now. - SourceRange R; - if (SS) R = SS->getRange(); - Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R; + Actions.DiagnoseUnknownTypeName(II, Loc, getCurScope(), SS, T, + getLangOpts().CPlusPlus && + NextToken().is(tok::less)); + if (T) { + // The action has suggested that the type T could be used. Set that as + // the type in the declaration specifiers, consume the would-be type + // name token, and we're done. + const char *PrevSpec; + unsigned DiagID; + DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T, + Actions.getASTContext().getPrintingPolicy()); + DS.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); + // There may be other declaration specifiers after this. + return true; + } else if (II != Tok.getIdentifierInfo()) { + // If no type was suggested, the correction is to a keyword + Tok.setKind(II->getTokenID()); + // There may be other declaration specifiers after this. + return true; } - // Mark this as an error. + // Otherwise, the action had no suggestion for us. Mark this as an error. DS.SetTypeSpecError(); DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); @@ -2256,8 +2233,13 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { return DSC_class; if (Context == Declarator::FileContext) return DSC_top_level; + if (Context == Declarator::TemplateTypeArgContext) + return DSC_template_type_arg; if (Context == Declarator::TrailingReturnContext) return DSC_trailing; + if (Context == Declarator::AliasDeclContext || + Context == Declarator::AliasTemplateContext) + return DSC_alias_declaration; return DSC_normal; } @@ -2282,8 +2264,8 @@ ExprResult Parser::ParseAlignArgument(SourceLocation Start, } else ER = ParseConstantExpression(); - if (getLangOpts().CPlusPlus11 && Tok.is(tok::ellipsis)) - EllipsisLoc = ConsumeToken(); + if (getLangOpts().CPlusPlus11) + TryConsumeToken(tok::ellipsis, EllipsisLoc); return ER; } @@ -2305,7 +2287,7 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation KWLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen)) + if (T.expectAndConsume()) return; SourceLocation EllipsisLoc; @@ -2320,8 +2302,8 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, *EndLoc = T.getCloseLocation(); ArgsVector ArgExprs; - ArgExprs.push_back(ArgExpr.release()); - Attrs.addNew(KWName, KWLoc, 0, KWLoc, ArgExprs.data(), 1, + ArgExprs.push_back(ArgExpr.get()); + Attrs.addNew(KWName, KWLoc, nullptr, KWLoc, ArgExprs.data(), 1, AttributeList::AS_Keyword, EllipsisLoc); } @@ -2339,7 +2321,6 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, assert(DS.hasTagDefinition() && "shouldn't call this"); bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level); - bool HasMissingSemi = false; if (getLangOpts().CPlusPlus && (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || @@ -2349,63 +2330,77 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, return true; } + bool HasScope = Tok.is(tok::annot_cxxscope); + // Make a copy in case GetLookAheadToken invalidates the result of NextToken. + Token AfterScope = HasScope ? NextToken() : Tok; + // Determine whether the following tokens could possibly be a // declarator. - if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { - const Token &Next = NextToken(); + bool MightBeDeclarator = true; + if (Tok.is(tok::kw_typename) || Tok.is(tok::annot_typename)) { + // A declarator-id can't start with 'typename'. + MightBeDeclarator = false; + } else if (AfterScope.is(tok::annot_template_id)) { + // If we have a type expressed as a template-id, this cannot be a + // declarator-id (such a type cannot be redeclared in a simple-declaration). + TemplateIdAnnotation *Annot = + static_cast<TemplateIdAnnotation *>(AfterScope.getAnnotationValue()); + if (Annot->Kind == TNK_Type_template) + MightBeDeclarator = false; + } else if (AfterScope.is(tok::identifier)) { + const Token &Next = HasScope ? GetLookAheadToken(2) : NextToken(); + // These tokens cannot come after the declarator-id in a // simple-declaration, and are likely to come after a type-specifier. - HasMissingSemi = Next.is(tok::star) || Next.is(tok::amp) || - Next.is(tok::ampamp) || Next.is(tok::identifier) || - Next.is(tok::annot_cxxscope) || - Next.is(tok::coloncolon); - } else if (Tok.is(tok::annot_cxxscope) && - NextToken().is(tok::identifier) && - DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { - // We almost certainly have a missing semicolon. Look up the name and - // check; if it names a type, we're missing a semicolon. - CXXScopeSpec SS; - Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), - Tok.getAnnotationRange(), SS); - const Token &Next = NextToken(); - IdentifierInfo *Name = Next.getIdentifierInfo(); - Sema::NameClassification Classification = - Actions.ClassifyName(getCurScope(), SS, Name, Next.getLocation(), - NextToken(), /*IsAddressOfOperand*/false); - switch (Classification.getKind()) { - case Sema::NC_Error: - SkipMalformedDecl(); - return true; + if (Next.is(tok::star) || Next.is(tok::amp) || Next.is(tok::ampamp) || + Next.is(tok::identifier) || Next.is(tok::annot_cxxscope) || + Next.is(tok::coloncolon)) { + // Missing a semicolon. + MightBeDeclarator = false; + } else if (HasScope) { + // If the declarator-id has a scope specifier, it must redeclare a + // previously-declared entity. If that's a type (and this is not a + // typedef), that's an error. + CXXScopeSpec SS; + Actions.RestoreNestedNameSpecifierAnnotation( + Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS); + IdentifierInfo *Name = AfterScope.getIdentifierInfo(); + Sema::NameClassification Classification = Actions.ClassifyName( + getCurScope(), SS, Name, AfterScope.getLocation(), Next, + /*IsAddressOfOperand*/false); + switch (Classification.getKind()) { + case Sema::NC_Error: + SkipMalformedDecl(); + return true; - case Sema::NC_Keyword: - case Sema::NC_NestedNameSpecifier: - llvm_unreachable("typo correction and nested name specifiers not " - "possible here"); + case Sema::NC_Keyword: + case Sema::NC_NestedNameSpecifier: + llvm_unreachable("typo correction and nested name specifiers not " + "possible here"); - case Sema::NC_Type: - case Sema::NC_TypeTemplate: - // Not a previously-declared non-type entity. - HasMissingSemi = true; - break; + case Sema::NC_Type: + case Sema::NC_TypeTemplate: + // Not a previously-declared non-type entity. + MightBeDeclarator = false; + break; - case Sema::NC_Unknown: - case Sema::NC_Expression: - case Sema::NC_VarTemplate: - case Sema::NC_FunctionTemplate: - // Might be a redeclaration of a prior entity. - HasMissingSemi = false; - break; + case Sema::NC_Unknown: + case Sema::NC_Expression: + case Sema::NC_VarTemplate: + case Sema::NC_FunctionTemplate: + // Might be a redeclaration of a prior entity. + break; + } } - } else if (Tok.is(tok::kw_typename) || Tok.is(tok::annot_typename)) { - HasMissingSemi = true; } - if (!HasMissingSemi) + if (MightBeDeclarator) return false; + const PrintingPolicy &PPol = Actions.getASTContext().getPrintingPolicy(); Diag(PP.getLocForEndOfToken(DS.getRepAsDecl()->getLocEnd()), - diag::err_expected_semi_after_tagdecl) - << DeclSpec::getSpecifierName(DS.getTypeSpecType()); + diag::err_expected_after) + << DeclSpec::getSpecifierName(DS.getTypeSpecType(), PPol) << tok::semi; // Try to recover from the typo, by dropping the tag definition and parsing // the problematic tokens as a type. @@ -2461,9 +2456,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level); bool AttrsLastTime = false; ParsedAttributesWithRange attrs(AttrFactory); + const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy(); while (1) { bool isInvalid = false; - const char *PrevSpec = 0; + const char *PrevSpec = nullptr; unsigned DiagID = 0; SourceLocation Loc = Tok.getLocation(); @@ -2484,7 +2480,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // If this is not a declaration specifier token, we're done reading decl // specifiers. First verify that DeclSpec's are consistent. - DS.Finish(Diags, PP); + DS.Finish(Diags, PP, Policy); return; case tok::l_square: @@ -2586,7 +2582,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if ((DSContext == DSC_top_level || DSContext == DSC_class) && TemplateId->Name && Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) { - if (isConstructorDeclarator()) { + if (isConstructorDeclarator(/*Unqualified*/false)) { // The user meant this to be an out-of-line constructor // definition, but template arguments are not allowed // there. Just allow this as a constructor; we'll @@ -2618,7 +2614,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParsedType T = getTypeAnnotation(Tok); isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Tok.getAnnotationEndLoc(), - PrevSpec, DiagID, T); + PrevSpec, DiagID, T, Policy); if (isInvalid) break; } @@ -2636,7 +2632,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if ((DSContext == DSC_top_level || DSContext == DSC_class) && Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(), &SS)) { - if (isConstructorDeclarator()) + if (isConstructorDeclarator(/*Unqualified*/false)) goto DoneWithDeclSpec; // As noted in C++ [class.qual]p2 (cited above), when the name @@ -2677,7 +2673,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ConsumeToken(); // The C++ scope. isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, - DiagID, TypeRep); + DiagID, TypeRep, Policy); if (isInvalid) break; @@ -2696,7 +2692,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Tok.getAnnotationValue()) { ParsedType T = getTypeAnnotation(Tok); isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, - DiagID, T); + DiagID, T, Policy); } else DS.SetTypeSpecError(); @@ -2734,24 +2730,23 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // typedef-name case tok::kw_decltype: case tok::identifier: { + // This identifier can only be a typedef name if we haven't already seen + // a type-specifier. Without this check we misparse: + // typedef int X; struct Y { short X; }; as 'short int'. + if (DS.hasTypeSpecifier()) + goto DoneWithDeclSpec; + // In C++, check to see if this is a scope specifier like foo::bar::, if // so handle it as such. This is important for ctor parsing. if (getLangOpts().CPlusPlus) { if (TryAnnotateCXXScopeToken(EnteringContext)) { - if (!DS.hasTypeSpecifier()) - DS.SetTypeSpecError(); + DS.SetTypeSpecError(); goto DoneWithDeclSpec; } if (!Tok.is(tok::identifier)) continue; } - // This identifier can only be a typedef name if we haven't already seen - // a type-specifier. Without this check we misparse: - // typedef int X; struct Y { short X; }; as 'short int'. - if (DS.hasTypeSpecifier()) - goto DoneWithDeclSpec; - // Check for need to substitute AltiVec keyword tokens. if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) break; @@ -2765,11 +2760,21 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope()); + // MSVC: If we weren't able to parse a default template argument, and it's + // just a simple identifier, create a DependentNameType. This will allow us + // to defer the name lookup to template instantiation time, as long we forge a + // NestedNameSpecifier for the current context. + if (!TypeRep && DSContext == DSC_template_type_arg && + getLangOpts().MSVCCompat && getCurScope()->isTemplateParamScope()) { + TypeRep = Actions.ActOnDelayedDefaultTemplateArg( + *Tok.getIdentifierInfo(), Tok.getLocation()); + } + // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. if (!TypeRep) { ParsedAttributesWithRange Attrs(AttrFactory); - if (ParseImplicitInt(DS, 0, TemplateInfo, AS, DSContext, Attrs)) { + if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { if (!Attrs.empty()) { AttrsLastTime = true; attrs.takeAllFrom(Attrs); @@ -2783,11 +2788,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // check whether this is a constructor declaration. if (getLangOpts().CPlusPlus && DSContext == DSC_class && Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) && - isConstructorDeclarator()) + isConstructorDeclarator(/*Unqualified*/true)) goto DoneWithDeclSpec; isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, - DiagID, TypeRep); + DiagID, TypeRep, Policy); if (isInvalid) break; @@ -2819,7 +2824,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // constructor declaration. if (getLangOpts().CPlusPlus && DSContext == DSC_class && Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) && - isConstructorDeclarator()) + isConstructorDeclarator(TemplateId->SS.isEmpty())) goto DoneWithDeclSpec; // Turn the template-id annotation token into a type annotation @@ -2830,7 +2835,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // GNU attributes support. case tok::kw___attribute: - ParseGNUAttributes(DS.getAttributes(), 0, LateAttrs); + ParseGNUAttributes(DS.getAttributes(), nullptr, LateAttrs); continue; // Microsoft declspec support. @@ -2843,10 +2848,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.setFunctionSpecForceInline(Loc, PrevSpec, DiagID); IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = Tok.getLocation(); - // FIXME: This does not work correctly if it is set to be a declspec - // attribute, and a GNU attribute is simply incorrect. - DS.getAttributes().addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, - AttributeList::AS_GNU); + DS.getAttributes().addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, + nullptr, 0, AttributeList::AS_Keyword); break; } @@ -2876,46 +2879,46 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // storage-class-specifier case tok::kw_typedef: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc, - PrevSpec, DiagID); + PrevSpec, DiagID, Policy); break; case tok::kw_extern: if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread) Diag(Tok, diag::ext_thread_before) << "extern"; isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_extern, Loc, - PrevSpec, DiagID); + PrevSpec, DiagID, Policy); break; case tok::kw___private_extern__: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_private_extern, - Loc, PrevSpec, DiagID); + Loc, PrevSpec, DiagID, Policy); break; case tok::kw_static: if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread) Diag(Tok, diag::ext_thread_before) << "static"; isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc, - PrevSpec, DiagID); + PrevSpec, DiagID, Policy); break; case tok::kw_auto: if (getLangOpts().CPlusPlus11) { if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, - PrevSpec, DiagID); + PrevSpec, DiagID, Policy); if (!isInvalid) Diag(Tok, diag::ext_auto_storage_class) << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); } else isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, - DiagID); + DiagID, Policy); } else isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, - PrevSpec, DiagID); + PrevSpec, DiagID, Policy); break; case tok::kw_register: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_register, Loc, - PrevSpec, DiagID); + PrevSpec, DiagID, Policy); break; case tok::kw_mutable: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_mutable, Loc, - PrevSpec, DiagID); + PrevSpec, DiagID, Policy); break; case tok::kw___thread: isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS___thread, Loc, @@ -2977,19 +2980,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // type-specifier case tok::kw_short: isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw_long: if (DS.getTypeSpecWidth() != DeclSpec::TSW_long) isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, - DiagID); + DiagID, Policy); else isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw___int64: isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw_signed: isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, @@ -3009,43 +3012,43 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, break; case tok::kw_void: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw_char: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw_int: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw___int128: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw_half: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw_float: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw_double: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw_wchar_t: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw_char16_t: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw_char32_t: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw_bool: case tok::kw__Bool: @@ -3059,62 +3062,30 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = true; } else { isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, - DiagID); + DiagID, Policy); } break; case tok::kw__Decimal32: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw__Decimal64: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw__Decimal128: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec, - DiagID); + DiagID, Policy); break; case tok::kw___vector: - isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID, Policy); break; case tok::kw___pixel: - isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); - break; - case tok::kw_image1d_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_t, Loc, - PrevSpec, DiagID); - break; - case tok::kw_image1d_array_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_array_t, Loc, - PrevSpec, DiagID); - break; - case tok::kw_image1d_buffer_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_buffer_t, Loc, - PrevSpec, DiagID); - break; - case tok::kw_image2d_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image2d_t, Loc, - PrevSpec, DiagID); - break; - case tok::kw_image2d_array_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image2d_array_t, Loc, - PrevSpec, DiagID); - break; - case tok::kw_image3d_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image3d_t, Loc, - PrevSpec, DiagID); - break; - case tok::kw_sampler_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_sampler_t, Loc, - PrevSpec, DiagID); - break; - case tok::kw_event_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_event_t, Loc, - PrevSpec, DiagID); + isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID, Policy); break; case tok::kw___unknown_anytype: isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc, - PrevSpec, DiagID); + PrevSpec, DiagID, Policy); break; // class-specifier: @@ -3198,9 +3169,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, break; // OpenCL qualifiers: - case tok::kw_private: - if (!getLangOpts().OpenCL) - goto DoneWithDeclSpec; case tok::kw___private: case tok::kw___global: case tok::kw___local: @@ -3208,7 +3176,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___read_only: case tok::kw___write_only: case tok::kw___read_write: - ParseOpenCLQualifiers(DS); + ParseOpenCLQualifiers(DS.getAttributes()); break; case tok::less: @@ -3305,13 +3273,12 @@ ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) { ParseDeclarator(DeclaratorInfo.D); } - if (Tok.is(tok::colon)) { - ConsumeToken(); + if (TryConsumeToken(tok::colon)) { ExprResult Res(ParseConstantExpression()); if (Res.isInvalid()) SkipUntil(tok::semi, StopBeforeMatch); else - DeclaratorInfo.BitfieldSize = Res.release(); + DeclaratorInfo.BitfieldSize = Res.get(); } // If attributes exist after the declarator, parse them. @@ -3322,12 +3289,9 @@ ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) { // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. - if (Tok.isNot(tok::comma)) + if (!TryConsumeToken(tok::comma, CommaLoc)) return; - // Consume the comma. - CommaLoc = ConsumeToken(); - FirstDeclarator = false; } } @@ -3358,7 +3322,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, SmallVector<Decl *, 32> FieldDecls; // While we still have something to read, read the declarations in the struct. - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { // Each iteration of this loop reads one struct-declaration. // Check for extraneous top-level semicolon. @@ -3394,7 +3358,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, SmallVectorImpl<Decl *> &FieldDecls) : P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {} - void invoke(ParsingFieldDeclarator &FD) { + void invoke(ParsingFieldDeclarator &FD) override { // Install the declarator into the current TagDecl. Decl *Field = P.Actions.ActOnField(P.getCurScope(), TagDecl, FD.D.getDeclSpec().getSourceRange().getBegin(), @@ -3415,9 +3379,9 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, continue; } ConsumeToken(); - ExpectAndConsume(tok::l_paren, diag::err_expected_lparen); + ExpectAndConsume(tok::l_paren); if (!Tok.is(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); + Diag(Tok, diag::err_expected) << tok::identifier; SkipUntil(tok::semi); continue; } @@ -3426,21 +3390,22 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, Tok.getIdentifierInfo(), Fields); FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end()); ConsumeToken(); - ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); + ExpectAndConsume(tok::r_paren); } - if (Tok.is(tok::semi)) { - ConsumeToken(); - } else if (Tok.is(tok::r_brace)) { + if (TryConsumeToken(tok::semi)) + continue; + + if (Tok.is(tok::r_brace)) { ExpectAndConsume(tok::semi, diag::ext_expected_semi_decl_list); break; - } else { - ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list); - // Skip to end of block or statement to avoid ext-warning on extra ';'. - SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); - // If we stopped at a ';', eat it. - if (Tok.is(tok::semi)) ConsumeToken(); } + + ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list); + // Skip to end of block or statement to avoid ext-warning on extra ';'. + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); + // If we stopped at a ';', eat it. + TryConsumeToken(tok::semi); } T.consumeClose(); @@ -3557,7 +3522,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; if (SS.isSet() && Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); + Diag(Tok, diag::err_expected) << tok::identifier; if (Tok.isNot(tok::l_brace)) { // Has no name and is not a definition. // Skip the rest of this declarator, up until the comma or semicolon. @@ -3570,7 +3535,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // Must have either 'enum name' or 'enum {...}'. if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) && !(AllowFixedUnderlyingType && Tok.is(tok::colon))) { - Diag(Tok, diag::err_expected_ident_lbrace); + Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace; // Skip the rest of this declarator, up until the comma or semicolon. SkipUntil(tok::comma, StopAtSemi); @@ -3578,7 +3543,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, } // If an identifier is present, consume and remember it. - IdentifierInfo *Name = 0; + IdentifierInfo *Name = nullptr; SourceLocation NameLoc; if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); @@ -3617,13 +3582,13 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, 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()) + 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() && + else if (TPR == TPResult::False && GetLookAheadToken(2).getKind() == tok::semi) { // Consume the ':'. ConsumeToken(); @@ -3643,7 +3608,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // FIXME: The standard is not entirely clear on how to disambiguate in // this case. if ((getLangOpts().CPlusPlus && - isCXXDeclarationSpecifier(TPResult::True()) != TPResult::True()) || + isCXXDeclarationSpecifier(TPResult::True) != TPResult::True) || (!getLangOpts().CPlusPlus && !isDeclarationSpecifier(true))) { // We'll parse this as a bitfield later. PossibleBitfield = true; @@ -3696,15 +3661,14 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, } else { TUK = Sema::TUK_Definition; } - } else if (DSC != DSC_type_specifier && + } else if (!isTypeSpecifier(DSC) && (Tok.is(tok::semi) || (Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(CanBeBitfield)))) { TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; if (Tok.isNot(tok::semi)) { // A semicolon was missing after this declaration. Diagnose and recover. - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, - "enum"); + ExpectAndConsume(tok::semi, diag::err_expected_after, "enum"); PP.EnterToken(Tok); Tok.setKind(tok::semi); } @@ -3753,13 +3717,14 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, bool Owned = false; bool IsDependent = false; - const char *PrevSpec = 0; + const char *PrevSpec = nullptr; unsigned DiagID; Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc, attrs.getList(), AS, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent, ScopedEnumKWLoc, - IsScopedUsingClassTag, BaseType); + IsScopedUsingClassTag, BaseType, + DSC == DSC_type_specifier); if (IsDependent) { // This enum has a dependent nested-name-specifier. Handle it as a @@ -3770,9 +3735,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } - TypeResult Type = Actions.ActOnDependentTag(getCurScope(), DeclSpec::TST_enum, - TUK, SS, Name, StartLoc, - NameLoc); + TypeResult Type = Actions.ActOnDependentTag( + getCurScope(), DeclSpec::TST_enum, TUK, SS, Name, StartLoc, NameLoc); if (Type.isInvalid()) { DS.SetTypeSpecError(); return; @@ -3780,7 +3744,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, - PrevSpec, DiagID, Type.get())) + PrevSpec, DiagID, Type.get(), + Actions.getASTContext().getPrintingPolicy())) Diag(StartLoc, DiagID) << PrevSpec; return; @@ -3803,7 +3768,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, - PrevSpec, DiagID, TagDecl, Owned)) + PrevSpec, DiagID, TagDecl, Owned, + Actions.getASTContext().getPrintingPolicy())) Diag(StartLoc, DiagID) << PrevSpec; } @@ -3819,7 +3785,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, /// void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { // Enter the scope of the enum body and start the definition. - ParseScope EnumScope(this, Scope::DeclScope); + ParseScope EnumScope(this, Scope::DeclScope | Scope::EnumScope); Actions.ActOnTagStartDefinition(getCurScope(), EnumDecl); BalancedDelimiterTracker T(*this, tok::l_brace); @@ -3831,10 +3797,19 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { SmallVector<Decl *, 32> EnumConstantDecls; - Decl *LastEnumConstDecl = 0; + Decl *LastEnumConstDecl = nullptr; // Parse the enumerator-list. - while (Tok.is(tok::identifier)) { + while (Tok.isNot(tok::r_brace)) { + // Parse enumerator. If failed, try skipping till the start of the next + // enumerator definition. + if (Tok.isNot(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; + if (SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch) && + TryConsumeToken(tok::comma)) + continue; + break; + } IdentifierInfo *Ident = Tok.getIdentifierInfo(); SourceLocation IdentLoc = ConsumeToken(); @@ -3848,11 +3823,10 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { ExprResult AssignedVal; ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent); - if (Tok.is(tok::equal)) { - EqualLoc = ConsumeToken(); + if (TryConsumeToken(tok::equal, EqualLoc)) { AssignedVal = ParseConstantExpression(); if (AssignedVal.isInvalid()) - SkipUntil(tok::comma, tok::r_brace, StopAtSemi | StopBeforeMatch); + SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch); } // Install the enumerator constant into EnumDecl. @@ -3860,7 +3834,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { LastEnumConstDecl, IdentLoc, Ident, attrs.getList(), EqualLoc, - AssignedVal.release()); + AssignedVal.get()); PD.complete(EnumConstDecl); EnumConstantDecls.push_back(EnumConstDecl); @@ -3874,11 +3848,25 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { continue; } - if (Tok.isNot(tok::comma)) - break; - SourceLocation CommaLoc = ConsumeToken(); + // Emumerator definition must be finished, only comma or r_brace are + // allowed here. + SourceLocation CommaLoc; + if (Tok.isNot(tok::r_brace) && !TryConsumeToken(tok::comma, CommaLoc)) { + if (EqualLoc.isValid()) + Diag(Tok.getLocation(), diag::err_expected_either) << tok::r_brace + << tok::comma; + else + Diag(Tok.getLocation(), diag::err_expected_end_of_enumerator); + if (SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch)) { + if (TryConsumeToken(tok::comma, CommaLoc)) + continue; + } else { + break; + } + } - if (Tok.isNot(tok::identifier)) { + // If comma is followed by r_brace, emit appropriate warning. + if (Tok.is(tok::r_brace) && CommaLoc.isValid()) { if (!getLangOpts().C99 && !getLangOpts().CPlusPlus11) Diag(CommaLoc, getLangOpts().CPlusPlus ? diag::ext_enumerator_list_comma_cxx : @@ -3887,6 +3875,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { else if (getLangOpts().CPlusPlus11) Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma) << FixItHint::CreateRemoval(CommaLoc); + break; } } @@ -3910,7 +3899,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { // was probably forgotten. bool CanBeBitfield = getCurScope()->getFlags() & Scope::ClassScope; if (!isValidAfterTypeSpecifier(CanBeBitfield)) { - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, "enum"); + ExpectAndConsume(tok::semi, diag::err_expected_after, "enum"); // Push this token back into the preprocessor and change our current token // to ';' so that the rest of the code recovers as though there were an // ';' after the definition. @@ -3924,12 +3913,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { bool Parser::isTypeQualifier() const { switch (Tok.getKind()) { default: return false; - - // type-qualifier only in OpenCL - case tok::kw_private: - return getLangOpts().OpenCL; - - // type-qualifier + // type-qualifier case tok::kw_const: case tok::kw_volatile: case tok::kw_restrict: @@ -3975,16 +3959,6 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { case tok::kw__Decimal128: case tok::kw___vector: - // OpenCL specific types: - case tok::kw_image1d_t: - case tok::kw_image1d_array_t: - case tok::kw_image1d_buffer_t: - case tok::kw_image2d_t: - case tok::kw_image2d_array_t: - case tok::kw_image3d_t: - case tok::kw_sampler_t: - case tok::kw_event_t: - // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: @@ -4057,16 +4031,6 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw__Decimal128: case tok::kw___vector: - // OpenCL specific types: - case tok::kw_image1d_t: - case tok::kw_image1d_array_t: - case tok::kw_image1d_buffer_t: - case tok::kw_image2d_t: - case tok::kw_image2d_array_t: - case tok::kw_image3d_t: - case tok::kw_sampler_t: - case tok::kw_event_t: - // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: @@ -4111,9 +4075,6 @@ bool Parser::isTypeSpecifierQualifier() { return true; - case tok::kw_private: - return getLangOpts().OpenCL; - // C11 _Atomic case tok::kw__Atomic: return true; @@ -4129,9 +4090,6 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { switch (Tok.getKind()) { default: return false; - case tok::kw_private: - return getLangOpts().OpenCL; - case tok::identifier: // foo::bar // Unfortunate hack to support "Class.factoryMethod" notation. if (getLangOpts().ObjC1 && NextToken().is(tok::period)) @@ -4213,16 +4171,6 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw__Decimal128: case tok::kw___vector: - // OpenCL specific types: - case tok::kw_image1d_t: - case tok::kw_image1d_array_t: - case tok::kw_image1d_buffer_t: - case tok::kw_image2d_t: - case tok::kw_image2d_array_t: - case tok::kw_image3d_t: - case tok::kw_sampler_t: - case tok::kw_event_t: - // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: @@ -4300,7 +4248,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { } } -bool Parser::isConstructorDeclarator() { +bool Parser::isConstructorDeclarator(bool IsUnqualified) { TentativeParsingAction TPA(*this); // Parse the C++ scope specifier. @@ -4382,12 +4330,35 @@ bool Parser::isConstructorDeclarator() { case tok::coloncolon: // C(X :: Y); // C(X :: *p); - case tok::r_paren: - // C(X ) // Assume this isn't a constructor, rather than assuming it's a // constructor with an unnamed parameter of an ill-formed type. break; + case tok::r_paren: + // C(X ) + if (NextToken().is(tok::colon) || NextToken().is(tok::kw_try)) { + // Assume these were meant to be constructors: + // C(X) : (the name of a bit-field cannot be parenthesized). + // C(X) try (this is otherwise ill-formed). + IsConstructor = true; + } + if (NextToken().is(tok::semi) || NextToken().is(tok::l_brace)) { + // If we have a constructor name within the class definition, + // assume these were meant to be constructors: + // C(X) { + // C(X) ; + // ... because otherwise we would be declaring a non-static data + // member that is ill-formed because it's of the same type as its + // surrounding class. + // + // FIXME: We can actually do this whether or not the name is qualified, + // because if it is qualified in this context it must be being used as + // a constructor name. However, we do not implement that rule correctly + // currently, so we're somewhat conservative here. + IsConstructor = IsUnqualified; + } + break; + default: IsConstructor = true; break; @@ -4426,7 +4397,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, while (1) { bool isInvalid = false; - const char *PrevSpec = 0; + const char *PrevSpec = nullptr; unsigned DiagID = 0; SourceLocation Loc = Tok.getLocation(); @@ -4455,9 +4426,6 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, break; // OpenCL qualifiers: - case tok::kw_private: - if (!getLangOpts().OpenCL) - goto DoneWithTypeQuals; case tok::kw___private: case tok::kw___global: case tok::kw___local: @@ -4465,7 +4433,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, case tok::kw___read_only: case tok::kw___write_only: case tok::kw___read_write: - ParseOpenCLQualifiers(DS); + ParseOpenCLQualifiers(DS.getAttributes()); break; case tok::kw___uptr: @@ -4506,7 +4474,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, DoneWithTypeQuals: // If this is not a type-qualifier token, we're done reading type // qualifiers. First verify that DeclSpec's are consistent. - DS.Finish(Diags, PP); + DS.Finish(Diags, PP, Actions.getASTContext().getPrintingPolicy()); if (EndLoc.isValid()) DS.SetRangeEnd(EndLoc); return; @@ -4575,7 +4543,9 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // Member pointers get special handling, since there's no place for the // scope spec in the generic path below. if (getLangOpts().CPlusPlus && - (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) || + (Tok.is(tok::coloncolon) || + (Tok.is(tok::identifier) && + (NextToken().is(tok::coloncolon) || NextToken().is(tok::less))) || Tok.is(tok::annot_cxxscope))) { bool EnteringContext = D.getContext() == Declarator::FileContext || D.getContext() == Declarator::MemberContext; @@ -4710,17 +4680,17 @@ void Parser::ParseDeclaratorInternal(Declarator &D, } } -static void diagnoseMisplacedEllipsis(Parser &P, Declarator &D, - SourceLocation EllipsisLoc) { - if (EllipsisLoc.isValid()) { - FixItHint Insertion; - if (!D.getEllipsisLoc().isValid()) { - Insertion = FixItHint::CreateInsertion(D.getIdentifierLoc(), "..."); - D.setEllipsisLoc(EllipsisLoc); - } - P.Diag(EllipsisLoc, diag::err_misplaced_ellipsis_in_declaration) - << FixItHint::CreateRemoval(EllipsisLoc) << Insertion << !D.hasName(); - } +// When correcting from misplaced brackets before the identifier, the location +// is saved inside the declarator so that other diagnostic messages can use +// them. This extracts and returns that location, or returns the provided +// location if a stored location does not exist. +static SourceLocation getMissingDeclaratorIdLoc(Declarator &D, + SourceLocation Loc) { + if (D.getName().StartLocation.isInvalid() && + D.getName().EndLocation.isValid()) + return D.getName().EndLocation; + + return Loc; } /// ParseDirectDeclarator @@ -4768,6 +4738,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR inside a class, in + // this context it is a bitfield. Also in range-based for statement colon + // may delimit for-range-declaration. + ColonProtectionRAIIObject X(*this, + D.getContext() == Declarator::MemberContext || + (D.getContext() == Declarator::ForContext && + getLangOpts().CPlusPlus11)); + // ParseDeclaratorInternal might already have parsed the scope. if (D.getCXXScopeSpec().isEmpty()) { bool EnteringContext = D.getContext() == Declarator::FileContext || @@ -4802,7 +4780,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // The ellipsis was put in the wrong place. Recover, and explain to // the user what they should have done. ParseDeclarator(D); - diagnoseMisplacedEllipsis(*this, D, EllipsisLoc); + if (EllipsisLoc.isValid()) + DiagnoseMisplacedEllipsisInDeclarator(EllipsisLoc, D); return; } else D.setEllipsisLoc(EllipsisLoc); @@ -4837,7 +4816,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // Once we're past the identifier, if the scope was bad, mark the // whole declarator bad. D.getCXXScopeSpec().isInvalid()) { - D.SetIdentifier(0, Tok.getLocation()); + D.SetIdentifier(nullptr, Tok.getLocation()); D.setInvalidType(true); } else { // Parsed the unqualified-id; update range information and move along. @@ -4852,6 +4831,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { "There's a C++-specific check for tok::identifier above"); assert(Tok.getIdentifierInfo() && "Not an identifier?"); D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + D.SetRangeEnd(Tok.getLocation()); ConsumeToken(); goto PastIdentifier; } else if (Tok.is(tok::identifier) && D.diagnoseIdentifier()) { @@ -4861,7 +4841,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { !isCXX11VirtSpecifier(Tok)) { Diag(Tok.getLocation(), diag::err_unexpected_unqualified_id) << FixItHint::CreateRemoval(Tok.getLocation()); - D.SetIdentifier(0, Tok.getLocation()); + D.SetIdentifier(nullptr, Tok.getLocation()); ConsumeToken(); goto PastIdentifier; } @@ -4888,7 +4868,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { } else if (D.mayOmitIdentifier()) { // This could be something simple like "int" (in which case the declarator // portion is empty), if an abstract-declarator is allowed. - D.SetIdentifier(0, Tok.getLocation()); + D.SetIdentifier(nullptr, Tok.getLocation()); // The grammar for abstract-pack-declarator does not allow grouping parens. // FIXME: Revisit this once core issue 1488 is resolved. @@ -4898,10 +4878,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) { } else { if (Tok.getKind() == tok::annot_pragma_parser_crash) LLVM_BUILTIN_TRAP; - if (D.getContext() == Declarator::MemberContext) - Diag(Tok, diag::err_expected_member_name_or_semi) - << D.getDeclSpec().getSourceRange(); - else if (getLangOpts().CPlusPlus) { + if (Tok.is(tok::l_square)) + return ParseMisplacedBracketDeclarator(D); + if (D.getContext() == Declarator::MemberContext) { + Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()), + diag::err_expected_member_name_or_semi) + << (D.getDeclSpec().isEmpty() ? SourceRange() + : D.getDeclSpec().getSourceRange()); + } else if (getLangOpts().CPlusPlus) { if (Tok.is(tok::period) || Tok.is(tok::arrow)) Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow); else { @@ -4910,12 +4894,16 @@ void Parser::ParseDirectDeclarator(Declarator &D) { Diag(PP.getLocForEndOfToken(Loc), diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus; else - Diag(Tok, diag::err_expected_unqualified_id) + Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()), + diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus; } - } else - Diag(Tok, diag::err_expected_ident_lparen); - D.SetIdentifier(0, Tok.getLocation()); + } else { + Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()), + diag::err_expected_either) + << tok::identifier << tok::l_paren; + } + D.SetIdentifier(nullptr, Tok.getLocation()); D.setInvalidType(true); } @@ -5051,7 +5039,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { // An ellipsis cannot be placed outside parentheses. if (EllipsisLoc.isValid()) - diagnoseMisplacedEllipsis(*this, D, EllipsisLoc); + DiagnoseMisplacedEllipsisInDeclarator(EllipsisLoc, D); return; } @@ -5060,7 +5048,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { // argument list. Recognize that this declarator will never have an // identifier (and remember where it would have been), then call into // ParseFunctionDeclarator to handle of argument list. - D.SetIdentifier(0, Tok.getLocation()); + D.SetIdentifier(nullptr, Tok.getLocation()); // Enter function-declaration scope, limiting any declarators to the // function prototype scope, including parameter declarators. @@ -5122,7 +5110,6 @@ void Parser::ParseFunctionDeclarator(Declarator &D, ParsedAttributes FnAttrs(AttrFactory); TypeResult TrailingReturnType; - Actions.ActOnStartFunctionDeclarator(); /* LocalEndLoc is the end location for the local FunctionTypeLoc. EndLoc is the end location for the function declarator. They differ for trailing return types. */ @@ -5191,6 +5178,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, // FIXME: currently, "static" case isn't handled correctly. bool IsCXX11MemberFunction = getLangOpts().CPlusPlus11 && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && (D.getContext() == Declarator::MemberContext ? !D.getDeclSpec().isFriendSpecified() : D.getContext() == Declarator::FileContext && @@ -5246,12 +5234,10 @@ void Parser::ParseFunctionDeclarator(Declarator &D, DynamicExceptionRanges.data(), DynamicExceptions.size(), NoexceptExpr.isUsable() ? - NoexceptExpr.get() : 0, + NoexceptExpr.get() : nullptr, StartLoc, LocalEndLoc, D, TrailingReturnType), FnAttrs, EndLoc); - - Actions.ActOnEndFunctionDeclarator(); } /// isFunctionDeclaratorIdentifierList - This parameter list may have an @@ -5303,10 +5289,10 @@ void Parser::ParseFunctionDeclaratorIdentifierList( // Maintain an efficient lookup of params we have seen so far. llvm::SmallSet<const IdentifierInfo*, 16> ParamsSoFar; - while (1) { + do { // If this isn't an identifier, report the error and skip until ')'. if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); + Diag(Tok, diag::err_expected) << tok::identifier; SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); // Forget we parsed anything. ParamInfo.clear(); @@ -5326,17 +5312,13 @@ void Parser::ParseFunctionDeclaratorIdentifierList( // Remember this identifier in ParamInfo. ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, Tok.getLocation(), - 0)); + nullptr)); } // Eat the identifier. ConsumeToken(); - // The list continues if we see a comma. - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); - } + } while (TryConsumeToken(tok::comma)); } /// ParseParameterDeclarationClause - Parse a (possibly empty) parameter-list @@ -5375,13 +5357,11 @@ void Parser::ParseParameterDeclarationClause( ParsedAttributes &FirstArgAttrs, SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo, SourceLocation &EllipsisLoc) { - while (1) { - if (Tok.is(tok::ellipsis)) { - // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq - // before deciding this was a parameter-declaration-clause. - EllipsisLoc = ConsumeToken(); // Consume the ellipsis. + do { + // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq + // before deciding this was a parameter-declaration-clause. + if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) break; - } // Parse the declaration-specifiers. // Just use the ParsingDeclaration "scope" of the declarator. @@ -5422,11 +5402,11 @@ void Parser::ParseParameterDeclarationClause( // DefArgToks is used when the parsing of default arguments needs // to be delayed. - CachedTokens *DefArgToks = 0; + CachedTokens *DefArgToks = nullptr; // If no parameter was specified, verify that *something* was specified, // otherwise we have a missing type and identifier. - if (DS.isEmpty() && ParmDeclarator.getIdentifier() == 0 && + if (DS.isEmpty() && ParmDeclarator.getIdentifier() == nullptr && ParmDeclarator.getNumTypeObjects() == 0) { // Completely missing, emit error. Diag(DSStart, diag::err_missing_param); @@ -5455,8 +5435,8 @@ void Parser::ParseParameterDeclarationClause( if (!ConsumeAndStoreInitializer(*DefArgToks, CIK_DefaultArgument)) { delete DefArgToks; - DefArgToks = 0; - Actions.ActOnParamDefaultArgumentError(Param); + DefArgToks = nullptr; + Actions.ActOnParamDefaultArgumentError(Param, EqualLoc); } else { // Mark the end of the default argument so that we know when to // stop when we parse it later on. @@ -5485,12 +5465,12 @@ void Parser::ParseParameterDeclarationClause( } else DefArgResult = ParseAssignmentExpression(); if (DefArgResult.isInvalid()) { - Actions.ActOnParamDefaultArgumentError(Param); + Actions.ActOnParamDefaultArgumentError(Param, EqualLoc); SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch); } else { // Inform the actions module about the default argument Actions.ActOnParamDefaultArgument(Param, EqualLoc, - DefArgResult.take()); + DefArgResult.get()); } } } @@ -5500,26 +5480,17 @@ void Parser::ParseParameterDeclarationClause( Param, DefArgToks)); } - // If the next token is a comma, consume it and keep reading arguments. - if (Tok.isNot(tok::comma)) { - if (Tok.is(tok::ellipsis)) { - EllipsisLoc = ConsumeToken(); // Consume the ellipsis. - - if (!getLangOpts().CPlusPlus) { - // We have ellipsis without a preceding ',', which is ill-formed - // in C. Complain and provide the fix. - Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis) - << FixItHint::CreateInsertion(EllipsisLoc, ", "); - } - } - + if (TryConsumeToken(tok::ellipsis, EllipsisLoc) && + !getLangOpts().CPlusPlus) { + // We have ellipsis without a preceding ',', which is ill-formed + // in C. Complain and provide the fix. + Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis) + << FixItHint::CreateInsertion(EllipsisLoc, ", "); break; } - // Consume the comma. - ConsumeToken(); - } - + // If the next token is a comma, consume it and keep reading arguments. + } while (TryConsumeToken(tok::comma)); } /// [C90] direct-declarator '[' constant-expression[opt] ']' @@ -5544,8 +5515,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { MaybeParseCXX11Attributes(attrs); // Remember that we parsed the empty array type. - ExprResult NumElements; - D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, + D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, nullptr, T.getOpenLocation(), T.getCloseLocation()), attrs, T.getCloseLocation()); @@ -5562,7 +5532,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // Remember that we parsed a array type, and remember its features. D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, - ExprRes.release(), + ExprRes.get(), T.getOpenLocation(), T.getCloseLocation()), attrs, T.getCloseLocation()); @@ -5571,8 +5541,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // If valid, this location is the position where we read the 'static' keyword. SourceLocation StaticLoc; - if (Tok.is(tok::kw_static)) - StaticLoc = ConsumeToken(); + TryConsumeToken(tok::kw_static, StaticLoc); // If there is a type-qualifier-list, read it now. // Type qualifiers in an array subscript are a C99 feature. @@ -5581,8 +5550,8 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // If we haven't already read 'static', check to see if there is one after the // type-qualifier-list. - if (!StaticLoc.isValid() && Tok.is(tok::kw_static)) - StaticLoc = ConsumeToken(); + if (!StaticLoc.isValid()) + TryConsumeToken(tok::kw_static, StaticLoc); // Handle "direct-declarator [ type-qual-list[opt] * ]". bool isStar = false; @@ -5633,12 +5602,102 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // Remember that we parsed a array type, and remember its features. D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), StaticLoc.isValid(), isStar, - NumElements.release(), + NumElements.get(), T.getOpenLocation(), T.getCloseLocation()), attrs, T.getCloseLocation()); } +/// Diagnose brackets before an identifier. +void Parser::ParseMisplacedBracketDeclarator(Declarator &D) { + assert(Tok.is(tok::l_square) && "Missing opening bracket"); + assert(!D.mayOmitIdentifier() && "Declarator cannot omit identifier"); + + SourceLocation StartBracketLoc = Tok.getLocation(); + Declarator TempDeclarator(D.getDeclSpec(), D.getContext()); + + while (Tok.is(tok::l_square)) { + ParseBracketDeclarator(TempDeclarator); + } + + // Stuff the location of the start of the brackets into the Declarator. + // The diagnostics from ParseDirectDeclarator will make more sense if + // they use this location instead. + if (Tok.is(tok::semi)) + D.getName().EndLocation = StartBracketLoc; + + SourceLocation SuggestParenLoc = Tok.getLocation(); + + // Now that the brackets are removed, try parsing the declarator again. + ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); + + // Something went wrong parsing the brackets, in which case, + // ParseBracketDeclarator has emitted an error, and we don't need to emit + // one here. + if (TempDeclarator.getNumTypeObjects() == 0) + return; + + // Determine if parens will need to be suggested in the diagnostic. + bool NeedParens = false; + if (D.getNumTypeObjects() != 0) { + switch (D.getTypeObject(D.getNumTypeObjects() - 1).Kind) { + case DeclaratorChunk::Pointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + NeedParens = true; + break; + case DeclaratorChunk::Array: + case DeclaratorChunk::Function: + case DeclaratorChunk::Paren: + break; + } + } + + if (NeedParens) { + // Create a DeclaratorChunk for the inserted parens. + ParsedAttributes attrs(AttrFactory); + SourceLocation EndLoc = PP.getLocForEndOfToken(D.getLocEnd()); + D.AddTypeInfo(DeclaratorChunk::getParen(SuggestParenLoc, EndLoc), attrs, + SourceLocation()); + } + + // Adding back the bracket info to the end of the Declarator. + for (unsigned i = 0, e = TempDeclarator.getNumTypeObjects(); i < e; ++i) { + const DeclaratorChunk &Chunk = TempDeclarator.getTypeObject(i); + ParsedAttributes attrs(AttrFactory); + attrs.set(Chunk.Common.AttrList); + D.AddTypeInfo(Chunk, attrs, SourceLocation()); + } + + // The missing identifier would have been diagnosed in ParseDirectDeclarator. + // If parentheses are required, always suggest them. + if (!D.getIdentifier() && !NeedParens) + return; + + SourceLocation EndBracketLoc = TempDeclarator.getLocEnd(); + + // Generate the move bracket error message. + SourceRange BracketRange(StartBracketLoc, EndBracketLoc); + SourceLocation EndLoc = PP.getLocForEndOfToken(D.getLocEnd()); + + if (NeedParens) { + Diag(EndLoc, diag::err_brackets_go_after_unqualified_id) + << getLangOpts().CPlusPlus + << FixItHint::CreateInsertion(SuggestParenLoc, "(") + << FixItHint::CreateInsertion(EndLoc, ")") + << FixItHint::CreateInsertionFromRange( + EndLoc, CharSourceRange(BracketRange, true)) + << FixItHint::CreateRemoval(BracketRange); + } else { + Diag(EndLoc, diag::err_brackets_go_after_unqualified_id) + << getLangOpts().CPlusPlus + << FixItHint::CreateInsertionFromRange( + EndLoc, CharSourceRange(BracketRange, true)) + << FixItHint::CreateRemoval(BracketRange); + } +} + /// [GNU] typeof-specifier: /// typeof ( expressions ) /// typeof ( type-name ) @@ -5674,11 +5733,12 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { return; } - const char *PrevSpec = 0; + const char *PrevSpec = nullptr; unsigned DiagID; // Check for duplicate type specifiers (e.g. "int typeof(int)"). if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec, - DiagID, CastTy)) + DiagID, CastTy, + Actions.getASTContext().getPrintingPolicy())) Diag(StartLoc, DiagID) << PrevSpec; return; } @@ -5696,11 +5756,12 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { return; } - const char *PrevSpec = 0; + const char *PrevSpec = nullptr; unsigned DiagID; // Check for duplicate type specifiers (e.g. "int typeof(int)"). if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec, - DiagID, Operand.get())) + DiagID, Operand.get(), + Actions.getASTContext().getPrintingPolicy())) Diag(StartLoc, DiagID) << PrevSpec; } @@ -5731,10 +5792,11 @@ void Parser::ParseAtomicSpecifier(DeclSpec &DS) { DS.setTypeofParensRange(T.getRange()); DS.SetRangeEnd(T.getCloseLocation()); - const char *PrevSpec = 0; + const char *PrevSpec = nullptr; unsigned DiagID; if (DS.SetTypeSpecType(DeclSpec::TST_atomic, StartLoc, PrevSpec, - DiagID, Result.release())) + DiagID, Result.get(), + Actions.getASTContext().getPrintingPolicy())) Diag(StartLoc, DiagID) << PrevSpec; } @@ -5774,6 +5836,7 @@ bool Parser::TryAltiVecVectorTokenOutOfLine() { bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, bool &isInvalid) { + const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy(); if (Tok.getIdentifierInfo() == Ident_vector) { Token Next = NextToken(); switch (Next.getKind()) { @@ -5788,15 +5851,15 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, case tok::kw_double: case tok::kw_bool: case tok::kw___pixel: - isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID, Policy); return true; case tok::identifier: if (Next.getIdentifierInfo() == Ident_pixel) { - isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID,Policy); return true; } if (Next.getIdentifierInfo() == Ident_bool) { - isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID,Policy); return true; } break; @@ -5805,11 +5868,11 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, } } else if ((Tok.getIdentifierInfo() == Ident_pixel) && DS.isTypeAltiVecVector()) { - isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); + isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID, Policy); return true; } else if ((Tok.getIdentifierInfo() == Ident_bool) && DS.isTypeAltiVecVector()) { - isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID); + isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID, Policy); return true; } return false; |