diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp | 73 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp | 445 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp | 553 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp | 169 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp | 83 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp | 38 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp | 819 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp | 94 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp | 59 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp | 70 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp | 16 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp | 130 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp | 76 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/Parser.cpp | 137 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h | 22 |
15 files changed, 2087 insertions, 697 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp index 59b491a..ab1f97d 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -26,12 +26,10 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, AttributeList *AccessAttrs, ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo, - const VirtSpecifiers& VS, - FunctionDefinitionKind DefinitionKind, - ExprResult& Init) { + const VirtSpecifiers& VS, + SourceLocation PureSpecLoc) { assert(D.isFunctionDeclarator() && "This isn't a function declarator!"); - assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try) || - Tok.is(tok::equal)) && + assert(Tok.isOneOf(tok::l_brace, tok::colon, tok::kw_try, tok::equal) && "Current token not a '{', ':', '=', or 'try'!"); MultiTemplateParamsArg TemplateParams( @@ -40,7 +38,6 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0); NamedDecl *FnD; - D.setFunctionDefinitionKind(DefinitionKind); if (D.getDeclSpec().isFriendSpecified()) FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, TemplateParams); @@ -50,12 +47,8 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, VS, ICIS_NoInit); if (FnD) { Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs); - bool TypeSpecContainsAuto = D.getDeclSpec().containsPlaceholderType(); - if (Init.isUsable()) - Actions.AddInitializerToDecl(FnD, Init.get(), false, - TypeSpecContainsAuto); - else - Actions.ActOnUninitializedDecl(FnD, TypeSpecContainsAuto); + if (PureSpecLoc.isValid()) + Actions.ActOnPureSpecifier(FnD, PureSpecLoc); } } @@ -71,17 +64,24 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, bool Delete = false; SourceLocation KWLoc; + SourceLocation KWEndLoc = Tok.getEndLoc().getLocWithOffset(-1); if (TryConsumeToken(tok::kw_delete, KWLoc)) { Diag(KWLoc, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_deleted_function : diag::ext_deleted_function); Actions.SetDeclDeleted(FnD, KWLoc); Delete = true; + if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) { + DeclAsFunction->setRangeEnd(KWEndLoc); + } } else if (TryConsumeToken(tok::kw_default, KWLoc)) { Diag(KWLoc, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_defaulted_function : diag::ext_defaulted_function); Actions.SetDeclDefaulted(FnD, KWLoc); + if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) { + DeclAsFunction->setRangeEnd(KWEndLoc); + } } else { llvm_unreachable("function definition after = not 'delete' or 'default'"); } @@ -97,12 +97,12 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, return FnD; } - + // In delayed template parsing mode, if we are within a class template // or if we are about to parse function member template then consume // the tokens and store them for parsing at the end of the translation unit. if (getLangOpts().DelayedTemplateParsing && - DefinitionKind == FDK_Definition && + D.getFunctionDefinitionKind() == FDK_Definition && !D.getDeclSpec().isConstexprSpecified() && !(FnD && FnD->getAsFunction() && FnD->getAsFunction()->getReturnType()->getContainedAutoType()) && @@ -186,7 +186,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, /// declaration. Now lex its initializer and store its tokens for parsing /// after the class is complete. void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) { - assert((Tok.is(tok::l_brace) || Tok.is(tok::equal)) && + assert(Tok.isOneOf(tok::l_brace, tok::equal) && "Current token not a '{' or '='!"); LateParsedMemberInitializer *MI = @@ -306,9 +306,10 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope | Scope::FunctionDeclarationScope | Scope::DeclScope); for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { + auto Param = cast<ParmVarDecl>(LM.DefaultArgs[I].Param); // Introduce the parameter into scope. - Actions.ActOnDelayedCXXMethodParameter(getCurScope(), - LM.DefaultArgs[I].Param); + bool HasUnparsed = Param->hasUnparsedDefaultArg(); + Actions.ActOnDelayedCXXMethodParameter(getCurScope(), Param); if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { // Mark the end of the default argument so that we know when to stop when // we parse it later on. @@ -316,9 +317,8 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { Token DefArgEnd; DefArgEnd.startToken(); DefArgEnd.setKind(tok::eof); - DefArgEnd.setLocation(LastDefaultArgToken.getLocation().getLocWithOffset( - LastDefaultArgToken.getLength())); - DefArgEnd.setEofData(LM.DefaultArgs[I].Param); + DefArgEnd.setLocation(LastDefaultArgToken.getEndLoc()); + DefArgEnd.setEofData(Param); Toks->push_back(DefArgEnd); // Parse the default argument from its saved token stream. @@ -336,7 +336,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // used. EnterExpressionEvaluationContext Eval(Actions, Sema::PotentiallyEvaluatedIfUsed, - LM.DefaultArgs[I].Param); + Param); ExprResult DefArgResult; if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { @@ -346,11 +346,9 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { DefArgResult = ParseAssignmentExpression(); DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult); if (DefArgResult.isInvalid()) { - Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param, - EqualLoc); + Actions.ActOnParamDefaultArgumentError(Param, EqualLoc); } else { - if (Tok.isNot(tok::eof) || - Tok.getEofData() != LM.DefaultArgs[I].Param) { + if (Tok.isNot(tok::eof) || Tok.getEofData() != Param) { // The last two tokens are the terminator and the saved value of // Tok; the last token in the default argument is the one before // those. @@ -359,7 +357,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { << SourceRange(Tok.getLocation(), (*Toks)[Toks->size() - 3].getLocation()); } - Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc, + Actions.ActOnParamDefaultArgument(Param, EqualLoc, DefArgResult.get()); } @@ -368,11 +366,21 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { while (Tok.isNot(tok::eof)) ConsumeAnyToken(); - if (Tok.is(tok::eof) && Tok.getEofData() == LM.DefaultArgs[I].Param) + if (Tok.is(tok::eof) && Tok.getEofData() == Param) ConsumeAnyToken(); delete Toks; LM.DefaultArgs[I].Toks = nullptr; + } else if (HasUnparsed) { + assert(Param->hasInheritedDefaultArg()); + FunctionDecl *Old = cast<FunctionDecl>(LM.Method)->getPreviousDecl(); + ParmVarDecl *OldParam = Old->getParamDecl(I); + assert (!OldParam->hasUnparsedDefaultArg()); + if (OldParam->hasUninstantiatedDefaultArg()) + Param->setUninstantiatedDefaultArg( + Param->getUninstantiatedDefaultArg()); + else + Param->setDefaultArg(OldParam->getInit()); } } @@ -383,9 +391,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { Token ExceptionSpecEnd; ExceptionSpecEnd.startToken(); ExceptionSpecEnd.setKind(tok::eof); - ExceptionSpecEnd.setLocation( - LastExceptionSpecToken.getLocation().getLocWithOffset( - LastExceptionSpecToken.getLength())); + ExceptionSpecEnd.setLocation(LastExceptionSpecToken.getEndLoc()); ExceptionSpecEnd.setEofData(LM.Method); Toks->push_back(ExceptionSpecEnd); @@ -490,8 +496,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { Token BodyEnd; BodyEnd.startToken(); BodyEnd.setKind(tok::eof); - BodyEnd.setLocation( - LastBodyToken.getLocation().getLocWithOffset(LastBodyToken.getLength())); + BodyEnd.setLocation(LastBodyToken.getEndLoc()); BodyEnd.setEofData(LM.D); LM.Toks.push_back(BodyEnd); // Append the current token at the end of the new token stream so that it @@ -501,7 +506,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); - assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) + assert(Tok.isOneOf(tok::l_brace, tok::colon, tok::kw_try) && "Inline method not starting with '{', ':' or 'try'"); // Parse the method body. Function body parsing code is similar enough @@ -816,7 +821,7 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { } } - if (Tok.is(tok::identifier) || Tok.is(tok::kw_template)) { + if (Tok.isOneOf(tok::identifier, tok::kw_template)) { Toks.push_back(Tok); ConsumeToken(); } else if (Tok.is(tok::code_completion)) { diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp index 4d05e16..45878b9 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp @@ -285,7 +285,7 @@ unsigned Parser::ParseAttributeArgsCommon( if (AttrKind == AttributeList::UnknownAttribute || AttrKind == AttributeList::IgnoredAttribute) { const Token &Next = NextToken(); - IsIdentifierArg = Next.is(tok::r_paren) || Next.is(tok::comma); + IsIdentifierArg = Next.isOneOf(tok::r_paren, tok::comma); } if (IsIdentifierArg) @@ -365,7 +365,8 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, // 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()) { + if (normalizeAttrName(AttrName->getName()) == "enable_if" && + D && D->isFunctionDeclarator()) { DeclaratorChunk::FunctionTypeInfo FTI = D->getFunctionTypeInfo(); PrototypeScope.reset(new ParseScope(this, Scope::FunctionPrototypeScope | Scope::FunctionDeclarationScope | @@ -529,64 +530,72 @@ bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName, /// [MS] extended-decl-modifier-seq: /// extended-decl-modifier[opt] /// extended-decl-modifier extended-decl-modifier-seq -void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &Attrs) { +void Parser::ParseMicrosoftDeclSpecs(ParsedAttributes &Attrs, + SourceLocation *End) { + assert((getLangOpts().MicrosoftExt || getLangOpts().Borland || + getLangOpts().CUDA) && + "Incorrect language options for parsing __declspec"); assert(Tok.is(tok::kw___declspec) && "Not a declspec!"); - ConsumeToken(); - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, "__declspec", - tok::r_paren)) - return; - - // An empty declspec is perfectly legal and should not warn. Additionally, - // you can specify multiple attributes per declspec. - 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; - if (!IsString && Tok.getKind() != tok::identifier && - Tok.getKind() != tok::kw_restrict) { - Diag(Tok, diag::err_ms_declspec_type); - T.skipToEnd(); + while (Tok.is(tok::kw___declspec)) { + ConsumeToken(); + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, "__declspec", + tok::r_paren)) return; - } - IdentifierInfo *AttrName; - SourceLocation AttrNameLoc; - if (IsString) { - SmallString<8> StrBuffer; - bool Invalid = false; - StringRef Str = PP.getSpelling(Tok, StrBuffer, &Invalid); - if (Invalid) { + // An empty declspec is perfectly legal and should not warn. Additionally, + // you can specify multiple attributes per declspec. + 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; + if (!IsString && Tok.getKind() != tok::identifier && + Tok.getKind() != tok::kw_restrict) { + Diag(Tok, diag::err_ms_declspec_type); T.skipToEnd(); return; } - AttrName = PP.getIdentifierInfo(Str); - AttrNameLoc = ConsumeStringToken(); - } else { - AttrName = Tok.getIdentifierInfo(); - AttrNameLoc = ConsumeToken(); - } - bool AttrHandled = false; + IdentifierInfo *AttrName; + SourceLocation AttrNameLoc; + if (IsString) { + SmallString<8> StrBuffer; + bool Invalid = false; + StringRef Str = PP.getSpelling(Tok, StrBuffer, &Invalid); + if (Invalid) { + T.skipToEnd(); + return; + } + AttrName = PP.getIdentifierInfo(Str); + AttrNameLoc = ConsumeStringToken(); + } else { + AttrName = Tok.getIdentifierInfo(); + AttrNameLoc = ConsumeToken(); + } + + 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(); + // 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); + if (!AttrHandled) + Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + AttributeList::AS_Declspec); + } + T.consumeClose(); + if (End) + *End = T.getCloseLocation(); } - T.consumeClose(); } void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { @@ -679,6 +688,28 @@ void Parser::ParseOpenCLQualifiers(ParsedAttributes &Attrs) { AttributeList::AS_Keyword); } +void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) { + // Treat these like attributes, even though they're type specifiers. + while (true) { + switch (Tok.getKind()) { + case tok::kw__Nonnull: + case tok::kw__Nullable: + case tok::kw__Null_unspecified: { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + if (!getLangOpts().ObjC1) + Diag(AttrNameLoc, diag::ext_nullability) + << AttrName; + attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + AttributeList::AS_Keyword); + break; + } + default: + return; + } + } +} + static bool VersionNumberSeparator(const char Separator) { return (Separator == '.' || Separator == '_'); } @@ -1360,6 +1391,46 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs) { } } +// As an exception to the rule, __declspec(align(...)) before the +// class-key affects the type instead of the variable. +void Parser::handleDeclspecAlignBeforeClassKey(ParsedAttributesWithRange &Attrs, + DeclSpec &DS, + Sema::TagUseKind TUK) { + if (TUK == Sema::TUK_Reference) + return; + + ParsedAttributes &PA = DS.getAttributes(); + AttributeList *AL = PA.getList(); + AttributeList *Prev = nullptr; + while (AL) { + AttributeList *Next = AL->getNext(); + + // We only consider attributes using the appropriate '__declspec' spelling, + // this behavior doesn't extend to any other spellings. + if (AL->getKind() == AttributeList::AT_Aligned && + AL->isDeclspecAttribute()) { + // Stitch the attribute into the tag's attribute list. + AL->setNext(nullptr); + Attrs.add(AL); + + // Remove the attribute from the variable's attribute list. + if (Prev) { + // Set the last variable attribute's next attribute to be the attribute + // after the current one. + Prev->setNext(Next); + } else { + // Removing the head of the list requires us to reset the head to the + // next attribute. + PA.set(Next); + } + } else { + Prev = AL; + } + + AL = Next; + } +} + /// ParseDeclaration - Parse a full 'declaration', which consists of /// declaration-specifiers, some number of declarators, and a semicolon. /// 'Context' should be a Declarator::TheContext value. This returns the @@ -1551,7 +1622,7 @@ void Parser::SkipMalformedDecl() { // a malformed class or function definition or similar. ConsumeBrace(); SkipUntil(tok::r_brace); - if (Tok.is(tok::comma) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try)) { + if (Tok.isOneOf(tok::comma, tok::l_brace, tok::kw_try)) { // This declaration isn't over yet. Keep skipping. continue; } @@ -1657,7 +1728,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // and we don't have any other declarators in this declaration. bool Fixit = !DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID); MaybeParseGNUAttributes(D, &LateParsedAttrs); - Fixit &= Tok.is(tok::semi) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try); + Fixit &= Tok.isOneOf(tok::semi, tok::l_brace, tok::kw_try); Diag(Loc, diag::err_c11_noreturn_misplaced) << (Fixit ? FixItHint::CreateRemoval(Loc) : FixItHint()) @@ -1691,11 +1762,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } if (isDeclarationSpecifier()) { - // If there is an invalid declaration specifier right after the function - // prototype, then we must be in a missing semicolon case where this isn't - // actually a body. Just fall through into the code that handles it as a - // prototype, and let the top-level code handle the erroneous declspec - // where it would otherwise expect a comma or semicolon. + // If there is an invalid declaration specifier right after the + // function prototype, then we must be in a missing semicolon case + // where this isn't actually a body. Just fall through into the code + // that handles it as a prototype, and let the top-level code handle + // the erroneous declspec where it would otherwise expect a comma or + // semicolon. } else { Diag(Tok, diag::err_expected_fn_body); SkipUntil(tok::semi); @@ -1993,7 +2065,11 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); } - if (ParseExpressionList(Exprs, CommaLocs)) { + if (ParseExpressionList(Exprs, CommaLocs, [&] { + Actions.CodeCompleteConstructor(getCurScope(), + cast<VarDecl>(ThisDecl)->getType()->getCanonicalTypeInternal(), + ThisDecl->getLocation(), Exprs); + })) { Actions.ActOnInitializerError(ThisDecl); SkipUntil(tok::r_paren, StopAtSemi); @@ -2069,8 +2145,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, if (isTypeSpecifier(DSC) && !DS.hasTypeSpecifier()) { Diag(Tok, diag::err_expected_type); DS.SetTypeSpecError(); - } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() && - !DS.hasAttributes()) { + } else if (Specs == DeclSpec::PQ_None && !DS.hasAttributes()) { Diag(Tok, diag::err_typename_requires_specqual); if (!DS.hasTypeSpecifier()) DS.SetTypeSpecError(); @@ -2098,7 +2173,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, } // Issue diagnostic and remove constexpr specfier if present. - if (DS.isConstexprSpecified()) { + if (DS.isConstexprSpecified() && DSC != DSC_condition) { Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr); DS.ClearConstexprSpec(); } @@ -2123,9 +2198,9 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, /// int (x) /// static bool isValidAfterIdentifierInDeclarator(const Token &T) { - return T.is(tok::l_square) || T.is(tok::l_paren) || T.is(tok::r_paren) || - T.is(tok::semi) || T.is(tok::comma) || T.is(tok::equal) || - T.is(tok::kw_asm) || T.is(tok::l_brace) || T.is(tok::colon); + return T.isOneOf(tok::l_square, tok::l_paren, tok::r_paren, tok::semi, + tok::comma, tok::equal, tok::kw_asm, tok::l_brace, + tok::colon); } @@ -2385,7 +2460,7 @@ ExprResult Parser::ParseAlignArgument(SourceLocation Start, /// [C++11] 'alignas' '(' assignment-expression ...[opt] ')' void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation *EndLoc) { - assert((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) && + assert(Tok.isOneOf(tok::kw_alignas, tok::kw__Alignas) && "Not an alignment-specifier!"); IdentifierInfo *KWName = Tok.getIdentifierInfo(); @@ -2428,8 +2503,8 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level); if (getLangOpts().CPlusPlus && - (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || - Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id)) && + Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_decltype, + tok::annot_template_id) && TryAnnotateCXXScopeToken(EnteringContext)) { SkipMalformedDecl(); return true; @@ -2442,7 +2517,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, // Determine whether the following tokens could possibly be a // declarator. bool MightBeDeclarator = true; - if (Tok.is(tok::kw_typename) || Tok.is(tok::annot_typename)) { + if (Tok.isOneOf(tok::kw_typename, tok::annot_typename)) { // A declarator-id can't start with 'typename'. MightBeDeclarator = false; } else if (AfterScope.is(tok::annot_template_id)) { @@ -2457,9 +2532,8 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, // These tokens cannot come after the declarator-id in a // simple-declaration, and are likely to come after a type-specifier. - 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)) { + if (Next.isOneOf(tok::star, tok::amp, tok::ampamp, tok::identifier, + tok::annot_cxxscope, tok::coloncolon)) { // Missing a semicolon. MightBeDeclarator = false; } else if (HasScope) { @@ -2528,6 +2602,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, /// [C11] alignment-specifier declaration-specifiers[opt] /// [GNU] attributes declaration-specifiers[opt] /// [Clang] '__module_private__' declaration-specifiers[opt] +/// [ObjC1] '__kindof' declaration-specifiers[opt] /// /// storage-class-specifier: [C99 6.7.1] /// 'typedef' @@ -2564,7 +2639,8 @@ 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(); + // We use Sema's policy to get bool macros right. + const PrintingPolicy &Policy = Actions.getPrintingPolicy(); while (1) { bool isInvalid = false; bool isStorageClass = false; @@ -2811,12 +2887,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); // The typename - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); - continue; } @@ -2866,14 +2936,27 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DS.isTypeAltiVecVector()) goto DoneWithDeclSpec; + if (DSContext == DSC_objc_method_result && isObjCInstancetype()) { + ParsedType TypeRep = Actions.ActOnObjCInstanceType(Loc); + assert(TypeRep); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, + DiagID, TypeRep, Policy); + if (isInvalid) + break; + + DS.SetRangeEnd(Loc); + ConsumeToken(); + continue; + } + ParsedType TypeRep = 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. + // 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( @@ -2909,11 +2992,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); // The identifier - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); + // Objective-C supports type arguments and protocol references + // following an Objective-C object or object pointer + // type. Handle either one of them. + if (Tok.is(tok::less) && getLangOpts().ObjC1) { + SourceLocation NewEndLoc; + TypeResult NewTypeRep = parseObjCTypeArgsAndProtocolQualifiers( + Loc, TypeRep, /*consumeLastToken=*/true, + NewEndLoc); + if (NewTypeRep.isUsable()) { + DS.UpdateTypeRep(NewTypeRep.get()); + DS.SetRangeEnd(NewEndLoc); + } + } // Need to support trailing type qualifiers (e.g. "id<p> const"). // If a type specifier follows, it will be diagnosed elsewhere. @@ -2950,7 +3041,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Microsoft declspec support. case tok::kw___declspec: - ParseMicrosoftDeclSpec(DS.getAttributes()); + ParseMicrosoftDeclSpecs(DS.getAttributes()); continue; // Microsoft single token adornments. @@ -2987,6 +3078,20 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParseOpenCLAttributes(DS.getAttributes()); continue; + // Nullability type specifiers. + case tok::kw__Nonnull: + case tok::kw__Nullable: + case tok::kw__Null_unspecified: + ParseNullabilityTypeSpecifiers(DS.getAttributes()); + continue; + + // Objective-C 'kindof' types. + case tok::kw___kindof: + DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc, + nullptr, 0, AttributeList::AS_Keyword); + (void)ConsumeToken(); + continue; + // storage-class-specifier case tok::kw_typedef: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc, @@ -3097,6 +3202,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID); break; + // concept + case tok::kw_concept: + isInvalid = DS.SetConceptSpec(Loc, PrevSpec, DiagID); + break; + // type-specifier case tok::kw_short: isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, @@ -3318,10 +3428,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DS.hasTypeSpecifier() || !getLangOpts().ObjC1) goto DoneWithDeclSpec; - if (!ParseObjCProtocolQualifiers(DS)) - Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id) - << FixItHint::CreateInsertion(Loc, "id") - << SourceRange(Loc, DS.getSourceRange().getEnd()); + SourceLocation StartLoc = Tok.getLocation(); + SourceLocation EndLoc; + TypeResult Type = parseObjCProtocolQualifierType(EndLoc); + if (Type.isUsable()) { + if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, StartLoc, + PrevSpec, DiagID, Type.get(), + Actions.getASTContext().getPrintingPolicy())) + Diag(StartLoc, DiagID) << PrevSpec; + + DS.SetRangeEnd(EndLoc); + } else { + DS.SetTypeSpecError(); + } // Need to support trailing type qualifiers (e.g. "id<p> const"). // If a type specifier follows, it will be diagnosed elsewhere. @@ -3484,6 +3603,14 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, continue; } + if (Tok.is(tok::annot_pragma_openmp)) { + // Result can be ignored, because it must be always empty. + auto Res = ParseOpenMPDeclarativeDirective(); + assert(!Res); + // Silence possible warnings. + (void)Res; + continue; + } if (!Tok.is(tok::at)) { auto CFieldCallback = [&](ParsingFieldDeclarator &FD) { // Install the declarator into the current TagDecl. @@ -3594,16 +3721,13 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, ParsedAttributesWithRange attrs(AttrFactory); MaybeParseGNUAttributes(attrs); MaybeParseCXX11Attributes(attrs); - - // If declspecs exist after tag, parse them. - while (Tok.is(tok::kw___declspec)) - ParseMicrosoftDeclSpec(attrs); + MaybeParseMicrosoftDeclSpecs(attrs); SourceLocation ScopedEnumKWLoc; bool IsScopedUsingClassTag = false; // In C++11, recognize 'enum class' and 'enum struct'. - if (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct)) { + if (Tok.isOneOf(tok::kw_class, tok::kw_struct)) { Diag(Tok, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_scoped_enum : diag::ext_scoped_enum); IsScopedUsingClassTag = Tok.is(tok::kw_class); @@ -3616,8 +3740,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // They are allowed afterwards, though. MaybeParseGNUAttributes(attrs); MaybeParseCXX11Attributes(attrs); - while (Tok.is(tok::kw___declspec)) - ParseMicrosoftDeclSpec(attrs); + MaybeParseMicrosoftDeclSpecs(attrs); } // C++11 [temp.explicit]p12: @@ -3644,11 +3767,12 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // if a fixed underlying type is allowed. ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType); - if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + CXXScopeSpec Spec; + if (ParseOptionalCXXScopeSpecifier(Spec, ParsedType(), /*EnteringContext=*/true)) return; - if (SS.isSet() && Tok.isNot(tok::identifier)) { + if (Spec.isSet() && Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; if (Tok.isNot(tok::l_brace)) { // Has no name and is not a definition. @@ -3657,6 +3781,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } } + + SS = Spec; } // Must have either 'enum name' or 'enum {...}'. @@ -3842,6 +3968,15 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } + handleDeclspecAlignBeforeClassKey(attrs, DS, TUK); + + Sema::SkipBodyInfo SkipBody; + if (!Name && TUK == Sema::TUK_Definition && Tok.is(tok::l_brace) && + NextToken().is(tok::identifier)) + SkipBody = Actions.shouldSkipAnonEnumBody(getCurScope(), + NextToken().getIdentifierInfo(), + NextToken().getLocation()); + bool Owned = false; bool IsDependent = false; const char *PrevSpec = nullptr; @@ -3851,7 +3986,22 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, AS, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent, ScopedEnumKWLoc, IsScopedUsingClassTag, BaseType, - DSC == DSC_type_specifier); + DSC == DSC_type_specifier, &SkipBody); + + if (SkipBody.ShouldSkip) { + assert(TUK == Sema::TUK_Definition && "can only skip a definition"); + + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); + T.skipToEnd(); + + if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, + PrevSpec, DiagID, TagDecl, Owned, + Actions.getASTContext().getPrintingPolicy())) + Diag(StartLoc, DiagID) << PrevSpec; + return; + } if (IsDependent) { // This enum has a dependent nested-name-specifier. Handle it as a @@ -3923,6 +4073,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { Diag(Tok, diag::error_empty_enum); SmallVector<Decl *, 32> EnumConstantDecls; + SmallVector<SuppressAccessChecks, 32> EnumAvailabilityDiags; Decl *LastEnumConstDecl = nullptr; @@ -3953,7 +4104,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { SourceLocation EqualLoc; ExprResult AssignedVal; - ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent); + EnumAvailabilityDiags.emplace_back(*this); if (TryConsumeToken(tok::equal, EqualLoc)) { AssignedVal = ParseConstantExpression(); @@ -3967,7 +4118,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { IdentLoc, Ident, attrs.getList(), EqualLoc, AssignedVal.get()); - PD.complete(EnumConstDecl); + EnumAvailabilityDiags.back().done(); EnumConstantDecls.push_back(EnumConstDecl); LastEnumConstDecl = EnumConstDecl; @@ -4023,6 +4174,14 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { getCurScope(), attrs.getList()); + // Now handle enum constant availability diagnostics. + assert(EnumConstantDecls.size() == EnumAvailabilityDiags.size()); + for (size_t i = 0, e = EnumConstantDecls.size(); i != e; ++i) { + ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent); + EnumAvailabilityDiags[i].redelay(); + PD.complete(EnumConstantDecls[i]); + } + EnumScope.Exit(); Actions.ActOnTagFinishDefinition(getCurScope(), EnumDecl, T.getCloseLocation()); @@ -4199,6 +4358,12 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw___pascal: case tok::kw___unaligned: + case tok::kw__Nonnull: + case tok::kw__Nullable: + case tok::kw__Null_unspecified: + + case tok::kw___kindof: + case tok::kw___private: case tok::kw___local: case tok::kw___global: @@ -4344,6 +4509,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::annot_decltype: case tok::kw_constexpr: + // C++ Concepts TS - concept + case tok::kw_concept: + // C11 _Atomic case tok::kw__Atomic: return true; @@ -4372,6 +4540,12 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw___pascal: case tok::kw___unaligned: + case tok::kw__Nonnull: + case tok::kw__Nullable: + case tok::kw__Null_unspecified: + + case tok::kw___kindof: + case tok::kw___private: case tok::kw___local: case tok::kw___global: @@ -4397,7 +4571,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) { } // Parse the constructor name. - if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { + if (Tok.isOneOf(tok::identifier, tok::annot_template_id)) { // We already know that we have a constructor name; just consume // the token. ConsumeToken(); @@ -4601,6 +4775,21 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs, continue; } goto DoneWithTypeQuals; + + // Nullability type specifiers. + case tok::kw__Nonnull: + case tok::kw__Nullable: + case tok::kw__Null_unspecified: + ParseNullabilityTypeSpecifiers(DS.getAttributes()); + continue; + + // Objective-C 'kindof' types. + case tok::kw___kindof: + DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc, + nullptr, 0, AttributeList::AS_Keyword); + (void)ConsumeToken(); + continue; + case tok::kw___attribute: if (AttrReqs & AR_GNUAttributesParsedAndRejected) // When GNU attributes are expressly forbidden, diagnose their usage. @@ -4773,7 +4962,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D, D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc, DS.getConstSpecLoc(), DS.getVolatileSpecLoc(), - DS.getRestrictSpecLoc()), + DS.getRestrictSpecLoc(), + DS.getAtomicSpecLoc()), DS.getAttributes(), SourceLocation()); else @@ -4916,7 +5106,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { } if (D.getCXXScopeSpec().isValid()) { - if (Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) + if (Actions.ShouldEnterDeclaratorScope(getCurScope(), + D.getCXXScopeSpec())) // Change the declaration context for name lookup, until this function // is exited (and the declarator has been parsed). DeclScopeObj.EnterDeclaratorScope(); @@ -4953,8 +5144,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // the l_paren token. } - if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || - Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) { + if (Tok.isOneOf(tok::identifier, tok::kw_operator, tok::annot_template_id, + tok::tilde)) { // We found something that indicates the start of an unqualified-id. // Parse that unqualified-id. bool AllowConstructorName; @@ -4968,6 +5159,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { AllowConstructorName = (D.getContext() == Declarator::MemberContext); SourceLocation TemplateKWLoc; + bool HadScope = D.getCXXScopeSpec().isValid(); if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*EnteringContext=*/true, /*AllowDestructorName=*/true, @@ -4981,6 +5173,13 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.SetIdentifier(nullptr, Tok.getLocation()); D.setInvalidType(true); } else { + // ParseUnqualifiedId might have parsed a scope specifier during error + // recovery. If it did so, enter that scope. + if (!HadScope && D.getCXXScopeSpec().isValid() && + Actions.ShouldEnterDeclaratorScope(getCurScope(), + D.getCXXScopeSpec())) + DeclScopeObj.EnterDeclaratorScope(); + // Parsed the unqualified-id; update range information and move along. if (D.getSourceRange().getBegin().isInvalid()) D.SetRangeBegin(D.getName().getSourceRange().getBegin()); @@ -5022,7 +5221,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // If there was an error parsing parenthesized declarator, declarator // scope may have been entered before. Don't do it again. if (!D.isInvalidType() && - Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) + Actions.ShouldEnterDeclaratorScope(getCurScope(), + D.getCXXScopeSpec())) // Change the declaration context for name lookup, until this function // is exited (and the declarator has been parsed). DeclScopeObj.EnterDeclaratorScope(); @@ -5048,7 +5248,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { << (D.getDeclSpec().isEmpty() ? SourceRange() : D.getDeclSpec().getSourceRange()); } else if (getLangOpts().CPlusPlus) { - if (Tok.is(tok::period) || Tok.is(tok::arrow)) + if (Tok.isOneOf(tok::period, tok::arrow)) Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow); else { SourceLocation Loc = D.getCXXScopeSpec().getEndLoc(); @@ -5310,7 +5510,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, if (getLangOpts().CPlusPlus) { // FIXME: Accept these components in any order, and produce fixits to // correct the order if the user gets it wrong. Ideally we should deal - // with the virt-specifier-seq and pure-specifier in the same way. + // with the pure-specifier in the same way. // Parse cv-qualifier-seq[opt]. ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, @@ -5323,15 +5523,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, } // Parse ref-qualifier[opt]. - if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { - Diag(Tok, getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_ref_qualifier : - diag::ext_ref_qualifier); - - RefQualifierIsLValueRef = Tok.is(tok::amp); - RefQualifierLoc = ConsumeToken(); + if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc)) EndLoc = RefQualifierLoc; - } // C++11 [expr.prim.general]p3: // If a declaration declares a member function or member function @@ -5427,6 +5620,22 @@ void Parser::ParseFunctionDeclarator(Declarator &D, FnAttrs, EndLoc); } +/// ParseRefQualifier - Parses a member function ref-qualifier. Returns +/// true if a ref-qualifier is found. +bool Parser::ParseRefQualifier(bool &RefQualifierIsLValueRef, + SourceLocation &RefQualifierLoc) { + if (Tok.isOneOf(tok::amp, tok::ampamp)) { + Diag(Tok, getLangOpts().CPlusPlus11 ? + diag::warn_cxx98_compat_ref_qualifier : + diag::ext_ref_qualifier); + + RefQualifierIsLValueRef = Tok.is(tok::amp); + RefQualifierLoc = ConsumeToken(); + return true; + } + return false; +} + /// isFunctionDeclaratorIdentifierList - This parameter list may have an /// identifier list form for a K&R-style function: void foo(a,b,c) /// diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp index 87d9909..e347d4e 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp @@ -543,10 +543,11 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, SourceLocation IdLoc = ConsumeToken(); ParsedType Type = Actions.getInheritingConstructorName(SS, IdLoc, *LastII); Name.setConstructorName(Type, IdLoc, IdLoc); - } else if (ParseUnqualifiedId(SS, /*EnteringContext=*/ false, - /*AllowDestructorName=*/ true, - /*AllowConstructorName=*/ true, ParsedType(), - TemplateKWLoc, Name)) { + } else if (ParseUnqualifiedId( + SS, /*EnteringContext=*/false, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/NextToken().isNot(tok::equal), + ParsedType(), TemplateKWLoc, Name)) { SkipUntil(tok::semi); return nullptr; } @@ -558,6 +559,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, // Maybe this is an alias-declaration. TypeResult TypeAlias; bool IsAliasDecl = Tok.is(tok::equal); + Decl *DeclFromDeclSpec = nullptr; if (IsAliasDecl) { // If we had any misplaced attributes from earlier, this is where they // should have been written. @@ -612,10 +614,12 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier) << FixItHint::CreateRemoval(SS.getRange()); - TypeAlias = ParseTypeName(nullptr, TemplateInfo.Kind ? - Declarator::AliasTemplateContext : - Declarator::AliasDeclContext, AS, OwnedType, - &Attrs); + TypeAlias = ParseTypeName(nullptr, TemplateInfo.Kind + ? Declarator::AliasTemplateContext + : Declarator::AliasDeclContext, + AS, &DeclFromDeclSpec, &Attrs); + if (OwnedType) + *OwnedType = DeclFromDeclSpec; } else { // C++11 attributes are not allowed on a using-declaration, but GNU ones // are. @@ -664,7 +668,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, TemplateParams ? TemplateParams->size() : 0); return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg, UsingLoc, Name, Attrs.getList(), - TypeAlias); + TypeAlias, DeclFromDeclSpec); } return Actions.ActOnUsingDeclaration(getCurScope(), AS, @@ -682,7 +686,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, /// _Static_assert ( constant-expression , string-literal ) ; /// Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ - assert((Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) && + assert(Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert) && "Not a static_assert declaration"); if (Tok.is(tok::kw__Static_assert) && !getLangOpts().C11) @@ -750,7 +754,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ /// 'decltype' ( 'auto' ) [C++1y] /// SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { - assert((Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) + assert(Tok.isOneOf(tok::kw_decltype, tok::annot_decltype) && "Not a decltype specifier"); ExprResult Result; @@ -796,7 +800,10 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { // The operand of the decltype specifier is an unevaluated operand. EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, nullptr,/*IsDecltype=*/true); - Result = Actions.CorrectDelayedTyposInExpr(ParseExpression()); + Result = + Actions.CorrectDelayedTyposInExpr(ParseExpression(), [](Expr *E) { + return E->hasPlaceholderType() ? ExprError() : E; + }); if (Result.isInvalid()) { DS.SetTypeSpecError(); if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) { @@ -937,7 +944,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, // Parse decltype-specifier // tok == kw_decltype is just error recovery, it can only happen when SS // isn't empty - if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) { + if (Tok.isOneOf(tok::kw_decltype, tok::annot_decltype)) { if (SS.isNotEmpty()) Diag(SS.getBeginLoc(), diag::err_unexpected_scope_on_base_decltype) << FixItHint::CreateRemoval(SS.getRange()); @@ -1052,9 +1059,9 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, } void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) { - while (Tok.is(tok::kw___single_inheritance) || - Tok.is(tok::kw___multiple_inheritance) || - Tok.is(tok::kw___virtual_inheritance)) { + while (Tok.isOneOf(tok::kw___single_inheritance, + tok::kw___multiple_inheritance, + tok::kw___virtual_inheritance)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, @@ -1223,15 +1230,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, ParsedAttributesWithRange attrs(AttrFactory); // If attributes exist after tag, parse them. MaybeParseGNUAttributes(attrs); - - // If declspecs exist after tag, parse them. - while (Tok.is(tok::kw___declspec)) - ParseMicrosoftDeclSpec(attrs); + MaybeParseMicrosoftDeclSpecs(attrs); // Parse inheritance specifiers. - if (Tok.is(tok::kw___single_inheritance) || - Tok.is(tok::kw___multiple_inheritance) || - Tok.is(tok::kw___virtual_inheritance)) + if (Tok.isOneOf(tok::kw___single_inheritance, + tok::kw___multiple_inheritance, + tok::kw___virtual_inheritance)) ParseMicrosoftInheritanceClassAttributes(attrs); // If C++0x attributes exist here, parse them. @@ -1247,55 +1251,55 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Tok.isNot(tok::identifier) && !Tok.isAnnotation() && Tok.getIdentifierInfo() && - (Tok.is(tok::kw___is_abstract) || - Tok.is(tok::kw___is_arithmetic) || - Tok.is(tok::kw___is_array) || - Tok.is(tok::kw___is_base_of) || - Tok.is(tok::kw___is_class) || - Tok.is(tok::kw___is_complete_type) || - Tok.is(tok::kw___is_compound) || - Tok.is(tok::kw___is_const) || - Tok.is(tok::kw___is_constructible) || - Tok.is(tok::kw___is_convertible) || - Tok.is(tok::kw___is_convertible_to) || - Tok.is(tok::kw___is_destructible) || - Tok.is(tok::kw___is_empty) || - Tok.is(tok::kw___is_enum) || - Tok.is(tok::kw___is_floating_point) || - Tok.is(tok::kw___is_final) || - Tok.is(tok::kw___is_function) || - Tok.is(tok::kw___is_fundamental) || - Tok.is(tok::kw___is_integral) || - Tok.is(tok::kw___is_interface_class) || - Tok.is(tok::kw___is_literal) || - Tok.is(tok::kw___is_lvalue_expr) || - Tok.is(tok::kw___is_lvalue_reference) || - Tok.is(tok::kw___is_member_function_pointer) || - Tok.is(tok::kw___is_member_object_pointer) || - Tok.is(tok::kw___is_member_pointer) || - Tok.is(tok::kw___is_nothrow_assignable) || - Tok.is(tok::kw___is_nothrow_constructible) || - Tok.is(tok::kw___is_nothrow_destructible) || - Tok.is(tok::kw___is_object) || - Tok.is(tok::kw___is_pod) || - Tok.is(tok::kw___is_pointer) || - Tok.is(tok::kw___is_polymorphic) || - Tok.is(tok::kw___is_reference) || - Tok.is(tok::kw___is_rvalue_expr) || - Tok.is(tok::kw___is_rvalue_reference) || - Tok.is(tok::kw___is_same) || - Tok.is(tok::kw___is_scalar) || - Tok.is(tok::kw___is_sealed) || - Tok.is(tok::kw___is_signed) || - Tok.is(tok::kw___is_standard_layout) || - Tok.is(tok::kw___is_trivial) || - Tok.is(tok::kw___is_trivially_assignable) || - Tok.is(tok::kw___is_trivially_constructible) || - Tok.is(tok::kw___is_trivially_copyable) || - Tok.is(tok::kw___is_union) || - Tok.is(tok::kw___is_unsigned) || - Tok.is(tok::kw___is_void) || - Tok.is(tok::kw___is_volatile))) + Tok.isOneOf(tok::kw___is_abstract, + tok::kw___is_arithmetic, + tok::kw___is_array, + tok::kw___is_base_of, + tok::kw___is_class, + tok::kw___is_complete_type, + tok::kw___is_compound, + tok::kw___is_const, + tok::kw___is_constructible, + tok::kw___is_convertible, + tok::kw___is_convertible_to, + tok::kw___is_destructible, + tok::kw___is_empty, + tok::kw___is_enum, + tok::kw___is_floating_point, + tok::kw___is_final, + tok::kw___is_function, + tok::kw___is_fundamental, + tok::kw___is_integral, + tok::kw___is_interface_class, + tok::kw___is_literal, + tok::kw___is_lvalue_expr, + tok::kw___is_lvalue_reference, + tok::kw___is_member_function_pointer, + tok::kw___is_member_object_pointer, + tok::kw___is_member_pointer, + tok::kw___is_nothrow_assignable, + tok::kw___is_nothrow_constructible, + tok::kw___is_nothrow_destructible, + tok::kw___is_object, + tok::kw___is_pod, + tok::kw___is_pointer, + tok::kw___is_polymorphic, + tok::kw___is_reference, + tok::kw___is_rvalue_expr, + tok::kw___is_rvalue_reference, + tok::kw___is_same, + tok::kw___is_scalar, + tok::kw___is_sealed, + tok::kw___is_signed, + tok::kw___is_standard_layout, + tok::kw___is_trivial, + tok::kw___is_trivially_assignable, + tok::kw___is_trivially_constructible, + tok::kw___is_trivially_copyable, + tok::kw___is_union, + tok::kw___is_unsigned, + tok::kw___is_void, + tok::kw___is_volatile)) // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the // name of struct templates, but some are keywords in GCC >= 4.3 // and Clang. Therefore, when we see the token sequence "struct @@ -1310,11 +1314,19 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // is a base-specifier-list. ColonProtectionRAIIObject X(*this); - if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) + CXXScopeSpec Spec; + bool HasValidSpec = true; + if (ParseOptionalCXXScopeSpecifier(Spec, ParsedType(), EnteringContext)) { DS.SetTypeSpecError(); - if (SS.isSet()) - if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) + HasValidSpec = false; + } + if (Spec.isSet()) + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) { Diag(Tok, diag::err_expected) << tok::identifier; + HasValidSpec = false; + } + if (HasValidSpec) + SS = Spec; } TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; @@ -1465,7 +1477,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } } - if (Tok.is(tok::l_brace) || Tok.is(tok::colon)) + if (Tok.isOneOf(tok::l_brace, tok::colon)) TUK = Sema::TUK_Definition; else TUK = Sema::TUK_Reference; @@ -1539,6 +1551,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TypeResult TypeResult = true; // invalid bool Owned = false; + Sema::SkipBodyInfo SkipBody; if (TemplateId) { // Explicit specialization, class template partial specialization, // or explicit instantiation. @@ -1625,7 +1638,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, *TemplateId, attrs.getList(), MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0] : nullptr, - TemplateParams ? TemplateParams->size() : 0)); + TemplateParams ? TemplateParams->size() : 0), + &SkipBody); } } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Sema::TUK_Declaration) { @@ -1677,6 +1691,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TParams = MultiTemplateParamsArg(&(*TemplateParams)[0], TemplateParams->size()); + handleDeclspecAlignBeforeClassKey(attrs, DS, TUK); + // Declaration or definition of a class type TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc, SS, Name, NameLoc, attrs.getList(), AS, @@ -1684,7 +1700,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TParams, Owned, IsDependent, SourceLocation(), false, clang::TypeResult(), - DSC == DSC_type_specifier); + DSC == DSC_type_specifier, + &SkipBody); // If ActOnTag said the type was dependent, try again with the // less common call. @@ -1700,7 +1717,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, assert(Tok.is(tok::l_brace) || (getLangOpts().CPlusPlus && Tok.is(tok::colon)) || isCXX11FinalKeyword()); - if (getLangOpts().CPlusPlus) + if (SkipBody.ShouldSkip) + SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType, + TagOrTempResult.get()); + else if (getLangOpts().CPlusPlus) ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType, TagOrTempResult.get()); else @@ -1882,51 +1902,40 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const { /// the class definition. void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, Decl *ThisDecl) { - // We just declared a member function. If this member function - // has any default arguments or an exception-specification, we'll need to - // parse them later. - LateParsedMethodDeclaration *LateMethod = nullptr; DeclaratorChunk::FunctionTypeInfo &FTI = DeclaratorInfo.getFunctionTypeInfo(); + // If there was a late-parsed exception-specification, we'll need a + // late parse + bool NeedLateParse = FTI.getExceptionSpecType() == EST_Unparsed; + + if (!NeedLateParse) { + // Look ahead to see if there are any default args + for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) { + auto Param = cast<ParmVarDecl>(FTI.Params[ParamIdx].Param); + if (Param->hasUnparsedDefaultArg()) { + NeedLateParse = true; + break; + } + } + } - // If there was a late-parsed exception-specification, hold onto its tokens. - if (FTI.getExceptionSpecType() == EST_Unparsed) { + if (NeedLateParse) { // Push this method onto the stack of late-parsed method // declarations. - LateMethod = new LateParsedMethodDeclaration(this, ThisDecl); + auto LateMethod = new LateParsedMethodDeclaration(this, ThisDecl); getCurrentClass().LateParsedDeclarations.push_back(LateMethod); LateMethod->TemplateScope = getCurScope()->isTemplateParamScope(); - // Stash the exception-specification tokens in the late-pased mthod. + // Stash the exception-specification tokens in the late-pased method. LateMethod->ExceptionSpecTokens = FTI.ExceptionSpecTokens; FTI.ExceptionSpecTokens = 0; - // Reserve space for the parameters. + // Push tokens for each parameter. Those that do not have + // defaults will be NULL. LateMethod->DefaultArgs.reserve(FTI.NumParams); - } - - for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) { - if (LateMethod || FTI.Params[ParamIdx].DefaultArgTokens) { - if (!LateMethod) { - // Push this method onto the stack of late-parsed method - // declarations. - LateMethod = new LateParsedMethodDeclaration(this, ThisDecl); - getCurrentClass().LateParsedDeclarations.push_back(LateMethod); - LateMethod->TemplateScope = getCurScope()->isTemplateParamScope(); - - // Add all of the parameters prior to this one (they don't - // have default arguments). - LateMethod->DefaultArgs.reserve(FTI.NumParams); - for (unsigned I = 0; I < ParamIdx; ++I) - LateMethod->DefaultArgs.push_back( - LateParsedDefaultArgument(FTI.Params[I].Param)); - } - - // Add this parameter to the list of parameters (it may or may - // not have a default argument). + for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) LateMethod->DefaultArgs.push_back(LateParsedDefaultArgument( - FTI.Params[ParamIdx].Param, FTI.Params[ParamIdx].DefaultArgTokens)); - } + FTI.Params[ParamIdx].Param, FTI.Params[ParamIdx].DefaultArgTokens)); } } @@ -2019,7 +2028,7 @@ bool Parser::isCXX11FinalKeyword() const { /// \brief Parse a C++ member-declarator up to, but not including, the optional /// brace-or-equal-initializer or pure-specifier. -void Parser::ParseCXXMemberDeclaratorBeforeInitializer( +bool Parser::ParseCXXMemberDeclaratorBeforeInitializer( Declarator &DeclaratorInfo, VirtSpecifiers &VS, ExprResult &BitfieldSize, LateParsedAttrList &LateParsedAttrs) { // member-declarator: @@ -2037,10 +2046,13 @@ void Parser::ParseCXXMemberDeclaratorBeforeInitializer( BitfieldSize = ParseConstantExpression(); if (BitfieldSize.isInvalid()) SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); - } else + } else { ParseOptionalCXX11VirtSpecifierSeq( VS, getCurrentClass().IsInterface, DeclaratorInfo.getDeclSpec().getFriendSpecLoc()); + if (!VS.isUnset()) + MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(DeclaratorInfo, VS); + } // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { @@ -2071,6 +2083,78 @@ void Parser::ParseCXXMemberDeclaratorBeforeInitializer( Diag(Attr->getLoc(), diag::warn_gcc_attribute_location); Attr = Attr->getNext(); } + MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(DeclaratorInfo, VS); + } + } + + // If this has neither a name nor a bit width, something has gone seriously + // wrong. Skip until the semi-colon or }. + if (!DeclaratorInfo.hasName() && BitfieldSize.isUnset()) { + // If so, skip until the semi-colon or a }. + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); + return true; + } + return false; +} + +/// \brief Look for declaration specifiers possibly occurring after C++11 +/// virt-specifier-seq and diagnose them. +void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq( + Declarator &D, + VirtSpecifiers &VS) { + DeclSpec DS(AttrFactory); + + // GNU-style and C++11 attributes are not allowed here, but they will be + // handled by the caller. Diagnose everything else. + ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, false); + D.ExtendWithDeclSpec(DS); + + if (D.isFunctionDeclarator()) { + auto &Function = D.getFunctionTypeInfo(); + if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) { + auto DeclSpecCheck = [&] (DeclSpec::TQ TypeQual, + const char *FixItName, + SourceLocation SpecLoc, + unsigned* QualifierLoc) { + FixItHint Insertion; + if (DS.getTypeQualifiers() & TypeQual) { + if (!(Function.TypeQuals & TypeQual)) { + std::string Name(FixItName); + Name += " "; + Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name.c_str()); + Function.TypeQuals |= TypeQual; + *QualifierLoc = SpecLoc.getRawEncoding(); + } + Diag(SpecLoc, diag::err_declspec_after_virtspec) + << FixItName + << VirtSpecifiers::getSpecifierName(VS.getLastSpecifier()) + << FixItHint::CreateRemoval(SpecLoc) + << Insertion; + } + }; + DeclSpecCheck(DeclSpec::TQ_const, "const", DS.getConstSpecLoc(), + &Function.ConstQualifierLoc); + DeclSpecCheck(DeclSpec::TQ_volatile, "volatile", DS.getVolatileSpecLoc(), + &Function.VolatileQualifierLoc); + DeclSpecCheck(DeclSpec::TQ_restrict, "restrict", DS.getRestrictSpecLoc(), + &Function.RestrictQualifierLoc); + } + + // Parse ref-qualifiers. + bool RefQualifierIsLValueRef = true; + SourceLocation RefQualifierLoc; + if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc)) { + const char *Name = (RefQualifierIsLValueRef ? "& " : "&& "); + FixItHint Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name); + Function.RefQualifierIsLValueRef = RefQualifierIsLValueRef; + Function.RefQualifierLoc = RefQualifierLoc.getRawEncoding(); + + Diag(RefQualifierLoc, diag::err_declspec_after_virtspec) + << (RefQualifierIsLValueRef ? "&" : "&&") + << VirtSpecifiers::getSpecifierName(VS.getLastSpecifier()) + << FixItHint::CreateRemoval(RefQualifierLoc) + << Insertion; + D.SetRangeEnd(RefQualifierLoc); } } } @@ -2137,8 +2221,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Access declarations. bool MalformedTypeSpec = false; if (!TemplateInfo.Kind && - (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || - Tok.is(tok::kw___super))) { + Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw___super)) { if (TryAnnotateCXXScopeToken()) MalformedTypeSpec = true; @@ -2191,7 +2274,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // static_assert-declaration. A templated static_assert declaration is // diagnosed in Parser::ParseSingleDeclarationAfterTemplate. if (!TemplateInfo.Kind && - (Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert))) { + Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) { SourceLocation DeclEnd; ParseStaticAssertDeclaration(DeclEnd); return; @@ -2290,22 +2373,36 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, LateParsedAttrList LateParsedAttrs; SourceLocation EqualLoc; - bool HasInitializer = false; - ExprResult Init; + SourceLocation PureSpecLoc; + + auto TryConsumePureSpecifier = [&] (bool AllowDefinition) { + if (Tok.isNot(tok::equal)) + return false; + + auto &Zero = NextToken(); + SmallString<8> Buffer; + if (Zero.isNot(tok::numeric_constant) || Zero.getLength() != 1 || + PP.getSpelling(Zero, Buffer) != "0") + return false; + + auto &After = GetLookAheadToken(2); + if (!After.isOneOf(tok::semi, tok::comma) && + !(AllowDefinition && + After.isOneOf(tok::l_brace, tok::colon, tok::kw_try))) + return false; + + EqualLoc = ConsumeToken(); + PureSpecLoc = ConsumeToken(); + return true; + }; SmallVector<Decl *, 8> DeclsInGroup; ExprResult BitfieldSize; bool ExpectSemi = true; // Parse the first declarator. - ParseCXXMemberDeclaratorBeforeInitializer(DeclaratorInfo, VS, BitfieldSize, - LateParsedAttrs); - - // If this has neither a name nor a bit width, something has gone seriously - // wrong. Skip until the semi-colon or }. - if (!DeclaratorInfo.hasName() && BitfieldSize.isUnset()) { - // If so, skip until the semi-colon or a }. - SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); + if (ParseCXXMemberDeclaratorBeforeInitializer( + DeclaratorInfo, VS, BitfieldSize, LateParsedAttrs)) { TryConsumeToken(tok::semi); return; } @@ -2314,16 +2411,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (BitfieldSize.isUnset()) { // MSVC permits pure specifier on inline functions defined at class scope. // Hence check for =0 before checking for function definition. - if (getLangOpts().MicrosoftExt && Tok.is(tok::equal) && - DeclaratorInfo.isFunctionDeclarator() && - NextToken().is(tok::numeric_constant)) { - EqualLoc = ConsumeToken(); - Init = ParseInitializer(); - if (Init.isInvalid()) - SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); - else - HasInitializer = true; - } + if (getLangOpts().MicrosoftExt && DeclaratorInfo.isDeclarationOfFunction()) + TryConsumePureSpecifier(/*AllowDefinition*/ true); FunctionDefinitionKind DefinitionKind = FDK_Declaration; // function-definition: @@ -2334,7 +2423,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (Tok.is(tok::l_brace) && !getLangOpts().CPlusPlus11) { DefinitionKind = FDK_Definition; } else if (DeclaratorInfo.isFunctionDeclarator()) { - if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) { + if (Tok.isOneOf(tok::l_brace, tok::colon, tok::kw_try)) { DefinitionKind = FDK_Definition; } else if (Tok.is(tok::equal)) { const Token &KW = NextToken(); @@ -2344,6 +2433,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, DefinitionKind = FDK_Deleted; } } + DeclaratorInfo.setFunctionDefinitionKind(DefinitionKind); // C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains // to a friend declaration, that declaration shall be a definition. @@ -2354,7 +2444,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ProhibitAttributes(FnAttrs); } - if (DefinitionKind) { + if (DefinitionKind != FDK_Declaration) { if (!DeclaratorInfo.isFunctionDeclarator()) { Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params); ConsumeBrace(); @@ -2376,7 +2466,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, Decl *FunDecl = ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo, - VS, DefinitionKind, Init); + VS, PureSpecLoc); if (FunDecl) { for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) { @@ -2402,16 +2492,25 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, while (1) { InClassInitStyle HasInClassInit = ICIS_NoInit; - if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) { + bool HasStaticInitializer = false; + if (Tok.isOneOf(tok::equal, tok::l_brace) && PureSpecLoc.isInvalid()) { if (BitfieldSize.get()) { Diag(Tok, diag::err_bitfield_member_init); SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); + } else if (DeclaratorInfo.isDeclarationOfFunction()) { + // It's a pure-specifier. + if (!TryConsumePureSpecifier(/*AllowFunctionDefinition*/ false)) + // Parse it as an expression so that Sema can diagnose it. + HasStaticInitializer = true; + } else if (DeclaratorInfo.getDeclSpec().getStorageClassSpec() != + DeclSpec::SCS_static && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() != + DeclSpec::SCS_typedef && + !DS.isFriendSpecified()) { + // It's a default member initializer. + HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit; } else { - HasInitializer = true; - if (!DeclaratorInfo.isDeclarationOfFunction() && - DeclaratorInfo.getDeclSpec().getStorageClassSpec() - != DeclSpec::SCS_typedef) - HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit; + HasStaticInitializer = true; } } @@ -2451,10 +2550,20 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs); } - // Handle the initializer. + // Error recovery might have converted a non-static member into a static + // member. if (HasInClassInit != ICIS_NoInit && - DeclaratorInfo.getDeclSpec().getStorageClassSpec() != - DeclSpec::SCS_static) { + DeclaratorInfo.getDeclSpec().getStorageClassSpec() == + DeclSpec::SCS_static) { + HasInClassInit = ICIS_NoInit; + HasStaticInitializer = true; + } + + if (ThisDecl && PureSpecLoc.isValid()) + Actions.ActOnPureSpecifier(ThisDecl, PureSpecLoc); + + // Handle the initializer. + if (HasInClassInit != ICIS_NoInit) { // The initializer was deferred; parse it and cache the tokens. Diag(Tok, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_nonstatic_member_init @@ -2474,11 +2583,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ThisDecl->setInvalidDecl(); } else ParseCXXNonStaticMemberInitializer(ThisDecl); - } else if (HasInitializer) { + } else if (HasStaticInitializer) { // Normal initializer. - if (!Init.isUsable()) - Init = ParseCXXMemberInitializer( - ThisDecl, DeclaratorInfo.isDeclarationOfFunction(), EqualLoc); + ExprResult Init = ParseCXXMemberInitializer( + ThisDecl, DeclaratorInfo.isDeclarationOfFunction(), EqualLoc); if (Init.isInvalid()) SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); @@ -2530,16 +2638,16 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Parse the next declarator. DeclaratorInfo.clear(); VS.clear(); - BitfieldSize = true; - Init = true; - HasInitializer = false; + BitfieldSize = ExprResult(/*Invalid=*/false); + EqualLoc = PureSpecLoc = SourceLocation(); DeclaratorInfo.setCommaLoc(CommaLoc); // GNU attributes are allowed before the second and subsequent declarator. MaybeParseGNUAttributes(DeclaratorInfo); - ParseCXXMemberDeclaratorBeforeInitializer(DeclaratorInfo, VS, BitfieldSize, - LateParsedAttrs); + if (ParseCXXMemberDeclaratorBeforeInitializer( + DeclaratorInfo, VS, BitfieldSize, LateParsedAttrs)) + break; } if (ExpectSemi && @@ -2554,13 +2662,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup); } -/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or -/// pure-specifier. Also detect and reject any attempted defaulted/deleted -/// function definition. The location of the '=', if any, will be placed in -/// EqualLoc. +/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer. +/// Also detect and reject any attempted defaulted/deleted function definition. +/// The location of the '=', if any, will be placed in EqualLoc. /// -/// pure-specifier: -/// '= 0' +/// This does not check for a pure-specifier; that's handled elsewhere. /// /// brace-or-equal-initializer: /// '=' initializer-expression @@ -2578,7 +2684,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, /// be a constant-expression. ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, SourceLocation &EqualLoc) { - assert((Tok.is(tok::equal) || Tok.is(tok::l_brace)) + assert(Tok.isOneOf(tok::equal, tok::l_brace) && "Data member initializer not starting with '=' or '{'"); EnterExpressionEvaluationContext Context(Actions, @@ -2592,8 +2698,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, // An initializer of '= delete p, foo' will never be parsed, because // a top-level comma always ends the initializer expression. const Token &Next = NextToken(); - if (IsFunction || Next.is(tok::semi) || Next.is(tok::comma) || - Next.is(tok::eof)) { + if (IsFunction || Next.isOneOf(tok::semi, tok::comma, tok::eof)) { if (IsFunction) Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) << 1 /* delete */; @@ -2617,6 +2722,61 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, return ParseInitializer(); } +void Parser::SkipCXXMemberSpecification(SourceLocation RecordLoc, + SourceLocation AttrFixitLoc, + unsigned TagType, Decl *TagDecl) { + // Skip the optional 'final' keyword. + if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) { + assert(isCXX11FinalKeyword() && "not a class definition"); + ConsumeToken(); + + // Diagnose any C++11 attributes after 'final' keyword. + // We deliberately discard these attributes. + ParsedAttributesWithRange Attrs(AttrFactory); + CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc); + + // This can only happen if we had malformed misplaced attributes; + // we only get called if there is a colon or left-brace after the + // attributes. + if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_brace)) + return; + } + + // Skip the base clauses. This requires actually parsing them, because + // otherwise we can't be sure where they end (a left brace may appear + // within a template argument). + if (Tok.is(tok::colon)) { + // Enter the scope of the class so that we can correctly parse its bases. + ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope); + ParsingClassDefinition ParsingDef(*this, TagDecl, /*NonNestedClass*/ true, + TagType == DeclSpec::TST_interface); + auto OldContext = + Actions.ActOnTagStartSkippedDefinition(getCurScope(), TagDecl); + + // Parse the bases but don't attach them to the class. + ParseBaseClause(nullptr); + + Actions.ActOnTagFinishSkippedDefinition(OldContext); + + if (!Tok.is(tok::l_brace)) { + Diag(PP.getLocForEndOfToken(PrevTokLocation), + diag::err_expected_lbrace_after_base_specifiers); + return; + } + } + + // Skip the body. + assert(Tok.is(tok::l_brace)); + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); + T.skipToEnd(); + + // Parse and discard any trailing attributes. + ParsedAttributes Attrs(AttrFactory); + if (Tok.is(tok::kw___attribute)) + MaybeParseGNUAttributes(Attrs); +} + /// ParseCXXMemberSpecification - Parse the class definition. /// /// member-specification: @@ -2655,16 +2815,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, break; } - if ((S->getFlags() & Scope::FnScope)) { - // If we're in a function or function template declared in the - // body of a class, then this is a local class rather than a - // nested class. - const Scope *Parent = S->getParent(); - if (Parent->isTemplateParamScope()) - Parent = Parent->getParent(); - if (Parent->isClassScope()) - break; - } + if ((S->getFlags() & Scope::FnScope)) + // If we're in a function or function template then this is a local + // class rather than a nested class. + break; } } @@ -2787,8 +2941,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { // Each iteration of this loop reads one member-declaration. - if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) || - Tok.is(tok::kw___if_not_exists))) { + if (getLangOpts().MicrosoftExt && Tok.isOneOf(tok::kw___if_exists, + tok::kw___if_not_exists)) { ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); continue; } @@ -2911,6 +3065,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, ParseLexedMemberInitializers(getCurrentClass()); ParseLexedMethodDefs(getCurrentClass()); PrevTokLocation = SavedPrevTokLocation; + + // We've finished parsing everything, including default argument + // initializers. + Actions.ActOnFinishCXXMemberDefaultArgs(TagDecl); } if (TagDecl) @@ -2965,9 +3123,11 @@ void Parser::DiagnoseUnexpectedNamespace(NamedDecl *D) { /// mem-initializer ...[opt] /// mem-initializer ...[opt] , mem-initializer-list void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { - assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'"); + assert(Tok.is(tok::colon) && + "Constructor initializer always starts with ':'"); - // Poison the SEH identifiers so they are flagged as illegal in constructor initializers + // Poison the SEH identifiers so they are flagged as illegal in constructor + // initializers. PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true); SourceLocation ColonLoc = ConsumeToken(); @@ -2993,7 +3153,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { break; // If the next token looks like a base or member initializer, assume that // we're just missing a comma. - else if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) { + else if (Tok.isOneOf(tok::identifier, tok::coloncolon)) { SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation); Diag(Loc, diag::err_ctor_init_missing_comma) << FixItHint::CreateInsertion(Loc, ", "); @@ -3184,13 +3344,16 @@ Parser::tryParseExceptionSpecification(bool Delayed, T.consumeOpen(); NoexceptType = EST_ComputedNoexcept; NoexceptExpr = ParseConstantExpression(); + T.consumeClose(); // The argument must be contextually convertible to bool. We use // ActOnBooleanCondition for this purpose. - if (!NoexceptExpr.isInvalid()) + if (!NoexceptExpr.isInvalid()) { NoexceptExpr = Actions.ActOnBooleanCondition(getCurScope(), KeywordLoc, NoexceptExpr.get()); - T.consumeClose(); - NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation()); + NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation()); + } else { + NoexceptType = EST_None; + } } else { // There is no argument. NoexceptType = EST_BasicNoexcept; @@ -3396,7 +3559,9 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { // Alternative tokens do not have identifier info, but their spelling // starts with an alphabetical character. SmallString<8> SpellingBuf; - StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf); + SourceLocation SpellingLoc = + PP.getSourceManager().getSpellingLoc(Tok.getLocation()); + StringRef Spelling = PP.getSpelling(SpellingLoc, SpellingBuf); if (isLetter(Spelling[0])) { Loc = ConsumeToken(); return &PP.getIdentifierTable().get(Spelling); @@ -3474,7 +3639,6 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, // The attribute was allowed to have arguments, but none were provided // even though the attribute parsed successfully. This is an error. Diag(LParenLoc, diag::err_attribute_requires_arguments) << AttrName; - return false; } else if (!Attr->getMaxArgs()) { // The attribute parsed successfully, but was not allowed to have any // arguments. It doesn't matter whether any were provided -- the @@ -3482,7 +3646,6 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, Diag(LParenLoc, diag::err_cxx11_attribute_forbids_arguments) << AttrName << FixItHint::CreateRemoval(SourceRange(LParenLoc, *EndLoc)); - return false; } } } @@ -3645,7 +3808,7 @@ SourceLocation Parser::SkipCXX11Attributes() { return EndLoc; } -/// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr] +/// ParseMicrosoftAttributes - Parse Microsoft attributes [Attr] /// /// [MS] ms-attribute: /// '[' token-seq ']' @@ -3657,13 +3820,15 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, SourceLocation *endLoc) { assert(Tok.is(tok::l_square) && "Not a Microsoft attribute list"); - while (Tok.is(tok::l_square)) { + do { // FIXME: If this is actually a C++11 attribute, parse it as one. - ConsumeBracket(); + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch); - if (endLoc) *endLoc = Tok.getLocation(); - ExpectAndConsume(tok::r_square); - } + T.consumeClose(); + if (endLoc) + *endLoc = T.getCloseLocation(); + } while (Tok.is(tok::l_square)); } void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, @@ -3695,7 +3860,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { // __if_exists, __if_not_exists can nest. - if ((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { + if (Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) { ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); continue; } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp index d0d97de..b866798 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp @@ -205,6 +205,24 @@ ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { return Actions.ActOnConstantExpression(Res); } +/// \brief Parse a constraint-expression. +/// +/// \verbatim +/// constraint-expression: [Concepts TS temp.constr.decl p1] +/// logical-or-expression +/// \endverbatim +ExprResult Parser::ParseConstraintExpression() { + // FIXME: this may erroneously consume a function-body as the braced + // initializer list of a compound literal + // + // FIXME: this may erroneously consume a parenthesized rvalue reference + // declarator as a parenthesized address-of-label expression + ExprResult LHS(ParseCastExpression(/*isUnaryExpression=*/false)); + ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr)); + + return Res; +} + bool Parser::isNotExpressionStart() { tok::TokenKind K = Tok.getKind(); if (K == tok::l_brace || K == tok::r_brace || @@ -347,7 +365,11 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { RHS = ParseCastExpression(false); if (RHS.isInvalid()) { + // FIXME: Errors generated by the delayed typo correction should be + // printed before errors from parsing the RHS, not after. Actions.CorrectDelayedTyposInExpr(LHS); + if (TernaryMiddle.isUsable()) + TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle); LHS = ExprError(); } @@ -380,7 +402,11 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { RHSIsInitList = false; if (RHS.isInvalid()) { + // FIXME: Errors generated by the delayed typo correction should be + // printed before errors from ParseRHSOfBinaryExpression, not after. Actions.CorrectDelayedTyposInExpr(LHS); + if (TernaryMiddle.isUsable()) + TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle); LHS = ExprError(); } @@ -446,8 +472,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, namespace { class CastExpressionIdValidator : public CorrectionCandidateCallback { public: - CastExpressionIdValidator(bool AllowTypes, bool AllowNonTypes) - : AllowNonTypes(AllowNonTypes) { + CastExpressionIdValidator(Token Next, bool AllowTypes, bool AllowNonTypes) + : NextToken(Next), AllowNonTypes(AllowNonTypes) { WantTypeSpecifiers = WantFunctionLikeCasts = AllowTypes; } @@ -458,11 +484,23 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { if (isa<TypeDecl>(ND)) return WantTypeSpecifiers; - return AllowNonTypes && - CorrectionCandidateCallback::ValidateCandidate(candidate); + + if (!AllowNonTypes || !CorrectionCandidateCallback::ValidateCandidate(candidate)) + return false; + + if (!NextToken.isOneOf(tok::equal, tok::arrow, tok::period)) + return true; + + for (auto *C : candidate) { + NamedDecl *ND = C->getUnderlyingDecl(); + if (isa<ValueDecl>(ND) && !isa<FunctionDecl>(ND)) + return true; + } + return false; } private: + Token NextToken; bool AllowNonTypes; }; } @@ -808,11 +846,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, } } - if (Next.is(tok::coloncolon) || - (!ColonIsSacred && Next.is(tok::colon)) || - Next.is(tok::less) || - Next.is(tok::l_paren) || - Next.is(tok::l_brace)) { + if ((!ColonIsSacred && Next.is(tok::colon)) || + Next.isOneOf(tok::coloncolon, tok::less, tok::l_paren, + tok::l_brace)) { // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. if (TryAnnotateTypeOrScopeToken()) return ExprError(); @@ -908,14 +944,20 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, SourceLocation TemplateKWLoc; Token Replacement; auto Validator = llvm::make_unique<CastExpressionIdValidator>( - isTypeCast != NotTypeCast, isTypeCast != IsTypeCast); + Tok, isTypeCast != NotTypeCast, isTypeCast != IsTypeCast); Validator->IsAddressOfOperand = isAddressOfOperand; - Validator->WantRemainingKeywords = Tok.isNot(tok::r_paren); + if (Tok.isOneOf(tok::periodstar, tok::arrowstar)) { + Validator->WantExpressionKeywords = false; + Validator->WantRemainingKeywords = false; + } else { + Validator->WantRemainingKeywords = Tok.isNot(tok::r_paren); + } Name.setIdentifier(&II, ILoc); Res = Actions.ActOnIdExpression( getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren), isAddressOfOperand, std::move(Validator), - /*IsInlineAsmIdentifier=*/false, &Replacement); + /*IsInlineAsmIdentifier=*/false, + Tok.is(tok::r_paren) ? nullptr : &Replacement); if (!Res.isInvalid() && !Res.get()) { UnconsumeToken(Replacement); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, @@ -1018,6 +1060,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression // unary-expression: 'sizeof' '(' type-name ')' case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression + // unary-expression: '__builtin_omp_required_simd_align' '(' type-name ')' + case tok::kw___builtin_omp_required_simd_align: return ParseUnaryExprOrTypeTraitExpression(); case tok::ampamp: { // unary-expression: '&&' identifier SourceLocation AmpAmpLoc = ConsumeToken(); @@ -1441,10 +1485,14 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (OpKind == tok::l_paren || !LHS.isInvalid()) { if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs, &Sema::CodeCompleteCall, - LHS.get())) { + if (ParseExpressionList(ArgExprs, CommaLocs, [&] { + Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs); + })) { (void)Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); + } else if (LHS.isInvalid()) { + for (auto &E : ArgExprs) + Actions.CorrectDelayedTyposInExpr(E); } } } @@ -1453,7 +1501,19 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (LHS.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); } else if (Tok.isNot(tok::r_paren)) { - PT.consumeClose(); + bool HadDelayedTypo = false; + if (Actions.CorrectDelayedTyposInExpr(LHS).get() != LHS.get()) + HadDelayedTypo = true; + for (auto &E : ArgExprs) + if (Actions.CorrectDelayedTyposInExpr(E).get() != E) + HadDelayedTypo = true; + // If there were delayed typos in the LHS or ArgExprs, call SkipUntil + // instead of PT.consumeClose() to avoid emitting extra diagnostics for + // the unmatched l_paren. + if (HadDelayedTypo) + SkipUntil(tok::r_paren, StopAtSemi); + else + PT.consumeClose(); LHS = ExprError(); } else { assert((ArgExprs.size() == 0 || @@ -1510,14 +1570,14 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { cutOffParsing(); return ExprError(); } - + if (MayBePseudoDestructor && !LHS.isInvalid()) { LHS = ParseCXXPseudoDestructor(LHS.get(), OpLoc, OpKind, SS, ObjectType); break; } - // Either the action has told is that this cannot be a + // Either the action has told us that this cannot be a // pseudo-destructor expression (based on the type of base // expression), or we didn't see a '~' in the right place. We // can still parse a destructor name here, but in that case it @@ -1526,7 +1586,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // FIXME: Add support for explicit call of template constructor. SourceLocation TemplateKWLoc; UnqualifiedId Name; - if (getLangOpts().ObjC2 && OpKind == tok::period && Tok.is(tok::kw_class)) { + if (getLangOpts().ObjC2 && OpKind == tok::period && + Tok.is(tok::kw_class)) { // Objective-C++: // After a '.' in a member access expression, treat the keyword // 'class' as if it were an identifier. @@ -1551,8 +1612,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc, OpKind, SS, TemplateKWLoc, Name, CurParsedObjCImpl ? CurParsedObjCImpl->Dcl - : nullptr, - Tok.is(tok::l_paren)); + : nullptr); break; } case tok::plusplus: // postfix-expression: postfix-expression '++' @@ -1596,10 +1656,10 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, ParsedType &CastTy, SourceRange &CastRange) { - assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) || - OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof) || - OpTok.is(tok::kw__Alignof) || OpTok.is(tok::kw_vec_step)) && - "Not a typeof/sizeof/alignof/vec_step expression!"); + assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_sizeof, tok::kw___alignof, + tok::kw_alignof, tok::kw__Alignof, tok::kw_vec_step, + tok::kw___builtin_omp_required_simd_align) && + "Not a typeof/sizeof/alignof/vec_step expression!"); ExprResult Operand; @@ -1607,8 +1667,8 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, if (Tok.isNot(tok::l_paren)) { // If construct allows a form without parenthesis, user may forget to put // pathenthesis around type name. - if (OpTok.is(tok::kw_sizeof) || OpTok.is(tok::kw___alignof) || - OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw__Alignof)) { + if (OpTok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof, + tok::kw__Alignof)) { if (isTypeIdUnambiguously()) { DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); @@ -1682,9 +1742,9 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, /// [C++11] 'alignof' '(' type-id ')' /// \endverbatim ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { - assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof) || - Tok.is(tok::kw_alignof) || Tok.is(tok::kw__Alignof) || - Tok.is(tok::kw_vec_step)) && + assert(Tok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof, + tok::kw__Alignof, tok::kw_vec_step, + tok::kw___builtin_omp_required_simd_align) && "Not a sizeof/alignof/vec_step expression!"); Token OpTok = Tok; ConsumeToken(); @@ -1735,7 +1795,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { RParenLoc); } - if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw__Alignof)) + if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) Diag(OpTok, diag::warn_cxx98_compat_alignof); EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, @@ -1750,11 +1810,12 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { CastRange); UnaryExprOrTypeTrait ExprKind = UETT_SizeOf; - if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw___alignof) || - OpTok.is(tok::kw__Alignof)) + if (OpTok.isOneOf(tok::kw_alignof, tok::kw___alignof, tok::kw__Alignof)) ExprKind = UETT_AlignOf; else if (OpTok.is(tok::kw_vec_step)) ExprKind = UETT_VecStep; + else if (OpTok.is(tok::kw___builtin_omp_required_simd_align)) + ExprKind = UETT_OpenMPRequiredSimdAlign; if (isCastExpr) return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), @@ -1763,7 +1824,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { CastTy.getAsOpaquePtr(), CastRange); - if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw__Alignof)) + if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) Diag(OpTok, diag::ext_alignof_expr) << OpTok.getIdentifierInfo(); // If we get here, the operand to the sizeof/alignof was an expresion. @@ -2064,10 +2125,10 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // Diagnose use of bridge casts in non-arc mode. bool BridgeCast = (getLangOpts().ObjC2 && - (Tok.is(tok::kw___bridge) || - Tok.is(tok::kw___bridge_transfer) || - Tok.is(tok::kw___bridge_retained) || - Tok.is(tok::kw___bridge_retain))); + Tok.isOneOf(tok::kw___bridge, + tok::kw___bridge_transfer, + tok::kw___bridge_retained, + tok::kw___bridge_retain)); if (BridgeCast && !getLangOpts().ObjCAutoRefCount) { if (!TryConsumeToken(tok::kw___bridge)) { StringRef BridgeCastName = Tok.getName(); @@ -2088,6 +2149,17 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, if (!getCurScope()->getFnParent() && !getCurScope()->getBlockParent()) { Result = ExprError(Diag(OpenLoc, diag::err_stmtexpr_file_scope)); } else { + // Find the nearest non-record decl context. Variables declared in a + // statement expression behave as if they were declared in the enclosing + // function, block, or other code construct. + DeclContext *CodeDC = Actions.CurContext; + while (CodeDC->isRecord() || isa<EnumDecl>(CodeDC)) { + CodeDC = CodeDC->getParent(); + assert(CodeDC && !CodeDC->isFileContext() && + "statement expr not in code context"); + } + Sema::ContextRAII SavedContext(Actions, CodeDC, /*NewThisContext=*/false); + Actions.ActOnStartStmtExpr(); StmtResult Stmt(ParseCompoundStatement(true)); @@ -2256,6 +2328,11 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, InMessageExpressionRAIIObject InMessage(*this, false); Result = ParseExpression(MaybeTypeCast); + if (!getLangOpts().CPlusPlus && MaybeTypeCast && Result.isUsable()) { + // Correct typos in non-C++ code earlier so that implicit-cast-like + // expressions are parsed correctly. + Result = Actions.CorrectDelayedTyposInExpr(Result); + } ExprType = SimpleExpr; if (isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) @@ -2354,7 +2431,8 @@ ExprResult Parser::ParseGenericSelectionExpression() { // C11 6.5.1.1p3 "The controlling expression of a generic selection is // not evaluated." EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); - ControllingExpr = ParseAssignmentExpression(); + ControllingExpr = + Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); if (ControllingExpr.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); @@ -2400,7 +2478,8 @@ ExprResult Parser::ParseGenericSelectionExpression() { // FIXME: These expressions should be parsed in a potentially potentially // evaluated context. - ExprResult ER(ParseAssignmentExpression()); + ExprResult ER( + Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); if (ER.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); @@ -2493,17 +2572,14 @@ ExprResult Parser::ParseFoldExpression(ExprResult LHS, /// [C++0x] assignment-expression /// [C++0x] braced-init-list /// \endverbatim -bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs, +bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, SmallVectorImpl<SourceLocation> &CommaLocs, - void (Sema::*Completer)(Scope *S, - Expr *Data, - ArrayRef<Expr *> Args), - Expr *Data) { + std::function<void()> Completer) { bool SawError = false; while (1) { if (Tok.is(tok::code_completion)) { if (Completer) - (Actions.*Completer)(getCurScope(), Data, Exprs); + Completer(); else Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); cutOffParsing(); @@ -2588,9 +2664,6 @@ void Parser::ParseBlockId(SourceLocation CaretLoc) { Declarator DeclaratorInfo(DS, Declarator::BlockLiteralContext); ParseDeclarator(DeclaratorInfo); - // We do this for: ^ __attribute__((noreturn)) {, as DS has the attributes. - DeclaratorInfo.takeAttributes(DS.getAttributes(), SourceLocation()); - MaybeParseGNUAttributes(DeclaratorInfo); // Inform sema that we are starting a block. diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp index 67496ed..c1dafe9 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp @@ -118,6 +118,7 @@ void Parser::CheckForLParenAfterColonColon() { // Eat the '('. ConsumeParen(); Token RParen; + RParen.setLocation(SourceLocation()); // Do we have a ')' ? NextTok = StarTok.is(tok::star) ? GetLookAheadToken(2) : GetLookAheadToken(1); if (NextTok.is(tok::r_paren)) { @@ -194,6 +195,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, if (Tok.is(tok::annot_cxxscope)) { assert(!LastII && "want last identifier but have already annotated scope"); + assert(!MayBePseudoDestructor && "unexpected annot_cxxscope"); Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS); @@ -208,6 +210,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, SS = TemplateId->SS; } + // Has to happen before any "return false"s in this function. + bool CheckForDestructor = false; + if (MayBePseudoDestructor && *MayBePseudoDestructor) { + CheckForDestructor = true; + *MayBePseudoDestructor = false; + } + if (LastII) *LastII = nullptr; @@ -244,14 +253,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, return Actions.ActOnSuperScopeSpecifier(SuperLoc, ConsumeToken(), SS); } - bool CheckForDestructor = false; - if (MayBePseudoDestructor && *MayBePseudoDestructor) { - CheckForDestructor = true; - *MayBePseudoDestructor = false; - } - if (!HasScopeSpecifier && - (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype))) { + Tok.isOneOf(tok::kw_decltype, tok::annot_decltype)) { DeclSpec DS(AttrFactory); SourceLocation DeclLoc = Tok.getLocation(); SourceLocation EndLoc = ParseDecltypeSpecifier(DS); @@ -484,7 +487,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // as the name in a nested-name-specifier. Token Identifier = Tok; SourceLocation IdLoc = ConsumeToken(); - assert((Tok.is(tok::coloncolon) || Tok.is(tok::colon)) && + assert(Tok.isOneOf(tok::coloncolon, tok::colon) && "NextToken() not working properly!"); Token ColonColon = Tok; SourceLocation CCLoc = ConsumeToken(); @@ -659,7 +662,8 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); Token Replacement; - ExprResult Result = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement); + ExprResult Result = + tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement); if (Result.isUnset()) { // If the ExprResult is valid but null, then typo correction suggested a // keyword replacement that needs to be reparsed. @@ -888,7 +892,7 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, Parens.getCloseLocation(), Exprs); } - } else if (Tok.is(tok::l_brace) || Tok.is(tok::equal)) { + } else if (Tok.isOneOf(tok::l_brace, tok::equal)) { // Each lambda init-capture forms its own full expression, which clears // Actions.MaybeODRUseExprs. So create an expression evaluation context // to save the necessary state, and restore it later. @@ -1090,6 +1094,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( // compatible with GCC. MaybeParseGNUAttributes(Attr, &DeclEndLoc); + // MSVC-style attributes must be parsed before the mutable specifier to be + // compatible with MSVC. + MaybeParseMicrosoftDeclSpecs(Attr, &DeclEndLoc); + // Parse 'mutable'[opt]. SourceLocation MutableLoc; if (TryConsumeToken(tok::kw_mutable, MutableLoc)) @@ -1151,8 +1159,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( LParenLoc, FunLocalRangeEnd, D, TrailingReturnType), Attr, DeclEndLoc); - } else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow) || - Tok.is(tok::kw___attribute) || + } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute) || (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) { // It's common to forget that one needs '()' before 'mutable', an attribute // specifier, or the result type. Deal with this. @@ -1485,9 +1492,8 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc, ParseDecltypeSpecifier(DS); if (DS.getTypeSpecType() == TST_error) return ExprError(); - return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, - OpKind, TildeLoc, DS, - Tok.is(tok::l_paren)); + return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind, + TildeLoc, DS); } if (!Tok.is(tok::identifier)) { @@ -1510,11 +1516,9 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc, /*AssumeTemplateName=*/true)) return ExprError(); - return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, - OpLoc, OpKind, - SS, FirstTypeName, CCLoc, - TildeLoc, SecondTypeName, - Tok.is(tok::l_paren)); + return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind, + SS, FirstTypeName, CCLoc, TildeLoc, + SecondTypeName); } /// ParseCXXBoolLiteral - This handles the C++ Boolean literals. @@ -1602,7 +1606,11 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { CommaLocsTy CommaLocs; if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(Exprs, CommaLocs)) { + if (ParseExpressionList(Exprs, CommaLocs, [&] { + Actions.CodeCompleteConstructor(getCurScope(), + TypeRep.get()->getCanonicalTypeInternal(), + DS.getLocEnd(), Exprs); + })) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -1678,7 +1686,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, // type-specifier-seq DeclSpec DS(AttrFactory); DS.takeAttributesFrom(attrs); - ParseSpecifierQualifierList(DS); + ParseSpecifierQualifierList(DS, AS_none, DSC_condition); // declarator Declarator DeclaratorInfo(DS, Declarator::ConditionContext); @@ -1797,13 +1805,6 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. If we don't have Objective-C or a '<', this is - // just a normal reference to a typedef name. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); - DS.Finish(Diags, PP, Policy); return; } @@ -2509,14 +2510,23 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, } // If the user wrote ~T::T, correct it to T::~T. + DeclaratorScopeObj DeclScopeObj(*this, SS); if (!TemplateSpecified && NextToken().is(tok::coloncolon)) { + // Don't let ParseOptionalCXXScopeSpecifier() "correct" + // `int A; struct { ~A::A(); };` to `int A; struct { ~A:A(); };`, + // it will confuse this recovery logic. + ColonProtectionRAIIObject ColonRAII(*this, false); + if (SS.isSet()) { AnnotateScopeToken(SS, /*NewAnnotation*/true); SS.clear(); } if (ParseOptionalCXXScopeSpecifier(SS, ObjectType, EnteringContext)) return true; - if (Tok.isNot(tok::identifier) || NextToken().is(tok::coloncolon)) { + if (SS.isNotEmpty()) + ObjectType = ParsedType(); + if (Tok.isNot(tok::identifier) || NextToken().is(tok::coloncolon) || + !SS.isSet()) { Diag(TildeLoc, diag::err_destructor_tilde_scope); return true; } @@ -2525,6 +2535,10 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, Diag(TildeLoc, diag::err_destructor_tilde_scope) << FixItHint::CreateRemoval(TildeLoc) << FixItHint::CreateInsertion(Tok.getLocation(), "~"); + + // Temporarily enter the scope for the rest of this function. + if (Actions.ShouldEnterDeclaratorScope(getCurScope(), SS)) + DeclScopeObj.EnterDeclaratorScope(); } // Parse the class-name (or template-name in a simple-template-id). @@ -2668,7 +2682,14 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { ConstructorLParen = T.getOpenLocation(); if (Tok.isNot(tok::r_paren)) { CommaLocsTy CommaLocs; - if (ParseExpressionList(ConstructorArgs, CommaLocs)) { + if (ParseExpressionList(ConstructorArgs, CommaLocs, [&] { + ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), + DeclaratorInfo).get(); + Actions.CodeCompleteConstructor(getCurScope(), + TypeRep.get()->getCanonicalTypeInternal(), + DeclaratorInfo.getLocEnd(), + ConstructorArgs); + })) { SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp index 7fe9862..4896ff0 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp @@ -148,7 +148,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { Diag(NameLoc, diag::ext_gnu_old_style_field_designator) << FixItHint::CreateReplacement(SourceRange(NameLoc, ColonLoc), - NewSyntax.str()); + NewSyntax); Designation D; D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc)); @@ -252,26 +252,40 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { // Three cases. This is a message send to a type: [type foo] // This is a message send to super: [super foo] // This is a message sent to an expr: [super.bar foo] - switch (Sema::ObjCMessageKind Kind - = Actions.getObjCMessageKind(getCurScope(), II, IILoc, - II == Ident_super, - NextToken().is(tok::period), - ReceiverType)) { + switch (Actions.getObjCMessageKind( + getCurScope(), II, IILoc, II == Ident_super, + NextToken().is(tok::period), ReceiverType)) { case Sema::ObjCSuperMessage: + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + ConsumeToken(), + ParsedType(), + nullptr); + case Sema::ObjCClassMessage: CheckArrayDesignatorSyntax(*this, StartLoc, Desig); - if (Kind == Sema::ObjCSuperMessage) - return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, - ConsumeToken(), - ParsedType(), - nullptr); ConsumeToken(); // the identifier if (!ReceiverType) { SkipUntil(tok::r_square, StopAtSemi); return ExprError(); } - return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + // Parse type arguments and protocol qualifiers. + if (Tok.is(tok::less)) { + SourceLocation NewEndLoc; + TypeResult NewReceiverType + = parseObjCTypeArgsAndProtocolQualifiers(IILoc, ReceiverType, + /*consumeLastToken=*/true, + NewEndLoc); + if (!NewReceiverType.isUsable()) { + SkipUntil(tok::r_square, StopAtSemi); + return ExprError(); + } + + ReceiverType = NewReceiverType.get(); + } + + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, SourceLocation(), ReceiverType, nullptr); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp index a597a16..ed60904 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp @@ -13,6 +13,7 @@ #include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" +#include "clang/AST/ASTContext.h" #include "clang/Basic/CharInfo.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/DeclSpec.h" @@ -95,14 +96,17 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() { /// /// objc-class-declaration: -/// '@' 'class' identifier-list ';' +/// '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';' +/// +/// objc-class-forward-decl: +/// identifier objc-type-parameter-list[opt] /// Parser::DeclGroupPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { ConsumeToken(); // the identifier "class" SmallVector<IdentifierInfo *, 8> ClassNames; SmallVector<SourceLocation, 8> ClassLocs; - + SmallVector<ObjCTypeParamList *, 8> ClassTypeParams; while (1) { MaybeSkipAttributes(tok::objc_class); @@ -115,6 +119,14 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { ClassLocs.push_back(Tok.getLocation()); ConsumeToken(); + // Parse the optional objc-type-parameter-list. + ObjCTypeParamList *TypeParams = nullptr; + if (Tok.is(tok::less)) { + TypeParams = parseObjCTypeParamList(); + if (TypeParams) + Actions.popObjCTypeParamList(getCurScope(), TypeParams); + } + ClassTypeParams.push_back(TypeParams); if (!TryConsumeToken(tok::comma)) break; } @@ -125,6 +137,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(), ClassLocs.data(), + ClassTypeParams, ClassNames.size()); } @@ -153,20 +166,20 @@ void Parser::CheckNestedObjCContexts(SourceLocation AtLoc) /// objc-category-interface /// /// objc-class-interface: -/// '@' 'interface' identifier objc-superclass[opt] -/// objc-protocol-refs[opt] +/// '@' 'interface' identifier objc-type-parameter-list[opt] +/// objc-superclass[opt] objc-protocol-refs[opt] /// objc-class-instance-variables[opt] /// objc-interface-decl-list /// @end /// /// objc-category-interface: -/// '@' 'interface' identifier '(' identifier[opt] ')' -/// objc-protocol-refs[opt] +/// '@' 'interface' identifier objc-type-parameter-list[opt] +/// '(' identifier[opt] ')' objc-protocol-refs[opt] /// objc-interface-decl-list /// @end /// /// objc-superclass: -/// ':' identifier +/// ':' identifier objc-type-arguments[opt] /// /// objc-class-interface-attributes: /// __attribute__((visibility("default"))) @@ -201,7 +214,20 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); - if (Tok.is(tok::l_paren) && + + // Parse the objc-type-parameter-list or objc-protocol-refs. For the latter + // case, LAngleLoc will be valid and ProtocolIdents will capture the + // protocol references (that have not yet been resolved). + SourceLocation LAngleLoc, EndProtoLoc; + SmallVector<IdentifierLocPair, 8> ProtocolIdents; + ObjCTypeParamList *typeParameterList = nullptr; + if (Tok.is(tok::less)) { + typeParameterList = parseObjCTypeParamListOrProtocolRefs(LAngleLoc, + ProtocolIdents, + EndProtoLoc); + } + + if (Tok.is(tok::l_paren) && !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category. BalancedDelimiterTracker T(*this, tok::l_paren); @@ -236,17 +262,19 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, } // Next, we need to check for any protocol references. - SourceLocation LAngleLoc, EndProtoLoc; + assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols"); SmallVector<Decl *, 8> ProtocolRefs; SmallVector<SourceLocation, 8> ProtocolLocs; if (Tok.is(tok::less) && - ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, - LAngleLoc, EndProtoLoc)) + ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true, + LAngleLoc, EndProtoLoc, + /*consumeLastToken=*/true)) return nullptr; Decl *CategoryType = Actions.ActOnStartCategoryInterface(AtLoc, nameId, nameLoc, + typeParameterList, categoryId, categoryLoc, ProtocolRefs.data(), ProtocolRefs.size(), @@ -257,12 +285,20 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc); ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType); + + if (typeParameterList) + Actions.popObjCTypeParamList(getCurScope(), typeParameterList); + return CategoryType; } // Parse a class interface. IdentifierInfo *superClassId = nullptr; SourceLocation superClassLoc; - + SourceLocation typeArgsLAngleLoc; + SmallVector<ParsedType, 4> typeArgs; + SourceLocation typeArgsRAngleLoc; + SmallVector<Decl *, 4> protocols; + SmallVector<SourceLocation, 4> protocolLocs; if (Tok.is(tok::colon)) { // a super class is specified. ConsumeToken(); @@ -280,33 +316,295 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, } superClassId = Tok.getIdentifierInfo(); superClassLoc = ConsumeToken(); + + // Type arguments for the superclass or protocol conformances. + if (Tok.is(tok::less)) { + parseObjCTypeArgsOrProtocolQualifiers(ParsedType(), + typeArgsLAngleLoc, + typeArgs, + typeArgsRAngleLoc, + LAngleLoc, + protocols, + protocolLocs, + EndProtoLoc, + /*consumeLastToken=*/true, + /*warnOnIncompleteProtocols=*/true); + } } + // Next, we need to check for any protocol references. - SmallVector<Decl *, 8> ProtocolRefs; - SmallVector<SourceLocation, 8> ProtocolLocs; - SourceLocation LAngleLoc, EndProtoLoc; - if (Tok.is(tok::less) && - ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, - LAngleLoc, EndProtoLoc)) + if (LAngleLoc.isValid()) { + if (!ProtocolIdents.empty()) { + // We already parsed the protocols named when we thought we had a + // type parameter list. Translate them into actual protocol references. + for (const auto &pair : ProtocolIdents) { + protocolLocs.push_back(pair.second); + } + Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true, + /*ForObjCContainer=*/true, + &ProtocolIdents[0], ProtocolIdents.size(), + protocols); + } + } else if (protocols.empty() && Tok.is(tok::less) && + ParseObjCProtocolReferences(protocols, protocolLocs, true, true, + LAngleLoc, EndProtoLoc, + /*consumeLastToken=*/true)) { return nullptr; + } if (Tok.isNot(tok::less)) - Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc); + Actions.ActOnTypedefedProtocols(protocols, superClassId, superClassLoc); Decl *ClsType = - Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, - superClassId, superClassLoc, - ProtocolRefs.data(), ProtocolRefs.size(), - ProtocolLocs.data(), + Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc, + typeParameterList, superClassId, + superClassLoc, + typeArgs, + SourceRange(typeArgsLAngleLoc, + typeArgsRAngleLoc), + protocols.data(), protocols.size(), + protocolLocs.data(), EndProtoLoc, attrs.getList()); if (Tok.is(tok::l_brace)) ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc); ParseObjCInterfaceDeclList(tok::objc_interface, ClsType); + + if (typeParameterList) + Actions.popObjCTypeParamList(getCurScope(), typeParameterList); + return ClsType; } +/// Add an attribute for a context-sensitive type nullability to the given +/// declarator. +static void addContextSensitiveTypeNullability(Parser &P, + Declarator &D, + NullabilityKind nullability, + SourceLocation nullabilityLoc, + bool &addedToDeclSpec) { + // Create the attribute. + auto getNullabilityAttr = [&]() -> AttributeList * { + return D.getAttributePool().create( + P.getNullabilityKeyword(nullability), + SourceRange(nullabilityLoc), + nullptr, SourceLocation(), + nullptr, 0, + AttributeList::AS_ContextSensitiveKeyword); + }; + + if (D.getNumTypeObjects() > 0) { + // Add the attribute to the declarator chunk nearest the declarator. + auto nullabilityAttr = getNullabilityAttr(); + DeclaratorChunk &chunk = D.getTypeObject(0); + nullabilityAttr->setNext(chunk.getAttrListRef()); + chunk.getAttrListRef() = nullabilityAttr; + } else if (!addedToDeclSpec) { + // Otherwise, just put it on the declaration specifiers (if one + // isn't there already). + D.getMutableDeclSpec().addAttributes(getNullabilityAttr()); + addedToDeclSpec = true; + } +} + +/// Parse an Objective-C type parameter list, if present, or capture +/// the locations of the protocol identifiers for a list of protocol +/// references. +/// +/// objc-type-parameter-list: +/// '<' objc-type-parameter (',' objc-type-parameter)* '>' +/// +/// objc-type-parameter: +/// objc-type-parameter-variance? identifier objc-type-parameter-bound[opt] +/// +/// objc-type-parameter-bound: +/// ':' type-name +/// +/// objc-type-parameter-variance: +/// '__covariant' +/// '__contravariant' +/// +/// \param lAngleLoc The location of the starting '<'. +/// +/// \param protocolIdents Will capture the list of identifiers, if the +/// angle brackets contain a list of protocol references rather than a +/// type parameter list. +/// +/// \param rAngleLoc The location of the ending '>'. +ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs( + SourceLocation &lAngleLoc, + SmallVectorImpl<IdentifierLocPair> &protocolIdents, + SourceLocation &rAngleLoc, + bool mayBeProtocolList) { + assert(Tok.is(tok::less) && "Not at the beginning of a type parameter list"); + + // Within the type parameter list, don't treat '>' as an operator. + GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); + + // Local function to "flush" the protocol identifiers, turning them into + // type parameters. + SmallVector<Decl *, 4> typeParams; + auto makeProtocolIdentsIntoTypeParameters = [&]() { + unsigned index = 0; + for (const auto &pair : protocolIdents) { + DeclResult typeParam = Actions.actOnObjCTypeParam( + getCurScope(), + ObjCTypeParamVariance::Invariant, + SourceLocation(), + index++, + pair.first, + pair.second, + SourceLocation(), + ParsedType()); + if (typeParam.isUsable()) + typeParams.push_back(typeParam.get()); + } + + protocolIdents.clear(); + mayBeProtocolList = false; + }; + + bool invalid = false; + lAngleLoc = ConsumeToken(); + + do { + // Parse the variance, if any. + SourceLocation varianceLoc; + ObjCTypeParamVariance variance = ObjCTypeParamVariance::Invariant; + if (Tok.is(tok::kw___covariant) || Tok.is(tok::kw___contravariant)) { + variance = Tok.is(tok::kw___covariant) + ? ObjCTypeParamVariance::Covariant + : ObjCTypeParamVariance::Contravariant; + varianceLoc = ConsumeToken(); + + // Once we've seen a variance specific , we know this is not a + // list of protocol references. + if (mayBeProtocolList) { + // Up until now, we have been queuing up parameters because they + // might be protocol references. Turn them into parameters now. + makeProtocolIdentsIntoTypeParameters(); + } + } + + // Parse the identifier. + if (!Tok.is(tok::identifier)) { + // Code completion. + if (Tok.is(tok::code_completion)) { + // FIXME: If these aren't protocol references, we'll need different + // completions. + Actions.CodeCompleteObjCProtocolReferences(protocolIdents.data(), + protocolIdents.size()); + cutOffParsing(); + + // FIXME: Better recovery here?. + return nullptr; + } + + Diag(Tok, diag::err_objc_expected_type_parameter); + invalid = true; + break; + } + + IdentifierInfo *paramName = Tok.getIdentifierInfo(); + SourceLocation paramLoc = ConsumeToken(); + + // If there is a bound, parse it. + SourceLocation colonLoc; + TypeResult boundType; + if (TryConsumeToken(tok::colon, colonLoc)) { + // Once we've seen a bound, we know this is not a list of protocol + // references. + if (mayBeProtocolList) { + // Up until now, we have been queuing up parameters because they + // might be protocol references. Turn them into parameters now. + makeProtocolIdentsIntoTypeParameters(); + } + + // type-name + boundType = ParseTypeName(); + if (boundType.isInvalid()) + invalid = true; + } else if (mayBeProtocolList) { + // If this could still be a protocol list, just capture the identifier. + // We don't want to turn it into a parameter. + protocolIdents.push_back(std::make_pair(paramName, paramLoc)); + continue; + } + + // Create the type parameter. + DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(), + variance, + varianceLoc, + typeParams.size(), + paramName, + paramLoc, + colonLoc, + boundType.isUsable() + ? boundType.get() + : ParsedType()); + if (typeParam.isUsable()) + typeParams.push_back(typeParam.get()); + } while (TryConsumeToken(tok::comma)); + + // Parse the '>'. + if (invalid) { + SkipUntil(tok::greater, tok::at, StopBeforeMatch); + if (Tok.is(tok::greater)) + ConsumeToken(); + } else if (ParseGreaterThanInTemplateList(rAngleLoc, + /*ConsumeLastToken=*/true, + /*ObjCGenericList=*/true)) { + Diag(lAngleLoc, diag::note_matching) << "'<'"; + SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus, + tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace, + tok::comma, tok::semi }, + StopBeforeMatch); + if (Tok.is(tok::greater)) + ConsumeToken(); + } + + if (mayBeProtocolList) { + // A type parameter list must be followed by either a ':' (indicating the + // presence of a superclass) or a '(' (indicating that this is a category + // or extension). This disambiguates between an objc-type-parameter-list + // and a objc-protocol-refs. + if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_paren)) { + // Returning null indicates that we don't have a type parameter list. + // The results the caller needs to handle the protocol references are + // captured in the reference parameters already. + return nullptr; + } + + // We have a type parameter list that looks like a list of protocol + // references. Turn that parameter list into type parameters. + makeProtocolIdentsIntoTypeParameters(); + } + + // Form the type parameter list. + ObjCTypeParamList *list = Actions.actOnObjCTypeParamList( + getCurScope(), + lAngleLoc, + typeParams, + rAngleLoc); + + // Clear out the angle locations; they're used by the caller to indicate + // whether there are any protocol references. + lAngleLoc = SourceLocation(); + rAngleLoc = SourceLocation(); + return list; +} + +/// Parse an objc-type-parameter-list. +ObjCTypeParamList *Parser::parseObjCTypeParamList() { + SourceLocation lAngleLoc; + SmallVector<IdentifierLocPair, 1> protocolIdents; + SourceLocation rAngleLoc; + return parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents, + rAngleLoc, + /*mayBeProtocolList=*/false); +} + /// objc-interface-decl-list: /// empty /// objc-interface-decl-list objc-property-decl [OBJC2] @@ -330,7 +628,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, while (1) { // If this is a method prototype, parse it. - if (Tok.is(tok::minus) || Tok.is(tok::plus)) { + if (Tok.isOneOf(tok::minus, tok::plus)) { if (Decl *methodPrototype = ParseObjCMethodPrototype(MethodImplKind, false)) allMethods.push_back(methodPrototype); @@ -445,6 +743,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, ParseObjCPropertyAttribute(OCDS); } + bool addedToDeclSpec = false; auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) { if (FD.D.getIdentifier() == nullptr) { Diag(AtLoc, diag::err_objc_property_requires_field_name) @@ -457,6 +756,13 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, return; } + // Map a nullability property attribute to a context-sensitive keyword + // attribute. + if (OCDS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability) + addContextSensitiveTypeNullability(*this, FD.D, OCDS.getNullability(), + OCDS.getNullabilityLoc(), + addedToDeclSpec); + // Install the property declarator into interfaceDecl. IdentifierInfo *SelName = OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); @@ -510,6 +816,24 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, Actions.ActOnAtEnd(getCurScope(), AtEnd, allMethods, allTUVariables); } +/// Diagnose redundant or conflicting nullability information. +static void diagnoseRedundantPropertyNullability(Parser &P, + ObjCDeclSpec &DS, + NullabilityKind nullability, + SourceLocation nullabilityLoc){ + if (DS.getNullability() == nullability) { + P.Diag(nullabilityLoc, diag::warn_nullability_duplicate) + << DiagNullabilityKind(nullability, true) + << SourceRange(DS.getNullabilityLoc()); + return; + } + + P.Diag(nullabilityLoc, diag::err_nullability_conflicting) + << DiagNullabilityKind(nullability, true) + << DiagNullabilityKind(DS.getNullability(), true) + << SourceRange(DS.getNullabilityLoc()); +} + /// Parse property attribute declarations. /// /// property-attr-decl: '(' property-attrlist ')' @@ -529,6 +853,10 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, /// strong /// weak /// unsafe_unretained +/// nonnull +/// nullable +/// null_unspecified +/// null_resettable /// void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { assert(Tok.getKind() == tok::l_paren); @@ -614,6 +942,37 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter); DS.setGetterName(SelIdent); } + } else if (II->isStr("nonnull")) { + if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability) + diagnoseRedundantPropertyNullability(*this, DS, + NullabilityKind::NonNull, + Tok.getLocation()); + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability); + DS.setNullability(Tok.getLocation(), NullabilityKind::NonNull); + } else if (II->isStr("nullable")) { + if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability) + diagnoseRedundantPropertyNullability(*this, DS, + NullabilityKind::Nullable, + Tok.getLocation()); + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability); + DS.setNullability(Tok.getLocation(), NullabilityKind::Nullable); + } else if (II->isStr("null_unspecified")) { + if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability) + diagnoseRedundantPropertyNullability(*this, DS, + NullabilityKind::Unspecified, + Tok.getLocation()); + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability); + DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified); + } else if (II->isStr("null_resettable")) { + if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability) + diagnoseRedundantPropertyNullability(*this, DS, + NullabilityKind::Unspecified, + Tok.getLocation()); + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability); + DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified); + + // Also set the null_resettable bit. + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_null_resettable); } else { Diag(AttrName, diag::err_objc_expected_property_attr) << II; SkipUntil(tok::r_paren, StopAtSemi); @@ -641,7 +1000,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { /// Decl *Parser::ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind, bool MethodDefinition) { - assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-"); + assert(Tok.isOneOf(tok::minus, tok::plus) && "expected +/-"); tok::TokenKind methodType = Tok.getKind(); SourceLocation mLoc = ConsumeToken(); @@ -779,6 +1138,17 @@ bool Parser::isTokIdentifier_in() const { /// objc-type-qualifier /// objc-type-qualifiers objc-type-qualifier /// +/// objc-type-qualifier: +/// 'in' +/// 'out' +/// 'inout' +/// 'oneway' +/// 'bycopy' +/// 'byref' +/// 'nonnull' +/// 'nullable' +/// 'null_unspecified' +/// void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, Declarator::TheContext Context) { assert(Context == Declarator::ObjCParameterContext || @@ -796,10 +1166,13 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, const IdentifierInfo *II = Tok.getIdentifierInfo(); for (unsigned i = 0; i != objc_NumQuals; ++i) { - if (II != ObjCTypeQuals[i]) + if (II != ObjCTypeQuals[i] || + NextToken().is(tok::less) || + NextToken().is(tok::coloncolon)) continue; ObjCDeclSpec::ObjCDeclQualifier Qual; + NullabilityKind Nullability; switch (i) { default: llvm_unreachable("Unknown decl qualifier"); case objc_in: Qual = ObjCDeclSpec::DQ_In; break; @@ -808,8 +1181,28 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break; case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break; case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break; + + case objc_nonnull: + Qual = ObjCDeclSpec::DQ_CSNullability; + Nullability = NullabilityKind::NonNull; + break; + + case objc_nullable: + Qual = ObjCDeclSpec::DQ_CSNullability; + Nullability = NullabilityKind::Nullable; + break; + + case objc_null_unspecified: + Qual = ObjCDeclSpec::DQ_CSNullability; + Nullability = NullabilityKind::Unspecified; + break; } + + // FIXME: Diagnose redundant specifiers. DS.setObjCDeclQualifier(Qual); + if (Qual == ObjCDeclSpec::DQ_CSNullability) + DS.setNullability(Tok.getLocation(), Nullability); + ConsumeToken(); II = nullptr; break; @@ -878,17 +1271,28 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, ParseObjCTypeQualifierList(DS, context); ParsedType Ty; - if (isTypeSpecifierQualifier()) { + if (isTypeSpecifierQualifier() || isObjCInstancetype()) { // Parse an abstract declarator. DeclSpec declSpec(AttrFactory); declSpec.setObjCQualifiers(&DS); - ParseSpecifierQualifierList(declSpec); + DeclSpecContext dsContext = DSC_normal; + if (context == Declarator::ObjCResultContext) + dsContext = DSC_objc_method_result; + ParseSpecifierQualifierList(declSpec, AS_none, dsContext); declSpec.SetRangeEnd(Tok.getLocation()); Declarator declarator(declSpec, context); ParseDeclarator(declarator); // If that's not invalid, extract a type. if (!declarator.isInvalidType()) { + // Map a nullability specifier to a context-sensitive keyword attribute. + bool addedToDeclSpec = false; + if (DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability) + addContextSensitiveTypeNullability(*this, declarator, + DS.getNullability(), + DS.getNullabilityLoc(), + addedToDeclSpec); + TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator); if (!type.isInvalid()) Ty = type.get(); @@ -898,15 +1302,6 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, if (context == Declarator::ObjCParameterContext) takeDeclAttributes(*paramAttrs, declarator); } - } else if (context == Declarator::ObjCResultContext && - Tok.is(tok::identifier)) { - if (!Ident_instancetype) - Ident_instancetype = PP.getIdentifierInfo("instancetype"); - - if (Tok.getIdentifierInfo() == Ident_instancetype) { - Ty = Actions.ActOnObjCInstanceType(Tok.getLocation()); - ConsumeToken(); - } } if (Tok.is(tok::r_paren)) @@ -1151,8 +1546,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, bool Parser:: ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, SmallVectorImpl<SourceLocation> &ProtocolLocs, - bool WarnOnDeclarations, - SourceLocation &LAngleLoc, SourceLocation &EndLoc) { + bool WarnOnDeclarations, bool ForObjCContainer, + SourceLocation &LAngleLoc, SourceLocation &EndLoc, + bool consumeLastToken) { assert(Tok.is(tok::less) && "expected <"); LAngleLoc = ConsumeToken(); // the "<" @@ -1182,31 +1578,274 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, } // Consume the '>'. - if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true)) + if (ParseGreaterThanInTemplateList(EndLoc, consumeLastToken, + /*ObjCGenericList=*/false)) return true; // Convert the list of protocols identifiers into a list of protocol decls. - Actions.FindProtocolDeclaration(WarnOnDeclarations, + Actions.FindProtocolDeclaration(WarnOnDeclarations, ForObjCContainer, &ProtocolIdents[0], ProtocolIdents.size(), Protocols); return false; } -/// \brief Parse the Objective-C protocol qualifiers that follow a typename -/// in a decl-specifier-seq, starting at the '<'. -bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) { +TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) { assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'"); assert(getLangOpts().ObjC1 && "Protocol qualifiers only exist in Objective-C"); - SourceLocation LAngleLoc, EndProtoLoc; - SmallVector<Decl *, 8> ProtocolDecl; - SmallVector<SourceLocation, 8> ProtocolLocs; - bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, - LAngleLoc, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), - ProtocolLocs.data(), LAngleLoc); - if (EndProtoLoc.isValid()) - DS.SetRangeEnd(EndProtoLoc); - return Result; + + SourceLocation lAngleLoc; + SmallVector<Decl *, 8> protocols; + SmallVector<SourceLocation, 8> protocolLocs; + (void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false, + lAngleLoc, rAngleLoc, + /*consumeLastToken=*/true); + TypeResult result = Actions.actOnObjCProtocolQualifierType(lAngleLoc, + protocols, + protocolLocs, + rAngleLoc); + if (result.isUsable()) { + Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id) + << FixItHint::CreateInsertion(lAngleLoc, "id") + << SourceRange(lAngleLoc, rAngleLoc); + } + + return result; +} + +/// Parse Objective-C type arguments or protocol qualifiers. +/// +/// objc-type-arguments: +/// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>' +/// +void Parser::parseObjCTypeArgsOrProtocolQualifiers( + ParsedType baseType, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SmallVectorImpl<SourceLocation> &protocolLocs, + SourceLocation &protocolRAngleLoc, + bool consumeLastToken, + bool warnOnIncompleteProtocols) { + assert(Tok.is(tok::less) && "Not at the start of type args or protocols"); + SourceLocation lAngleLoc = ConsumeToken(); + + // Whether all of the elements we've parsed thus far are single + // identifiers, which might be types or might be protocols. + bool allSingleIdentifiers = true; + SmallVector<IdentifierInfo *, 4> identifiers; + SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs; + + // Parse a list of comma-separated identifiers, bailing out if we + // see something different. + do { + // Parse a single identifier. + if (Tok.is(tok::identifier) && + (NextToken().is(tok::comma) || + NextToken().is(tok::greater) || + NextToken().is(tok::greatergreater))) { + identifiers.push_back(Tok.getIdentifierInfo()); + identifierLocs.push_back(ConsumeToken()); + continue; + } + + if (Tok.is(tok::code_completion)) { + // FIXME: Also include types here. + SmallVector<IdentifierLocPair, 4> identifierLocPairs; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + identifierLocPairs.push_back(IdentifierLocPair(identifiers[i], + identifierLocs[i])); + } + + QualType BaseT = Actions.GetTypeFromParser(baseType); + if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) { + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); + } else { + Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs.data(), + identifierLocPairs.size()); + } + cutOffParsing(); + return; + } + + allSingleIdentifiers = false; + break; + } while (TryConsumeToken(tok::comma)); + + // If we parsed an identifier list, semantic analysis sorts out + // whether it refers to protocols or to type arguments. + if (allSingleIdentifiers) { + // Parse the closing '>'. + SourceLocation rAngleLoc; + (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken, + /*ObjCGenericList=*/true); + + // Let Sema figure out what we parsed. + Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(), + baseType, + lAngleLoc, + identifiers, + identifierLocs, + rAngleLoc, + typeArgsLAngleLoc, + typeArgs, + typeArgsRAngleLoc, + protocolLAngleLoc, + protocols, + protocolRAngleLoc, + warnOnIncompleteProtocols); + return; + } + + // We syntactically matched a type argument, so commit to parsing + // type arguments. + + // Convert the identifiers into type arguments. + bool invalid = false; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + ParsedType typeArg + = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope()); + if (typeArg) { + DeclSpec DS(AttrFactory); + const char *prevSpec = nullptr; + unsigned diagID; + DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID, + typeArg, Actions.getASTContext().getPrintingPolicy()); + + // Form a declarator to turn this into a type. + Declarator D(DS, Declarator::TypeNameContext); + TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D); + if (fullTypeArg.isUsable()) + typeArgs.push_back(fullTypeArg.get()); + else + invalid = true; + } else { + invalid = true; + } + } + + // Continue parsing type-names. + do { + TypeResult typeArg = ParseTypeName(); + + // Consume the '...' for a pack expansion. + SourceLocation ellipsisLoc; + TryConsumeToken(tok::ellipsis, ellipsisLoc); + if (typeArg.isUsable() && ellipsisLoc.isValid()) { + typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc); + } + + if (typeArg.isUsable()) { + typeArgs.push_back(typeArg.get()); + } else { + invalid = true; + } + } while (TryConsumeToken(tok::comma)); + + // Parse the closing '>'. + SourceLocation rAngleLoc; + (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken, + /*ObjCGenericList=*/true); + + if (invalid) { + typeArgs.clear(); + return; + } + + // Record left/right angle locations. + typeArgsLAngleLoc = lAngleLoc; + typeArgsRAngleLoc = rAngleLoc; +} + +void Parser::parseObjCTypeArgsAndProtocolQualifiers( + ParsedType baseType, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SmallVectorImpl<SourceLocation> &protocolLocs, + SourceLocation &protocolRAngleLoc, + bool consumeLastToken) { + assert(Tok.is(tok::less)); + + // Parse the first angle-bracket-delimited clause. + parseObjCTypeArgsOrProtocolQualifiers(baseType, + typeArgsLAngleLoc, + typeArgs, + typeArgsRAngleLoc, + protocolLAngleLoc, + protocols, + protocolLocs, + protocolRAngleLoc, + consumeLastToken, + /*warnOnIncompleteProtocols=*/false); + + // An Objective-C object pointer followed by type arguments + // can then be followed again by a set of protocol references, e.g., + // \c NSArray<NSView><NSTextDelegate> + if ((consumeLastToken && Tok.is(tok::less)) || + (!consumeLastToken && NextToken().is(tok::less))) { + // If we aren't consuming the last token, the prior '>' is still hanging + // there. Consume it before we parse the protocol qualifiers. + if (!consumeLastToken) + ConsumeToken(); + + if (!protocols.empty()) { + SkipUntilFlags skipFlags = SkipUntilFlags(); + if (!consumeLastToken) + skipFlags = skipFlags | StopBeforeMatch; + Diag(Tok, diag::err_objc_type_args_after_protocols) + << SourceRange(protocolLAngleLoc, protocolRAngleLoc); + SkipUntil(tok::greater, tok::greatergreater, skipFlags); + } else { + ParseObjCProtocolReferences(protocols, protocolLocs, + /*WarnOnDeclarations=*/false, + /*ForObjCContainer=*/false, + protocolLAngleLoc, protocolRAngleLoc, + consumeLastToken); + } + } +} + +TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers( + SourceLocation loc, + ParsedType type, + bool consumeLastToken, + SourceLocation &endLoc) { + assert(Tok.is(tok::less)); + SourceLocation typeArgsLAngleLoc; + SmallVector<ParsedType, 4> typeArgs; + SourceLocation typeArgsRAngleLoc; + SourceLocation protocolLAngleLoc; + SmallVector<Decl *, 4> protocols; + SmallVector<SourceLocation, 4> protocolLocs; + SourceLocation protocolRAngleLoc; + + // Parse type arguments and protocol qualifiers. + parseObjCTypeArgsAndProtocolQualifiers(type, typeArgsLAngleLoc, typeArgs, + typeArgsRAngleLoc, protocolLAngleLoc, + protocols, protocolLocs, + protocolRAngleLoc, consumeLastToken); + + // Compute the location of the last token. + if (consumeLastToken) + endLoc = PrevTokLocation; + else + endLoc = Tok.getLocation(); + + return Actions.actOnObjCTypeArgsAndProtocolQualifiers( + getCurScope(), + loc, + type, + typeArgsLAngleLoc, + typeArgs, + typeArgsRAngleLoc, + protocolLAngleLoc, + protocols, + protocolLocs, + protocolRAngleLoc); } void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc, @@ -1308,6 +1947,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) { Actions.ActOnObjCContainerStartDefinition(interfaceDecl); // Install the declarator into the interface decl. + FD.D.setObjCIvar(true); Decl *Field = Actions.ActOnIvar( getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D, FD.BitfieldSize, visibility); @@ -1416,8 +2056,9 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, SmallVector<Decl *, 8> ProtocolRefs; SmallVector<SourceLocation, 8> ProtocolLocs; if (Tok.is(tok::less) && - ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, - LAngleLoc, EndProtoLoc)) + ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true, + LAngleLoc, EndProtoLoc, + /*consumeLastToken=*/true)) return DeclGroupPtrTy(); Decl *ProtoType = @@ -1467,6 +2108,22 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { SourceLocation nameLoc = ConsumeToken(); // consume class or category name Decl *ObjCImpDecl = nullptr; + // Neither a type parameter list nor a list of protocol references is + // permitted here. Parse and diagnose them. + if (Tok.is(tok::less)) { + SourceLocation lAngleLoc, rAngleLoc; + SmallVector<IdentifierLocPair, 8> protocolIdents; + SourceLocation diagLoc = Tok.getLocation(); + if (parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents, + rAngleLoc)) { + Diag(diagLoc, diag::err_objc_parameterized_implementation) + << SourceRange(diagLoc, PrevTokLocation); + } else if (lAngleLoc.isValid()) { + Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier) + << FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc)); + } + } + if (Tok.is(tok::l_paren)) { // we have a category implementation. ConsumeParen(); @@ -1495,9 +2152,14 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { rparenLoc = ConsumeParen(); if (Tok.is(tok::less)) { // we have illegal '<' try to recover Diag(Tok, diag::err_unexpected_protocol_qualifier); - AttributeFactory attr; - DeclSpec DS(attr); - (void)ParseObjCProtocolQualifiers(DS); + SourceLocation protocolLAngleLoc, protocolRAngleLoc; + SmallVector<Decl *, 4> protocols; + SmallVector<SourceLocation, 4> protocolLocs; + (void)ParseObjCProtocolReferences(protocols, protocolLocs, + /*warnOnIncompleteProtocols=*/false, + /*ForObjCContainer=*/false, + protocolLAngleLoc, protocolRAngleLoc, + /*consumeLastToken=*/true); } ObjCImpDecl = Actions.ActOnStartCategoryImplementation( AtLoc, nameId, nameLoc, categoryId, @@ -1525,10 +2187,15 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc); else if (Tok.is(tok::less)) { // we have illegal '<' try to recover Diag(Tok, diag::err_unexpected_protocol_qualifier); - // try to recover. - AttributeFactory attr; - DeclSpec DS(attr); - (void)ParseObjCProtocolQualifiers(DS); + + SourceLocation protocolLAngleLoc, protocolRAngleLoc; + SmallVector<Decl *, 4> protocols; + SmallVector<SourceLocation, 4> protocolLocs; + (void)ParseObjCProtocolReferences(protocols, protocolLocs, + /*warnOnIncompleteProtocols=*/false, + /*ForObjCContainer=*/false, + protocolLAngleLoc, protocolRAngleLoc, + /*consumeLastToken=*/true); } } assert(ObjCImpDecl); @@ -2169,8 +2836,8 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { InMessageExpressionRAIIObject InMessage(*this, true); - if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || - Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) + if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_typename, + tok::annot_cxxscope)) TryAnnotateTypeOrScopeToken(); if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) { @@ -2264,7 +2931,7 @@ bool Parser::isStartOfObjCClassMessageMissingOpenBracket() { if (!Type.get().isNull() && Type.get()->isObjCObjectOrInterfaceType()) { const Token &AfterNext = GetLookAheadToken(2); - if (AfterNext.is(tok::colon) || AfterNext.is(tok::r_square)) { + if (AfterNext.isOneOf(tok::colon, tok::r_square)) { if (Tok.is(tok::identifier)) TryAnnotateTypeOrScopeToken(); @@ -2346,6 +3013,21 @@ ExprResult Parser::ParseObjCMessageExpression() { ConsumeToken(); // the type name + // Parse type arguments and protocol qualifiers. + if (Tok.is(tok::less)) { + SourceLocation NewEndLoc; + TypeResult NewReceiverType + = parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType, + /*consumeLastToken=*/true, + NewEndLoc); + if (!NewReceiverType.isUsable()) { + SkipUntil(tok::r_square, StopAtSemi); + return ExprError(); + } + + ReceiverType = NewReceiverType.get(); + } + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), ReceiverType, nullptr); @@ -2890,9 +3572,8 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); - assert((Tok.is(tok::l_brace) || Tok.is(tok::kw_try) || - Tok.is(tok::colon)) && - "Inline objective-c method not starting with '{' or 'try' or ':'"); + assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) && + "Inline objective-c method not starting with '{' or 'try' or ':'"); // Enter a scope for the method or c-function body. ParseScope BodyScope(this, parseMethod diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp index 764619a..0113a31 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp @@ -30,24 +30,39 @@ static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) { // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd // TODO: add other combined directives in topological order. const OpenMPDirectiveKind F[][3] = { - { OMPD_for, OMPD_simd, OMPD_for_simd }, - { OMPD_parallel, OMPD_for, OMPD_parallel_for }, - { OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd }, - { OMPD_parallel, OMPD_sections, OMPD_parallel_sections } - }; + {OMPD_unknown /*cancellation*/, OMPD_unknown /*point*/, + OMPD_cancellation_point}, + {OMPD_for, OMPD_simd, OMPD_for_simd}, + {OMPD_parallel, OMPD_for, OMPD_parallel_for}, + {OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd}, + {OMPD_parallel, OMPD_sections, OMPD_parallel_sections}}; auto Tok = P.getCurToken(); auto DKind = Tok.isAnnotation() ? OMPD_unknown : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok)); + bool TokenMatched = false; for (unsigned i = 0; i < llvm::array_lengthof(F); ++i) { - if (DKind == F[i][0]) { + if (!Tok.isAnnotation() && DKind == OMPD_unknown) { + TokenMatched = + (i == 0) && + !P.getPreprocessor().getSpelling(Tok).compare("cancellation"); + } else { + TokenMatched = DKind == F[i][0] && DKind != OMPD_unknown; + } + if (TokenMatched) { Tok = P.getPreprocessor().LookAhead(0); auto SDKind = Tok.isAnnotation() ? OMPD_unknown : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok)); - if (SDKind == F[i][1]) { + if (!Tok.isAnnotation() && DKind == OMPD_unknown) { + TokenMatched = + (i == 0) && !P.getPreprocessor().getSpelling(Tok).compare("point"); + } else { + TokenMatched = SDKind == F[i][1] && SDKind != OMPD_unknown; + } + if (TokenMatched) { P.ConsumeToken(); DKind = F[i][2]; } @@ -94,6 +109,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: + case OMPD_taskgroup: case OMPD_flush: case OMPD_for: case OMPD_for_simd: @@ -109,6 +125,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { case OMPD_atomic: case OMPD_target: case OMPD_teams: + case OMPD_cancellation_point: + case OMPD_cancel: Diag(Tok, diag::err_omp_unexpected_directive) << getOpenMPDirectiveName(DKind); break; @@ -128,7 +146,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { /// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] | /// 'parallel for' | 'parallel sections' | 'task' | 'taskyield' | /// 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'atomic' | -/// 'for simd' | 'parallel for simd' | 'target' | 'teams' {clause} +/// 'for simd' | 'parallel for simd' | 'target' | 'teams' | 'taskgroup' +/// {clause} /// annot_pragma_openmp_end /// StmtResult @@ -143,6 +162,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) { Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope; SourceLocation Loc = ConsumeToken(), EndLoc; auto DKind = ParseOpenMPDirectiveKind(*this); + OpenMPDirectiveKind CancelRegion = OMPD_unknown; // Name of critical directive. DeclarationNameInfo DirName; StmtResult Directive = StmtError(); @@ -176,6 +196,8 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) { case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: + case OMPD_cancellation_point: + case OMPD_cancel: if (!StandAloneAllowed) { Diag(Tok, diag::err_omp_immediate_directive) << getOpenMPDirectiveName(DKind); @@ -198,7 +220,8 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) { case OMPD_ordered: case OMPD_atomic: case OMPD_target: - case OMPD_teams: { + case OMPD_teams: + case OMPD_taskgroup: { ConsumeToken(); // Parse directive name of the 'critical' directive if any. if (DKind == OMPD_critical) { @@ -214,6 +237,10 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) { } T.consumeClose(); } + } else if (DKind == OMPD_cancellation_point || DKind == OMPD_cancel) { + CancelRegion = ParseOpenMPDirectiveKind(*this); + if (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeToken(); } if (isOpenMPLoopDirective(DKind)) @@ -229,6 +256,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) { ? OMPC_unknown : FlushHasClause ? OMPC_flush : getOpenMPClauseKind(PP.getSpelling(Tok)); + Actions.StartOpenMPClause(CKind); FlushHasClause = false; OMPClause *Clause = ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt()); @@ -241,6 +269,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) { // Skip ',' if any. if (Tok.is(tok::comma)) ConsumeToken(); + Actions.EndOpenMPClause(); } // End location of the directive. EndLoc = Tok.getLocation(); @@ -257,17 +286,13 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) { // Parse statement AssociatedStmt = ParseStatement(); Actions.ActOnFinishOfCompoundStmt(); - if (!AssociatedStmt.isUsable()) { - Actions.ActOnCapturedRegionError(); - CreateDirective = false; - } else { - AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.get()); - CreateDirective = AssociatedStmt.isUsable(); - } + AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); + CreateDirective = AssociatedStmt.isUsable(); } if (CreateDirective) Directive = Actions.ActOnOpenMPExecutableDirective( - DKind, DirName, Clauses, AssociatedStmt.get(), Loc, EndLoc); + DKind, DirName, CancelRegion, Clauses, AssociatedStmt.get(), Loc, + EndLoc); // Exit scope. Actions.EndOpenMPDSABlock(Directive.get()); @@ -453,6 +478,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_copyin: case OMPC_copyprivate: case OMPC_flush: + case OMPC_depend: Clause = ParseOpenMPVarListClause(CKind); break; case OMPC_unknown: @@ -674,6 +700,8 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec, /// 'copyprivate' '(' list ')' /// flush-clause: /// 'flush' '(' list ')' +/// depend-clause: +/// 'depend' '(' in | out | inout : list ')' /// OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) { SourceLocation Loc = Tok.getLocation(); @@ -683,6 +711,9 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) { CXXScopeSpec ReductionIdScopeSpec; UnqualifiedId ReductionId; bool InvalidReductionId = false; + OpenMPDependClauseKind DepKind = OMPC_DEPEND_unknown; + SourceLocation DepLoc; + // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, @@ -706,10 +737,30 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) { } else { Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier"; } + } else if (Kind == OMPC_depend) { + // Handle dependency type for depend clause. + ColonProtectionRAIIObject ColonRAII(*this); + DepKind = static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType( + Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); + DepLoc = Tok.getLocation(); + + if (DepKind == OMPC_DEPEND_unknown) { + SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } else { + ConsumeToken(); + } + if (Tok.is(tok::colon)) { + ColonLoc = ConsumeToken(); + } else { + Diag(Tok, diag::warn_pragma_expected_colon) << "dependency type"; + } } SmallVector<Expr *, 5> Vars; - bool IsComma = !InvalidReductionId; + bool IsComma = ((Kind != OMPC_reduction) && (Kind != OMPC_depend)) || + ((Kind == OMPC_reduction) && !InvalidReductionId) || + ((Kind == OMPC_depend) && DepKind != OMPC_DEPEND_unknown); const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned); while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) && Tok.isNot(tok::annot_pragma_openmp_end))) { @@ -753,13 +804,16 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) { // Parse ')'. T.consumeClose(); - if (Vars.empty() || (MustHaveTail && !TailExpr) || InvalidReductionId) + if ((Kind == OMPC_depend && DepKind != OMPC_DEPEND_unknown && Vars.empty()) || + (Kind != OMPC_depend && Vars.empty()) || (MustHaveTail && !TailExpr) || + InvalidReductionId) return nullptr; return Actions.ActOnOpenMPVarListClause( Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(), ReductionIdScopeSpec, ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId) - : DeclarationNameInfo()); + : DeclarationNameInfo(), + DepKind, DepLoc); } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp index 473be54..892d3c6 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp @@ -198,9 +198,12 @@ void Parser::initializePragmaHandlers() { OpenMPHandler.reset(new PragmaNoOpenMPHandler()); PP.AddPragmaHandler(OpenMPHandler.get()); - if (getLangOpts().MicrosoftExt) { + if (getLangOpts().MicrosoftExt || getTargetInfo().getTriple().isPS4()) { MSCommentHandler.reset(new PragmaCommentHandler(Actions)); PP.AddPragmaHandler(MSCommentHandler.get()); + } + + if (getLangOpts().MicrosoftExt) { MSDetectMismatchHandler.reset(new PragmaDetectMismatchHandler(Actions)); PP.AddPragmaHandler(MSDetectMismatchHandler.get()); MSPointersToMembers.reset(new PragmaMSPointersToMembers()); @@ -261,9 +264,12 @@ void Parser::resetPragmaHandlers() { PP.RemovePragmaHandler(OpenMPHandler.get()); OpenMPHandler.reset(); - if (getLangOpts().MicrosoftExt) { + if (getLangOpts().MicrosoftExt || getTargetInfo().getTriple().isPS4()) { PP.RemovePragmaHandler(MSCommentHandler.get()); MSCommentHandler.reset(); + } + + if (getLangOpts().MicrosoftExt) { PP.RemovePragmaHandler(MSDetectMismatchHandler.get()); MSDetectMismatchHandler.reset(); PP.RemovePragmaHandler(MSPointersToMembers.get()); @@ -793,8 +799,10 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) { "PragmaLoopHintInfo::Toks must contain at least one token."); // If no option is specified the argument is assumed to be a constant expr. + bool OptionUnroll = false; bool StateOption = false; - if (OptionInfo) { // Pragma unroll does not specify an option. + if (OptionInfo) { // Pragma Unroll does not specify an option. + OptionUnroll = OptionInfo->isStr("unroll"); StateOption = llvm::StringSwitch<bool>(OptionInfo->getName()) .Case("vectorize", true) .Case("interleave", true) @@ -806,19 +814,20 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) { if (Toks[0].is(tok::eof)) { ConsumeToken(); // The annotation token. Diag(Toks[0].getLocation(), diag::err_pragma_loop_missing_argument) - << /*StateArgument=*/StateOption << /*FullKeyword=*/PragmaUnroll; + << /*StateArgument=*/StateOption << /*FullKeyword=*/OptionUnroll; return false; } // Validate the argument. if (StateOption) { ConsumeToken(); // The annotation token. - bool OptionUnroll = OptionInfo->isStr("unroll"); SourceLocation StateLoc = Toks[0].getLocation(); IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo(); - if (!StateInfo || ((OptionUnroll ? !StateInfo->isStr("full") - : !StateInfo->isStr("enable")) && - !StateInfo->isStr("disable"))) { + if (!StateInfo || + ((OptionUnroll ? !StateInfo->isStr("full") + : !StateInfo->isStr("enable") && + !StateInfo->isStr("assume_safety")) && + !StateInfo->isStr("disable"))) { Diag(Toks[0].getLocation(), diag::err_pragma_invalid_keyword) << /*FullKeyword=*/OptionUnroll; return false; @@ -900,6 +909,7 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, << "visibility"; return; } + SourceLocation EndLoc = Tok.getLocation(); PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) @@ -911,6 +921,7 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_vis); Toks[0].setLocation(VisLoc); + Toks[0].setAnnotationEndLoc(EndLoc); Toks[0].setAnnotationValue( const_cast<void*>(static_cast<const void*>(VisType))); PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, @@ -1030,6 +1041,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_pack); Toks[0].setLocation(PackLoc); + Toks[0].setAnnotationEndLoc(RParenLoc); Toks[0].setAnnotationValue(static_cast<void*>(Info)); PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); @@ -1048,6 +1060,7 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct); return; } + SourceLocation EndLoc = Tok.getLocation(); const IdentifierInfo *II = Tok.getIdentifierInfo(); if (II->isStr("on")) { Kind = Sema::PMSST_ON; @@ -1073,6 +1086,7 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_msstruct); Toks[0].setLocation(MSStructTok.getLocation()); + Toks[0].setAnnotationEndLoc(EndLoc); Toks[0].setAnnotationValue(reinterpret_cast<void*>( static_cast<uintptr_t>(Kind))); PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, @@ -1128,6 +1142,7 @@ static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok, return; } + SourceLocation EndLoc = Tok.getLocation(); PP.Lex(Tok); if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) @@ -1142,6 +1157,7 @@ static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok, Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_align); Toks[0].setLocation(FirstTok.getLocation()); + Toks[0].setAnnotationEndLoc(EndLoc); Toks[0].setAnnotationValue(reinterpret_cast<void*>( static_cast<uintptr_t>(Kind))); PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, @@ -1285,6 +1301,7 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, pragmaUnusedTok.startToken(); pragmaUnusedTok.setKind(tok::annot_pragma_weakalias); pragmaUnusedTok.setLocation(WeakLoc); + pragmaUnusedTok.setAnnotationEndLoc(AliasName.getLocation()); Toks[1] = WeakName; Toks[2] = AliasName; PP.EnterTokenStream(Toks, 3, @@ -1297,6 +1314,7 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, pragmaUnusedTok.startToken(); pragmaUnusedTok.setKind(tok::annot_pragma_weak); pragmaUnusedTok.setLocation(WeakLoc); + pragmaUnusedTok.setAnnotationEndLoc(WeakLoc); Toks[1] = WeakName; PP.EnterTokenStream(Toks, 2, /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); @@ -1342,6 +1360,7 @@ void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP, pragmaRedefTok.startToken(); pragmaRedefTok.setKind(tok::annot_pragma_redefine_extname); pragmaRedefTok.setLocation(RedefLoc); + pragmaRedefTok.setAnnotationEndLoc(AliasName.getLocation()); Toks[1] = RedefName; Toks[2] = AliasName; PP.EnterTokenStream(Toks, 3, @@ -1364,6 +1383,7 @@ PragmaFPContractHandler::HandlePragma(Preprocessor &PP, Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_fp_contract); Toks[0].setLocation(Tok.getLocation()); + Toks[0].setAnnotationEndLoc(Tok.getLocation()); Toks[0].setAnnotationValue(reinterpret_cast<void*>( static_cast<uintptr_t>(OOS))); PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, @@ -1423,6 +1443,7 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, Toks[0].setKind(tok::annot_pragma_opencl_extension); Toks[0].setLocation(NameLoc); Toks[0].setAnnotationValue(data.getOpaqueValue()); + Toks[0].setAnnotationEndLoc(StateLoc); PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); @@ -1471,7 +1492,7 @@ PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, Token *Toks = new Token[Pragma.size()]; std::copy(Pragma.begin(), Pragma.end(), Toks); PP.EnterTokenStream(Toks, Pragma.size(), - /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true); + /*DisableMacroExpansion=*/false, /*OwnsTokens=*/true); } /// \brief Handle '#pragma pointers_to_members' @@ -1554,6 +1575,7 @@ void PragmaMSPointersToMembers::HandlePragma(Preprocessor &PP, return; } + SourceLocation EndLoc = Tok.getLocation(); PP.Lex(Tok); if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) @@ -1565,6 +1587,7 @@ void PragmaMSPointersToMembers::HandlePragma(Preprocessor &PP, AnnotTok.startToken(); AnnotTok.setKind(tok::annot_pragma_ms_pointers_to_members); AnnotTok.setLocation(PointersToMembersLoc); + AnnotTok.setAnnotationEndLoc(EndLoc); AnnotTok.setAnnotationValue( reinterpret_cast<void *>(static_cast<uintptr_t>(RepresentationMethod))); PP.EnterToken(AnnotTok); @@ -1644,6 +1667,7 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP, PP.Diag(VtorDispLoc, diag::warn_pragma_expected_rparen) << "vtordisp"; return; } + SourceLocation EndLoc = Tok.getLocation(); PP.Lex(Tok); if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) @@ -1656,6 +1680,7 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP, AnnotTok.startToken(); AnnotTok.setKind(tok::annot_pragma_ms_vtordisp); AnnotTok.setLocation(VtorDispLoc); + AnnotTok.setAnnotationEndLoc(EndLoc); AnnotTok.setAnnotationValue(reinterpret_cast<void *>( static_cast<uintptr_t>((Kind << 16) | (Value & 0xFFFF)))); PP.EnterToken(AnnotTok); @@ -1672,10 +1697,13 @@ void PragmaMSPragma::HandlePragma(Preprocessor &PP, AnnotTok.startToken(); AnnotTok.setKind(tok::annot_pragma_ms_pragma); AnnotTok.setLocation(Tok.getLocation()); + AnnotTok.setAnnotationEndLoc(Tok.getLocation()); SmallVector<Token, 8> TokenVector; // Suck up all of the tokens before the eod. - for (; Tok.isNot(tok::eod); PP.Lex(Tok)) + for (; Tok.isNot(tok::eod); PP.Lex(Tok)) { TokenVector.push_back(Tok); + AnnotTok.setAnnotationEndLoc(Tok.getLocation()); + } // Add a sentinal EoF token to the end of the list. TokenVector.push_back(EoF); // We must allocate this array with new because EnterTokenStream is going to @@ -1786,6 +1814,14 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, return; } + // On PS4, issue a warning about any pragma comments other than + // #pragma comment lib. + if (PP.getTargetInfo().getTriple().isPS4() && Kind != Sema::PCK_Lib) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_comment_ignored) + << II->getName(); + return; + } + // Read the optional string if present. PP.Lex(Tok); std::string ArgumentString; @@ -1920,6 +1956,7 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName, /// loop-hint-keyword: /// 'enable' /// 'disable' +/// 'assume_safety' /// /// unroll-hint-keyword: /// 'full' @@ -1994,6 +2031,7 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, LoopHintTok.startToken(); LoopHintTok.setKind(tok::annot_pragma_loop_hint); LoopHintTok.setLocation(PragmaName.getLocation()); + LoopHintTok.setAnnotationEndLoc(PragmaName.getLocation()); LoopHintTok.setAnnotationValue(static_cast<void *>(Info)); TokenList.push_back(LoopHintTok); } @@ -2076,6 +2114,7 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP, TokenArray[0].startToken(); TokenArray[0].setKind(tok::annot_pragma_loop_hint); TokenArray[0].setLocation(PragmaName.getLocation()); + TokenArray[0].setAnnotationEndLoc(PragmaName.getLocation()); TokenArray[0].setAnnotationValue(static_cast<void *>(Info)); PP.EnterTokenStream(TokenArray, 1, /*DisableMacroExpansion=*/false, /*OwnsTokens=*/true); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp index 2a5f840..b658cef 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp @@ -119,15 +119,12 @@ namespace { class StatementFilterCCC : public CorrectionCandidateCallback { public: StatementFilterCCC(Token nextTok) : NextToken(nextTok) { - WantTypeSpecifiers = nextTok.is(tok::l_paren) || nextTok.is(tok::less) || - nextTok.is(tok::identifier) || nextTok.is(tok::star) || - nextTok.is(tok::amp) || nextTok.is(tok::l_square); - WantExpressionKeywords = nextTok.is(tok::l_paren) || - nextTok.is(tok::identifier) || - nextTok.is(tok::arrow) || nextTok.is(tok::period); - WantRemainingKeywords = nextTok.is(tok::l_paren) || nextTok.is(tok::semi) || - nextTok.is(tok::identifier) || - nextTok.is(tok::l_brace); + WantTypeSpecifiers = nextTok.isOneOf(tok::l_paren, tok::less, tok::l_square, + tok::identifier, tok::star, tok::amp); + WantExpressionKeywords = + nextTok.isOneOf(tok::l_paren, tok::identifier, tok::arrow, tok::period); + WantRemainingKeywords = + nextTok.isOneOf(tok::l_paren, tok::semi, tok::identifier, tok::l_brace); WantCXXNamedCasts = false; } @@ -408,12 +405,6 @@ StmtResult Parser::ParseExprStatement() { return Actions.ActOnExprStmt(Expr); } -StmtResult Parser::ParseSEHTryBlock() { - assert(Tok.is(tok::kw___try) && "Expected '__try'"); - SourceLocation Loc = ConsumeToken(); - return ParseSEHTryBlockCommon(Loc); -} - /// ParseSEHTryBlockCommon /// /// seh-try-block: @@ -423,8 +414,11 @@ StmtResult Parser::ParseSEHTryBlock() { /// seh-except-block /// seh-finally-block /// -StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) { - if(Tok.isNot(tok::l_brace)) +StmtResult Parser::ParseSEHTryBlock() { + assert(Tok.is(tok::kw___try) && "Expected '__try'"); + SourceLocation TryLoc = ConsumeToken(); + + if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace); StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false, @@ -441,7 +435,7 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHFinallyBlock(Loc); } else { - return StmtError(Diag(Tok,diag::err_seh_expected_handler)); + return StmtError(Diag(Tok, diag::err_seh_expected_handler)); } if(Handler.isInvalid()) @@ -466,14 +460,21 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { if (ExpectAndConsume(tok::l_paren)) return StmtError(); - ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope); + ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope | + Scope::SEHExceptScope); if (getLangOpts().Borland) { Ident__exception_info->setIsPoisoned(false); Ident___exception_info->setIsPoisoned(false); Ident_GetExceptionInfo->setIsPoisoned(false); } - ExprResult FilterExpr(ParseExpression()); + + ExprResult FilterExpr; + { + ParseScopeFlags FilterScope(this, getCurScope()->getFlags() | + Scope::SEHFilterScope); + FilterExpr = Actions.CorrectDelayedTyposInExpr(ParseExpression()); + } if (getLangOpts().Borland) { Ident__exception_info->setIsPoisoned(true); @@ -487,6 +488,9 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { if (ExpectAndConsume(tok::r_paren)) return StmtError(); + if (Tok.isNot(tok::l_brace)) + return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace); + StmtResult Block(ParseCompoundStatement()); if(Block.isInvalid()) @@ -500,16 +504,24 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { /// seh-finally-block: /// '__finally' compound-statement /// -StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) { +StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyLoc) { PoisonIdentifierRAIIObject raii(Ident__abnormal_termination, false), raii2(Ident___abnormal_termination, false), raii3(Ident_AbnormalTermination, false); + if (Tok.isNot(tok::l_brace)) + return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace); + + ParseScope FinallyScope(this, 0); + Actions.ActOnStartSEHFinallyBlock(); + StmtResult Block(ParseCompoundStatement()); - if(Block.isInvalid()) + if(Block.isInvalid()) { + Actions.ActOnAbortSEHFinallyBlock(); return Block; + } - return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.get()); + return Actions.ActOnFinishSEHFinallyBlock(FinallyLoc, Block.get()); } /// Handle __leave @@ -1253,7 +1265,7 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) { // We have incremented the mangling number for the SwitchScope and the // InnerScope, which is one too many. if (C99orCXX) - getCurScope()->decrementMSLocalManglingNumber(); + getCurScope()->decrementMSManglingNumber(); // Read the body statement. StmtResult Body(ParseStatement(TrailingElseLoc)); @@ -1412,7 +1424,7 @@ bool Parser::isForRangeIdentifier() { if (Next.is(tok::colon)) return true; - if (Next.is(tok::l_square) || Next.is(tok::kw_alignas)) { + if (Next.isOneOf(tok::l_square, tok::kw_alignas)) { TentativeParsingAction PA(*this); ConsumeToken(); SkipCXX11Attributes(); @@ -1674,6 +1686,12 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { FirstPart.get(), Collection.get(), T.getCloseLocation()); + } else { + // In OpenMP loop region loop control variable must be captured and be + // private. Perform analysis of first part (if any). + if (getLangOpts().OpenMP && FirstPart.isUsable()) { + Actions.ActOnOpenMPLoopInitialization(ForLoc, FirstPart.get()); + } } // C99 6.8.5p5 - In C99, the body of the for statement is a scope, even if @@ -1695,7 +1713,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { // It will only be incremented if the body contains other things that would // normally increment the mangling number (like a compound statement). if (C99orCXXorObjC) - getCurScope()->decrementMSLocalManglingNumber(); + getCurScope()->decrementMSManglingNumber(); // Read the body statement. StmtResult Body(ParseStatement(TrailingElseLoc)); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp index 7bf4da6..8cdae6a 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp @@ -512,8 +512,8 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { llvm::SourceMgr TempSrcMgr; llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr); - MOFI->InitMCObjectFileInfo(TT, llvm::Reloc::Default, llvm::CodeModel::Default, - Ctx); + MOFI->InitMCObjectFileInfo(TheTriple, llvm::Reloc::Default, + llvm::CodeModel::Default, Ctx); std::unique_ptr<llvm::MemoryBuffer> Buffer = llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>"); @@ -530,7 +530,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions)); std::unique_ptr<llvm::MCInstPrinter> IP( - TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI)); + TheTarget->createMCInstPrinter(llvm::Triple(TT), 1, *MAI, *MII, *MRI)); // Change to the Intel dialect. Parser->setAssemblerDialect(1); @@ -615,6 +615,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { msAsm = true; return ParseMicrosoftAsmStatement(AsmLoc); } + DeclSpec DS(AttrFactory); SourceLocation Loc = Tok.getLocation(); ParseTypeQualifierListOpt(DS, AR_VendorAttributesParsed); @@ -639,6 +640,15 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { T.consumeOpen(); ExprResult AsmString(ParseAsmStringLiteral()); + + // Check if GNU-style InlineAsm is disabled. + // Error on anything other than empty string. + if (!(getLangOpts().GNUAsm || AsmString.isInvalid())) { + const auto *SL = cast<StringLiteral>(AsmString.get()); + if (!SL->getString().trim().empty()) + Diag(Loc, diag::err_gnu_inline_asm_disabled); + } + if (AsmString.isInvalid()) { // Consume up to and including the closing paren. T.skipToEnd(); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp index 53de72c..3a964dd 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp @@ -14,6 +14,7 @@ #include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" #include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/DeclSpec.h" @@ -61,7 +62,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, SourceLocation &DeclEnd, AccessSpecifier AS, AttributeList *AccessAttrs) { - assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) && + assert(Tok.isOneOf(tok::kw_export, tok::kw_template) && "Token does not start a template declaration."); // Enter template-parameter scope. @@ -115,7 +116,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, SmallVector<Decl*, 4> TemplateParams; if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(), TemplateParams, LAngleLoc, RAngleLoc)) { - // Skip until the semi-colon or a }. + // Skip until the semi-colon or a '}'. SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); TryConsumeToken(tok::semi); return nullptr; @@ -131,10 +132,21 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, if (!TemplateParams.empty()) { isSpecialization = false; ++CurTemplateDepthTracker; + + if (TryConsumeToken(tok::kw_requires)) { + ExprResult ER = + Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression()); + if (!ER.isUsable()) { + // Skip until the semi-colon or a '}'. + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); + TryConsumeToken(tok::semi); + return nullptr; + } + } } else { LastParamListWasEmpty = true; } - } while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template)); + } while (Tok.isOneOf(tok::kw_export, tok::kw_template)); // Parse the actual template declaration. return ParseSingleDeclarationAfterTemplate(Context, @@ -366,7 +378,7 @@ Parser::ParseTemplateParameterList(unsigned Depth, // Did we find a comma or the end of the template parameter list? if (Tok.is(tok::comma)) { ConsumeToken(); - } else if (Tok.is(tok::greater) || Tok.is(tok::greatergreater)) { + } else if (Tok.isOneOf(tok::greater, tok::greatergreater)) { // Don't consume this... that's done by template parser. break; } else { @@ -483,7 +495,7 @@ Decl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { /// 'typename' ...[opt][C++0x] identifier[opt] /// 'typename' identifier[opt] '=' type-id Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { - assert((Tok.is(tok::kw_class) || Tok.is(tok::kw_typename)) && + assert(Tok.isOneOf(tok::kw_class, tok::kw_typename) && "A type-parameter starts with 'class' or 'typename'"); // Consume the 'class' or 'typename' keyword. @@ -505,8 +517,8 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { if (Tok.is(tok::identifier)) { ParamName = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); - } else if (Tok.is(tok::equal) || Tok.is(tok::comma) || - Tok.is(tok::greater) || Tok.is(tok::greatergreater)) { + } else if (Tok.isOneOf(tok::equal, tok::comma, tok::greater, + tok::greatergreater)) { // Unnamed template parameter. Don't have to do anything here, just // don't consume this token. } else { @@ -566,7 +578,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { // or greater appear immediately or after 'struct'. In the latter case, // replace the keyword with 'class'. if (!TryConsumeToken(tok::kw_class)) { - bool Replace = Tok.is(tok::kw_typename) || Tok.is(tok::kw_struct); + bool Replace = Tok.isOneOf(tok::kw_typename, tok::kw_struct); const Token &Next = Tok.is(tok::kw_struct) ? NextToken() : Tok; if (Tok.is(tok::kw_typename)) { Diag(Tok.getLocation(), @@ -576,9 +588,8 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { << (!getLangOpts().CPlusPlus1z ? FixItHint::CreateReplacement(Tok.getLocation(), "class") : FixItHint()); - } else if (Next.is(tok::identifier) || Next.is(tok::comma) || - Next.is(tok::greater) || Next.is(tok::greatergreater) || - Next.is(tok::ellipsis)) { + } else if (Next.isOneOf(tok::identifier, tok::comma, tok::greater, + tok::greatergreater, tok::ellipsis)) { Diag(Tok.getLocation(), diag::err_class_on_template_template_param) << (Replace ? FixItHint::CreateReplacement(Tok.getLocation(), "class") : FixItHint::CreateInsertion(Tok.getLocation(), "class ")); @@ -603,8 +614,8 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { if (Tok.is(tok::identifier)) { ParamName = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); - } else if (Tok.is(tok::equal) || Tok.is(tok::comma) || - Tok.is(tok::greater) || Tok.is(tok::greatergreater)) { + } else if (Tok.isOneOf(tok::equal, tok::comma, tok::greater, + tok::greatergreater)) { // Unnamed template parameter. Don't have to do anything here, just // don't consume this token. } else { @@ -727,11 +738,16 @@ void Parser::DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc, /// /// \param RAngleLoc the location of the consumed '>'. /// -/// \param ConsumeLastToken if true, the '>' is not consumed. +/// \param ConsumeLastToken if true, the '>' is consumed. +/// +/// \param ObjCGenericList if true, this is the '>' closing an Objective-C +/// type parameter or type argument list, rather than a C++ template parameter +/// or argument list. /// /// \returns true, if current token does not start with '>', false otherwise. bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, - bool ConsumeLastToken) { + bool ConsumeLastToken, + bool ObjCGenericList) { // What will be left once we've consumed the '>'. tok::TokenKind RemainingToken; const char *ReplacementStr = "> >"; @@ -772,41 +788,44 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, // the token isn't '>>' or '>>>'. // '>>>' is for CUDA, where this sequence of characters is parsed into // tok::greatergreatergreater, rather than two separate tokens. - + // + // We always allow this for Objective-C type parameter and type argument + // lists. RAngleLoc = Tok.getLocation(); - - // The source range of the '>>' or '>=' at the start of the token. - CharSourceRange ReplacementRange = - CharSourceRange::getCharRange(RAngleLoc, - Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(), - getLangOpts())); - - // A hint to put a space between the '>>'s. In order to make the hint as - // clear as possible, we include the characters either side of the space in - // the replacement, rather than just inserting a space at SecondCharLoc. - FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange, - ReplacementStr); - - // A hint to put another space after the token, if it would otherwise be - // lexed differently. - FixItHint Hint2; Token Next = NextToken(); - if ((RemainingToken == tok::greater || - RemainingToken == tok::greatergreater) && - (Next.is(tok::greater) || Next.is(tok::greatergreater) || - Next.is(tok::greatergreatergreater) || Next.is(tok::equal) || - Next.is(tok::greaterequal) || Next.is(tok::greatergreaterequal) || - Next.is(tok::equalequal)) && - areTokensAdjacent(Tok, Next)) - Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " "); - - unsigned DiagId = diag::err_two_right_angle_brackets_need_space; - if (getLangOpts().CPlusPlus11 && - (Tok.is(tok::greatergreater) || Tok.is(tok::greatergreatergreater))) - DiagId = diag::warn_cxx98_compat_two_right_angle_brackets; - else if (Tok.is(tok::greaterequal)) - DiagId = diag::err_right_angle_bracket_equal_needs_space; - Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2; + if (!ObjCGenericList) { + // The source range of the '>>' or '>=' at the start of the token. + CharSourceRange ReplacementRange = + CharSourceRange::getCharRange(RAngleLoc, + Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(), + getLangOpts())); + + // A hint to put a space between the '>>'s. In order to make the hint as + // clear as possible, we include the characters either side of the space in + // the replacement, rather than just inserting a space at SecondCharLoc. + FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange, + ReplacementStr); + + // A hint to put another space after the token, if it would otherwise be + // lexed differently. + FixItHint Hint2; + if ((RemainingToken == tok::greater || + RemainingToken == tok::greatergreater) && + (Next.isOneOf(tok::greater, tok::greatergreater, + tok::greatergreatergreater, tok::equal, + tok::greaterequal, tok::greatergreaterequal, + tok::equalequal)) && + areTokensAdjacent(Tok, Next)) + Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " "); + + unsigned DiagId = diag::err_two_right_angle_brackets_need_space; + if (getLangOpts().CPlusPlus11 && + (Tok.is(tok::greatergreater) || Tok.is(tok::greatergreatergreater))) + DiagId = diag::warn_cxx98_compat_two_right_angle_brackets; + else if (Tok.is(tok::greaterequal)) + DiagId = diag::err_right_angle_bracket_equal_needs_space; + Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2; + } // Strip the initial '>' from the token. if (RemainingToken == tok::equal && Next.is(tok::equal) && @@ -885,7 +904,8 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, } } - return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken); + return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken, + /*ObjCGenericList=*/false); } /// \brief Replace the tokens that form a simple-template-id with an @@ -1054,8 +1074,7 @@ void Parser::AnnotateTemplateIdTokenAsType() { /// \brief Determine whether the given token can end a template argument. static bool isEndOfTemplateArgument(Token Tok) { - return Tok.is(tok::comma) || Tok.is(tok::greater) || - Tok.is(tok::greatergreater); + return Tok.isOneOf(tok::comma, tok::greater, tok::greatergreater); } /// \brief Parse a C++ template template argument. @@ -1216,7 +1235,7 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) { ConsumeToken(); // If we have a '>' or a ',' then this is a template argument list. - return Tok.is(tok::greater) || Tok.is(tok::comma); + return Tok.isOneOf(tok::greater, tok::comma); } /// ParseTemplateArgumentList - Parse a C++ template-argument-list @@ -1301,7 +1320,8 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); // To restore the context after late parsing. - Sema::ContextRAII GlobalSavedContext(Actions, Actions.CurContext); + Sema::ContextRAII GlobalSavedContext( + Actions, Actions.Context.getTranslationUnitDecl()); SmallVector<ParseScope*, 4> TemplateParamScopeStack; @@ -1337,8 +1357,8 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); - assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) - && "Inline method not starting with '{', ':' or 'try'"); + assert(Tok.isOneOf(tok::l_brace, tok::colon, tok::kw_try) && + "Inline method not starting with '{', ':' or 'try'"); // Parse the method body. Function body parsing code is similar enough // to be re-used for method bodies as well. diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp index abf16fa..9d2a2b9 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp @@ -179,8 +179,8 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() { ConsumeToken(); // Skip attributes. - while (Tok.is(tok::l_square) || Tok.is(tok::kw___attribute) || - Tok.is(tok::kw___declspec) || Tok.is(tok::kw_alignas)) { + while (Tok.isOneOf(tok::l_square, tok::kw___attribute, tok::kw___declspec, + tok::kw_alignas)) { if (Tok.is(tok::l_square)) { ConsumeBracket(); if (!SkipUntil(tok::r_square)) @@ -195,8 +195,8 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() { } } - if ((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || - Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id)) && + if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_decltype, + tok::annot_template_id) && TryAnnotateCXXScopeToken()) return TPResult::Error; if (Tok.is(tok::annot_cxxscope)) @@ -289,7 +289,7 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() { return TPR; // [GNU] simple-asm-expr[opt] attributes[opt] - if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute)) + if (Tok.isOneOf(tok::kw_asm, tok::kw___attribute)) return TPResult::True; // initializer[opt] @@ -370,8 +370,7 @@ bool Parser::isCXXConditionDeclaration() { if (TPR == TPResult::Ambiguous) { // '=' // [GNU] simple-asm-expr[opt] attributes[opt] - if (Tok.is(tok::equal) || - Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute)) + if (Tok.isOneOf(tok::equal, tok::kw_asm, tok::kw___attribute)) TPR = TPResult::True; else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) TPR = TPResult::True; @@ -448,7 +447,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { // the abstract declarator we encounter a '>', '>>' (in C++0x), or // ',', this is a type-id. Otherwise, it's an expression. } else if (Context == TypeIdAsTemplateArgument && - (Tok.is(tok::greater) || Tok.is(tok::comma) || + (Tok.isOneOf(tok::greater, tok::comma) || (getLangOpts().CPlusPlus11 && Tok.is(tok::greatergreater)))) { TPR = TPResult::True; isAmbiguous = true; @@ -624,18 +623,17 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, Parser::TPResult Parser::TryParsePtrOperatorSeq() { while (true) { - if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier)) + if (Tok.isOneOf(tok::coloncolon, tok::identifier)) if (TryAnnotateCXXScopeToken(true)) return TPResult::Error; - if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) || - Tok.is(tok::ampamp) || + if (Tok.isOneOf(tok::star, tok::amp, tok::caret, tok::ampamp) || (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { // ptr-operator ConsumeToken(); - while (Tok.is(tok::kw_const) || - Tok.is(tok::kw_volatile) || - Tok.is(tok::kw_restrict)) + while (Tok.isOneOf(tok::kw_const, tok::kw_volatile, tok::kw_restrict, + tok::kw__Nonnull, tok::kw__Nullable, + tok::kw__Null_unspecified)) ConsumeToken(); } else { return TPResult::True; @@ -803,7 +801,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, if (Tok.is(tok::ellipsis)) ConsumeToken(); - if ((Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || + if ((Tok.isOneOf(tok::identifier, tok::kw_operator) || (Tok.is(tok::annot_cxxscope) && (NextToken().is(tok::identifier) || NextToken().is(tok::kw_operator)))) && mayHaveIdentifier) { @@ -833,14 +831,9 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // '(' declarator ')' // '(' attributes declarator ')' // '(' abstract-declarator ')' - if (Tok.is(tok::kw___attribute) || - Tok.is(tok::kw___declspec) || - Tok.is(tok::kw___cdecl) || - Tok.is(tok::kw___stdcall) || - Tok.is(tok::kw___fastcall) || - Tok.is(tok::kw___thiscall) || - Tok.is(tok::kw___vectorcall) || - Tok.is(tok::kw___unaligned)) + if (Tok.isOneOf(tok::kw___attribute, tok::kw___declspec, tok::kw___cdecl, + tok::kw___stdcall, tok::kw___fastcall, tok::kw___thiscall, + tok::kw___vectorcall, tok::kw___unaligned)) return TPResult::True; // attributes indicate declaration TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier); if (TPR != TPResult::Ambiguous) @@ -1015,9 +1008,8 @@ class TentativeParseCCC : public CorrectionCandidateCallback { public: TentativeParseCCC(const Token &Next) { WantRemainingKeywords = false; - WantTypeSpecifiers = Next.is(tok::l_paren) || Next.is(tok::r_paren) || - Next.is(tok::greater) || Next.is(tok::l_brace) || - Next.is(tok::identifier); + WantTypeSpecifiers = Next.isOneOf(tok::l_paren, tok::r_paren, tok::greater, + tok::l_brace, tok::identifier); } bool ValidateCandidate(const TypoCorrection &Candidate) override { @@ -1201,8 +1193,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::coloncolon: { // ::foo::bar const Token &Next = NextToken(); - if (Next.is(tok::kw_new) || // ::new - Next.is(tok::kw_delete)) // ::delete + if (Next.isOneOf(tok::kw_new, // ::new + tok::kw_delete)) // ::delete return TPResult::False; } // Fall through. @@ -1221,9 +1213,11 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // 'friend' // 'typedef' // 'constexpr' + // 'concept' case tok::kw_friend: case tok::kw_typedef: case tok::kw_constexpr: + case tok::kw_concept: // storage-class-specifier case tok::kw_register: case tok::kw_static: @@ -1284,6 +1278,10 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw___ptr32: case tok::kw___forceinline: case tok::kw___unaligned: + case tok::kw__Nonnull: + case tok::kw__Nullable: + case tok::kw__Null_unspecified: + case tok::kw___kindof: return TPResult::True; // Borland @@ -1387,7 +1385,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case_typename: // In Objective-C, we might have a protocol-qualified type. if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { - // Tentatively parse the + // Tentatively parse the protocol qualifiers. TentativeParsingAction PA(*this); ConsumeToken(); // The type token @@ -1603,12 +1601,10 @@ bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) { TPR = TPResult::False; else { const Token &Next = NextToken(); - if (Next.is(tok::amp) || Next.is(tok::ampamp) || - Next.is(tok::kw_const) || Next.is(tok::kw_volatile) || - Next.is(tok::kw_throw) || Next.is(tok::kw_noexcept) || - Next.is(tok::l_square) || isCXX11VirtSpecifier(Next) || - Next.is(tok::l_brace) || Next.is(tok::kw_try) || - Next.is(tok::equal) || Next.is(tok::arrow)) + if (Next.isOneOf(tok::amp, tok::ampamp, tok::kw_const, tok::kw_volatile, + tok::kw_throw, tok::kw_noexcept, tok::l_square, + tok::l_brace, tok::kw_try, tok::equal, tok::arrow) || + isCXX11VirtSpecifier(Next)) // The next token cannot appear after a constructor-style initializer, // and can appear next in a function definition. This must be a function // declarator. @@ -1729,8 +1725,8 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration, // parameter-declaration-clause, and the last param is missing its default // argument. if (VersusTemplateArgument) - return (Tok.is(tok::equal) || Tok.is(tok::r_paren)) ? TPResult::True - : TPResult::False; + return Tok.isOneOf(tok::equal, tok::r_paren) ? TPResult::True + : TPResult::False; if (Tok.is(tok::equal)) { // '=' assignment-expression @@ -1783,13 +1779,11 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() { return TPResult::Error; // cv-qualifier-seq - while (Tok.is(tok::kw_const) || - Tok.is(tok::kw_volatile) || - Tok.is(tok::kw_restrict) ) + while (Tok.isOneOf(tok::kw_const, tok::kw_volatile, tok::kw_restrict)) ConsumeToken(); // ref-qualifier[opt] - if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) + if (Tok.isOneOf(tok::amp, tok::ampamp)) ConsumeToken(); // exception-specification diff --git a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp index 7ccd209..0574a63 100644 --- a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp @@ -38,6 +38,26 @@ public: return false; } }; + +/// \brief RAIIObject to destroy the contents of a SmallVector of +/// TemplateIdAnnotation pointers and clear the vector. +class DestroyTemplateIdAnnotationsRAIIObj { + SmallVectorImpl<TemplateIdAnnotation *> &Container; + +public: + DestroyTemplateIdAnnotationsRAIIObj( + SmallVectorImpl<TemplateIdAnnotation *> &Container) + : Container(Container) {} + + ~DestroyTemplateIdAnnotationsRAIIObj() { + for (SmallVectorImpl<TemplateIdAnnotation *>::iterator I = + Container.begin(), + E = Container.end(); + I != E; ++I) + (*I)->Destroy(); + Container.clear(); + } +}; } // end anonymous namespace IdentifierInfo *Parser::getSEHExceptKeyword() { @@ -414,6 +434,15 @@ Parser::~Parser() { PP.clearCodeCompletionHandler(); + if (getLangOpts().DelayedTemplateParsing && + !PP.isIncrementalProcessingEnabled() && !TemplateIds.empty()) { + // If an ASTConsumer parsed delay-parsed templates in their + // HandleTranslationUnit() method, TemplateIds created there were not + // guarded by a DestroyTemplateIdAnnotationsRAIIObj object in + // ParseTopLevelDecl(). Destroy them here. + DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds); + } + assert(TemplateIds.empty() && "Still alive TemplateIdAnnotations around?"); } @@ -434,6 +463,10 @@ void Parser::Initialize() { ObjCTypeQuals[objc_oneway] = &PP.getIdentifierTable().get("oneway"); ObjCTypeQuals[objc_bycopy] = &PP.getIdentifierTable().get("bycopy"); ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref"); + ObjCTypeQuals[objc_nonnull] = &PP.getIdentifierTable().get("nonnull"); + ObjCTypeQuals[objc_nullable] = &PP.getIdentifierTable().get("nullable"); + ObjCTypeQuals[objc_null_unspecified] + = &PP.getIdentifierTable().get("null_unspecified"); } Ident_instancetype = nullptr; @@ -443,11 +476,15 @@ void Parser::Initialize() { Ident_super = &PP.getIdentifierTable().get("super"); - if (getLangOpts().AltiVec) { + Ident_vector = nullptr; + Ident_bool = nullptr; + Ident_pixel = nullptr; + if (getLangOpts().AltiVec || getLangOpts().ZVector) { Ident_vector = &PP.getIdentifierTable().get("vector"); - Ident_pixel = &PP.getIdentifierTable().get("pixel"); Ident_bool = &PP.getIdentifierTable().get("bool"); } + if (getLangOpts().AltiVec) + Ident_pixel = &PP.getIdentifierTable().get("pixel"); Ident_introduced = nullptr; Ident_deprecated = nullptr; @@ -490,26 +527,6 @@ void Parser::Initialize() { ConsumeToken(); } -namespace { - /// \brief RAIIObject to destroy the contents of a SmallVector of - /// TemplateIdAnnotation pointers and clear the vector. - class DestroyTemplateIdAnnotationsRAIIObj { - SmallVectorImpl<TemplateIdAnnotation *> &Container; - public: - DestroyTemplateIdAnnotationsRAIIObj(SmallVectorImpl<TemplateIdAnnotation *> - &Container) - : Container(Container) {} - - ~DestroyTemplateIdAnnotationsRAIIObj() { - for (SmallVectorImpl<TemplateIdAnnotation *>::iterator I = - Container.begin(), E = Container.end(); - I != E; ++I) - (*I)->Destroy(); - Container.clear(); - } - }; -} - void Parser::LateTemplateParserCleanupCallback(void *P) { // While this RAII helper doesn't bracket any actual work, the destructor will // clean up annotations that were created during ActOnEndOfTranslationUnit @@ -541,8 +558,14 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { return false; case tok::annot_module_begin: + Actions.ActOnModuleBegin(Tok.getLocation(), reinterpret_cast<Module *>( + Tok.getAnnotationValue())); + ConsumeToken(); + return false; + case tok::annot_module_end: - // FIXME: Update visibility based on the submodule we're in. + Actions.ActOnModuleEnd(Tok.getLocation(), reinterpret_cast<Module *>( + Tok.getAnnotationValue())); ConsumeToken(); return false; @@ -669,8 +692,18 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, SourceLocation StartLoc = Tok.getLocation(); SourceLocation EndLoc; + ExprResult Result(ParseSimpleAsm(&EndLoc)); + // Check if GNU-style InlineAsm is disabled. + // Empty asm string is allowed because it will not introduce + // any assembly code. + if (!(getLangOpts().GNUAsm || Result.isInvalid())) { + const auto *SL = cast<StringLiteral>(Result.get()); + if (!SL->getString().trim().empty()) + Diag(StartLoc, diag::err_gnu_inline_asm_disabled); + } + ExpectAndConsume(tok::semi, diag::err_expected_after, "top-level asm block"); @@ -1048,7 +1081,6 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, if (TryConsumeToken(tok::equal)) { assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='"); - Actions.ActOnFinishFunctionBody(Res, nullptr, false); bool Delete = false; SourceLocation KWLoc; @@ -1076,6 +1108,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, SkipUntil(tok::semi); } + Stmt *GeneratedBody = Res ? Res->getBody() : nullptr; + Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false); return Res; } @@ -1383,14 +1417,35 @@ Parser::TryAnnotateName(bool IsAddressOfOperand, // It's not something we know about. Leave it unannotated. break; - case Sema::NC_Type: - Tok.setKind(tok::annot_typename); - setTypeAnnotation(Tok, Classification.getType()); - Tok.setAnnotationEndLoc(NameLoc); + case Sema::NC_Type: { + SourceLocation BeginLoc = NameLoc; if (SS.isNotEmpty()) - Tok.setLocation(SS.getBeginLoc()); + BeginLoc = SS.getBeginLoc(); + + /// An Objective-C object type followed by '<' is a specialization of + /// a parameterized class type or a protocol-qualified type. + ParsedType Ty = Classification.getType(); + if (getLangOpts().ObjC1 && NextToken().is(tok::less) && + (Ty.get()->isObjCObjectType() || + Ty.get()->isObjCObjectPointerType())) { + // Consume the name. + SourceLocation IdentifierLoc = ConsumeToken(); + SourceLocation NewEndLoc; + TypeResult NewType + = parseObjCTypeArgsAndProtocolQualifiers(IdentifierLoc, Ty, + /*consumeLastToken=*/false, + NewEndLoc); + if (NewType.isUsable()) + Ty = NewType.get(); + } + + Tok.setKind(tok::annot_typename); + setTypeAnnotation(Tok, Ty); + Tok.setAnnotationEndLoc(Tok.getLocation()); + Tok.setLocation(BeginLoc); PP.AnnotateCachedTokens(Tok); return ANK_Success; + } case Sema::NC_Expression: Tok.setKind(tok::annot_primary_expr); @@ -1597,13 +1652,33 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext, // A FixIt was applied as a result of typo correction if (CorrectedII) Tok.setIdentifierInfo(CorrectedII); + + SourceLocation BeginLoc = Tok.getLocation(); + if (SS.isNotEmpty()) // it was a C++ qualified type name. + BeginLoc = SS.getBeginLoc(); + + /// An Objective-C object type followed by '<' is a specialization of + /// a parameterized class type or a protocol-qualified type. + if (getLangOpts().ObjC1 && NextToken().is(tok::less) && + (Ty.get()->isObjCObjectType() || + Ty.get()->isObjCObjectPointerType())) { + // Consume the name. + SourceLocation IdentifierLoc = ConsumeToken(); + SourceLocation NewEndLoc; + TypeResult NewType + = parseObjCTypeArgsAndProtocolQualifiers(IdentifierLoc, Ty, + /*consumeLastToken=*/false, + NewEndLoc); + if (NewType.isUsable()) + Ty = NewType.get(); + } + // This is a typename. Replace the current token in-place with an // annotation type token. Tok.setKind(tok::annot_typename); setTypeAnnotation(Tok, Ty); Tok.setAnnotationEndLoc(Tok.getLocation()); - if (SS.isNotEmpty()) // it was a C++ qualified type name. - Tok.setLocation(SS.getBeginLoc()); + Tok.setLocation(BeginLoc); // In case the tokens were cached, have Preprocessor replace // them with the annotation token. diff --git a/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h b/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h index a0c9c1f..36d87eb 100644 --- a/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h +++ b/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h @@ -58,6 +58,12 @@ namespace clang { Active = false; } } + SuppressAccessChecks(SuppressAccessChecks &&Other) + : S(Other.S), DiagnosticPool(std::move(Other.DiagnosticPool)), + State(Other.State), Active(Other.Active) { + Other.Active = false; + } + void operator=(SuppressAccessChecks &&Other) = delete; void done() { assert(Active && "trying to end an inactive suppression"); @@ -87,8 +93,8 @@ namespace clang { Sema::ParsingDeclState State; bool Popped; - ParsingDeclRAIIObject(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION; - void operator=(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION; + ParsingDeclRAIIObject(const ParsingDeclRAIIObject &) = delete; + void operator=(const ParsingDeclRAIIObject &) = delete; public: enum NoParent_t { NoParent }; @@ -244,8 +250,8 @@ namespace clang { /// the way they used to be. This is used to handle __extension__ in the /// parser. class ExtensionRAIIObject { - ExtensionRAIIObject(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION; - void operator=(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION; + ExtensionRAIIObject(const ExtensionRAIIObject &) = delete; + void operator=(const ExtensionRAIIObject &) = delete; DiagnosticsEngine &Diags; public: @@ -423,7 +429,13 @@ namespace clang { if (P.Tok.is(Close)) { LClose = (P.*Consumer)(); return false; - } + } else if (P.Tok.is(tok::semi) && P.NextToken().is(Close)) { + SourceLocation SemiLoc = P.ConsumeToken(); + P.Diag(SemiLoc, diag::err_unexpected_semi) + << Close << FixItHint::CreateRemoval(SourceRange(SemiLoc, SemiLoc)); + LClose = (P.*Consumer)(); + return false; + } return diagnoseMissingClose(); } |