|  | //===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | /// \file | 
|  | /// This file implements parsing of all OpenMP directives and clauses. | 
|  | /// | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/AST/OpenMPClause.h" | 
|  | #include "clang/Basic/DiagnosticParse.h" | 
|  | #include "clang/Basic/OpenMPKinds.h" | 
|  | #include "clang/Basic/TargetInfo.h" | 
|  | #include "clang/Basic/TokenKinds.h" | 
|  | #include "clang/Parse/Parser.h" | 
|  | #include "clang/Parse/RAIIObjectsForParser.h" | 
|  | #include "clang/Sema/EnterExpressionEvaluationContext.h" | 
|  | #include "clang/Sema/Scope.h" | 
|  | #include "clang/Sema/SemaAMDGPU.h" | 
|  | #include "clang/Sema/SemaCodeCompletion.h" | 
|  | #include "clang/Sema/SemaOpenMP.h" | 
|  | #include "llvm/ADT/SmallBitVector.h" | 
|  | #include "llvm/ADT/StringSwitch.h" | 
|  | #include "llvm/Frontend/OpenMP/DirectiveNameParser.h" | 
|  | #include "llvm/Frontend/OpenMP/OMPAssume.h" | 
|  | #include "llvm/Frontend/OpenMP/OMPContext.h" | 
|  | #include <optional> | 
|  |  | 
|  | using namespace clang; | 
|  | using namespace llvm::omp; | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // OpenMP declarative directives. | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | namespace { | 
|  | class DeclDirectiveListParserHelper final { | 
|  | SmallVector<Expr *, 4> Identifiers; | 
|  | Parser *P; | 
|  | OpenMPDirectiveKind Kind; | 
|  |  | 
|  | public: | 
|  | DeclDirectiveListParserHelper(Parser *P, OpenMPDirectiveKind Kind) | 
|  | : P(P), Kind(Kind) {} | 
|  | void operator()(CXXScopeSpec &SS, DeclarationNameInfo NameInfo) { | 
|  | ExprResult Res = P->getActions().OpenMP().ActOnOpenMPIdExpression( | 
|  | P->getCurScope(), SS, NameInfo, Kind); | 
|  | if (Res.isUsable()) | 
|  | Identifiers.push_back(Res.get()); | 
|  | } | 
|  | llvm::ArrayRef<Expr *> getIdentifiers() const { return Identifiers; } | 
|  | }; | 
|  | } // namespace | 
|  |  | 
|  | static OpenMPDirectiveKind checkOpenMPDirectiveName(Parser &P, | 
|  | SourceLocation Loc, | 
|  | OpenMPDirectiveKind Kind, | 
|  | StringRef Name) { | 
|  | unsigned Version = P.getLangOpts().OpenMP; | 
|  | auto [D, VR] = getOpenMPDirectiveKindAndVersions(Name); | 
|  | assert(D == Kind && "Directive kind mismatch"); | 
|  | // Ignore the case Version > VR.Max: In OpenMP 6.0 all prior spellings | 
|  | // are explicitly allowed. | 
|  | if (static_cast<int>(Version) < VR.Min) | 
|  | P.Diag(Loc, diag::warn_omp_future_directive_spelling) << Name; | 
|  |  | 
|  | return Kind; | 
|  | } | 
|  |  | 
|  | static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) { | 
|  | static const DirectiveNameParser DirParser; | 
|  |  | 
|  | const DirectiveNameParser::State *S = DirParser.initial(); | 
|  |  | 
|  | Token Tok = P.getCurToken(); | 
|  | if (Tok.isAnnotation()) | 
|  | return OMPD_unknown; | 
|  |  | 
|  | std::string Concat = P.getPreprocessor().getSpelling(Tok); | 
|  | SourceLocation Loc = Tok.getLocation(); | 
|  |  | 
|  | S = DirParser.consume(S, Concat); | 
|  | if (S == nullptr) | 
|  | return OMPD_unknown; | 
|  |  | 
|  | while (!Tok.isAnnotation()) { | 
|  | OpenMPDirectiveKind DKind = S->Value; | 
|  | Tok = P.getPreprocessor().LookAhead(0); | 
|  | if (!Tok.isAnnotation()) { | 
|  | std::string TS = P.getPreprocessor().getSpelling(Tok); | 
|  | S = DirParser.consume(S, TS); | 
|  | if (S == nullptr) | 
|  | return checkOpenMPDirectiveName(P, Loc, DKind, Concat); | 
|  | Concat += ' ' + TS; | 
|  | P.ConsumeToken(); | 
|  | } | 
|  | } | 
|  |  | 
|  | assert(S && "Should have exited early"); | 
|  | return checkOpenMPDirectiveName(P, Loc, S->Value, Concat); | 
|  | } | 
|  |  | 
|  | static DeclarationName parseOpenMPReductionId(Parser &P) { | 
|  | Token Tok = P.getCurToken(); | 
|  | Sema &Actions = P.getActions(); | 
|  | OverloadedOperatorKind OOK = OO_None; | 
|  | // Allow to use 'operator' keyword for C++ operators | 
|  | bool WithOperator = false; | 
|  | if (Tok.is(tok::kw_operator)) { | 
|  | P.ConsumeToken(); | 
|  | Tok = P.getCurToken(); | 
|  | WithOperator = true; | 
|  | } | 
|  | switch (Tok.getKind()) { | 
|  | case tok::plus: // '+' | 
|  | OOK = OO_Plus; | 
|  | break; | 
|  | case tok::minus: // '-' | 
|  | OOK = OO_Minus; | 
|  | break; | 
|  | case tok::star: // '*' | 
|  | OOK = OO_Star; | 
|  | break; | 
|  | case tok::amp: // '&' | 
|  | OOK = OO_Amp; | 
|  | break; | 
|  | case tok::pipe: // '|' | 
|  | OOK = OO_Pipe; | 
|  | break; | 
|  | case tok::caret: // '^' | 
|  | OOK = OO_Caret; | 
|  | break; | 
|  | case tok::ampamp: // '&&' | 
|  | OOK = OO_AmpAmp; | 
|  | break; | 
|  | case tok::pipepipe: // '||' | 
|  | OOK = OO_PipePipe; | 
|  | break; | 
|  | case tok::identifier: // identifier | 
|  | if (!WithOperator) | 
|  | break; | 
|  | [[fallthrough]]; | 
|  | default: | 
|  | P.Diag(Tok.getLocation(), diag::err_omp_expected_reduction_identifier); | 
|  | P.SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | Parser::StopBeforeMatch); | 
|  | return DeclarationName(); | 
|  | } | 
|  | P.ConsumeToken(); | 
|  | auto &DeclNames = Actions.getASTContext().DeclarationNames; | 
|  | return OOK == OO_None ? DeclNames.getIdentifier(Tok.getIdentifierInfo()) | 
|  | : DeclNames.getCXXOperatorName(OOK); | 
|  | } | 
|  |  | 
|  | Parser::DeclGroupPtrTy | 
|  | Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { | 
|  | unsigned OMPVersion = Actions.getLangOpts().OpenMP; | 
|  | // Parse '('. | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume( | 
|  | diag::err_expected_lparen_after, | 
|  | getOpenMPDirectiveName(OMPD_declare_reduction, OMPVersion).data())) { | 
|  | SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); | 
|  | return DeclGroupPtrTy(); | 
|  | } | 
|  |  | 
|  | DeclarationName Name = parseOpenMPReductionId(*this); | 
|  | if (Name.isEmpty() && Tok.is(tok::annot_pragma_openmp_end)) | 
|  | return DeclGroupPtrTy(); | 
|  |  | 
|  | // Consume ':'. | 
|  | bool IsCorrect = !ExpectAndConsume(tok::colon); | 
|  |  | 
|  | if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) | 
|  | return DeclGroupPtrTy(); | 
|  |  | 
|  | IsCorrect = IsCorrect && !Name.isEmpty(); | 
|  |  | 
|  | if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) { | 
|  | Diag(Tok.getLocation(), diag::err_expected_type); | 
|  | IsCorrect = false; | 
|  | } | 
|  |  | 
|  | if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) | 
|  | return DeclGroupPtrTy(); | 
|  |  | 
|  | SmallVector<std::pair<QualType, SourceLocation>, 8> ReductionTypes; | 
|  | // Parse list of types until ':' token. | 
|  | do { | 
|  | ColonProtectionRAIIObject ColonRAII(*this); | 
|  | SourceRange Range; | 
|  | TypeResult TR = ParseTypeName(&Range, DeclaratorContext::Prototype, AS); | 
|  | if (TR.isUsable()) { | 
|  | QualType ReductionType = Actions.OpenMP().ActOnOpenMPDeclareReductionType( | 
|  | Range.getBegin(), TR); | 
|  | if (!ReductionType.isNull()) { | 
|  | ReductionTypes.push_back( | 
|  | std::make_pair(ReductionType, Range.getBegin())); | 
|  | } | 
|  | } else { | 
|  | SkipUntil(tok::comma, tok::colon, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | } | 
|  |  | 
|  | if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) | 
|  | break; | 
|  |  | 
|  | // Consume ','. | 
|  | if (ExpectAndConsume(tok::comma)) { | 
|  | IsCorrect = false; | 
|  | if (Tok.is(tok::annot_pragma_openmp_end)) { | 
|  | Diag(Tok.getLocation(), diag::err_expected_type); | 
|  | return DeclGroupPtrTy(); | 
|  | } | 
|  | } | 
|  | } while (Tok.isNot(tok::annot_pragma_openmp_end)); | 
|  |  | 
|  | if (ReductionTypes.empty()) { | 
|  | SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); | 
|  | return DeclGroupPtrTy(); | 
|  | } | 
|  |  | 
|  | if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) | 
|  | return DeclGroupPtrTy(); | 
|  |  | 
|  | // Consume ':'. | 
|  | if (ExpectAndConsume(tok::colon)) | 
|  | IsCorrect = false; | 
|  |  | 
|  | if (Tok.is(tok::annot_pragma_openmp_end)) { | 
|  | Diag(Tok.getLocation(), diag::err_expected_expression); | 
|  | return DeclGroupPtrTy(); | 
|  | } | 
|  |  | 
|  | DeclGroupPtrTy DRD = | 
|  | Actions.OpenMP().ActOnOpenMPDeclareReductionDirectiveStart( | 
|  | getCurScope(), Actions.getCurLexicalContext(), Name, ReductionTypes, | 
|  | AS); | 
|  |  | 
|  | // Parse <combiner> expression and then parse initializer if any for each | 
|  | // correct type. | 
|  | unsigned I = 0, E = ReductionTypes.size(); | 
|  | for (Decl *D : DRD.get()) { | 
|  | TentativeParsingAction TPA(*this); | 
|  | ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope | | 
|  | Scope::CompoundStmtScope | | 
|  | Scope::OpenMPDirectiveScope); | 
|  | // Parse <combiner> expression. | 
|  | Actions.OpenMP().ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D); | 
|  | ExprResult CombinerResult = Actions.ActOnFinishFullExpr( | 
|  | ParseExpression().get(), D->getLocation(), /*DiscardedValue*/ false); | 
|  | Actions.OpenMP().ActOnOpenMPDeclareReductionCombinerEnd( | 
|  | D, CombinerResult.get()); | 
|  |  | 
|  | if (CombinerResult.isInvalid() && Tok.isNot(tok::r_paren) && | 
|  | Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | TPA.Commit(); | 
|  | IsCorrect = false; | 
|  | break; | 
|  | } | 
|  | IsCorrect = !T.consumeClose() && IsCorrect && CombinerResult.isUsable(); | 
|  | ExprResult InitializerResult; | 
|  | if (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | // Parse <initializer> expression. | 
|  | if (Tok.is(tok::identifier) && | 
|  | Tok.getIdentifierInfo()->isStr("initializer")) { | 
|  | ConsumeToken(); | 
|  | } else { | 
|  | Diag(Tok.getLocation(), diag::err_expected) << "'initializer'"; | 
|  | TPA.Commit(); | 
|  | IsCorrect = false; | 
|  | break; | 
|  | } | 
|  | // Parse '('. | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, | 
|  | tok::annot_pragma_openmp_end); | 
|  | IsCorrect = | 
|  | !T.expectAndConsume(diag::err_expected_lparen_after, "initializer") && | 
|  | IsCorrect; | 
|  | if (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope | | 
|  | Scope::CompoundStmtScope | | 
|  | Scope::OpenMPDirectiveScope); | 
|  | // Parse expression. | 
|  | VarDecl *OmpPrivParm = | 
|  | Actions.OpenMP().ActOnOpenMPDeclareReductionInitializerStart( | 
|  | getCurScope(), D); | 
|  | // Check if initializer is omp_priv <init_expr> or something else. | 
|  | if (Tok.is(tok::identifier) && | 
|  | Tok.getIdentifierInfo()->isStr("omp_priv")) { | 
|  | ConsumeToken(); | 
|  | ParseOpenMPReductionInitializerForDecl(OmpPrivParm); | 
|  | } else { | 
|  | InitializerResult = Actions.ActOnFinishFullExpr( | 
|  | ParseAssignmentExpression().get(), D->getLocation(), | 
|  | /*DiscardedValue*/ false); | 
|  | } | 
|  | Actions.OpenMP().ActOnOpenMPDeclareReductionInitializerEnd( | 
|  | D, InitializerResult.get(), OmpPrivParm); | 
|  | if (InitializerResult.isInvalid() && Tok.isNot(tok::r_paren) && | 
|  | Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | TPA.Commit(); | 
|  | IsCorrect = false; | 
|  | break; | 
|  | } | 
|  | IsCorrect = | 
|  | !T.consumeClose() && IsCorrect && !InitializerResult.isInvalid(); | 
|  | } | 
|  | } | 
|  |  | 
|  | ++I; | 
|  | // Revert parsing if not the last type, otherwise accept it, we're done with | 
|  | // parsing. | 
|  | if (I != E) | 
|  | TPA.Revert(); | 
|  | else | 
|  | TPA.Commit(); | 
|  | } | 
|  | return Actions.OpenMP().ActOnOpenMPDeclareReductionDirectiveEnd( | 
|  | getCurScope(), DRD, IsCorrect); | 
|  | } | 
|  |  | 
|  | void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) { | 
|  | // Parse declarator '=' initializer. | 
|  | // If a '==' or '+=' is found, suggest a fixit to '='. | 
|  | if (isTokenEqualOrEqualTypo()) { | 
|  | ConsumeToken(); | 
|  |  | 
|  | if (Tok.is(tok::code_completion)) { | 
|  | cutOffParsing(); | 
|  | Actions.CodeCompletion().CodeCompleteInitializer(getCurScope(), | 
|  | OmpPrivParm); | 
|  | Actions.FinalizeDeclaration(OmpPrivParm); | 
|  | return; | 
|  | } | 
|  |  | 
|  | PreferredType.enterVariableInit(Tok.getLocation(), OmpPrivParm); | 
|  | ExprResult Init = ParseInitializer(); | 
|  |  | 
|  | if (Init.isInvalid()) { | 
|  | SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); | 
|  | Actions.ActOnInitializerError(OmpPrivParm); | 
|  | } else { | 
|  | Actions.AddInitializerToDecl(OmpPrivParm, Init.get(), | 
|  | /*DirectInit=*/false); | 
|  | } | 
|  | } else if (Tok.is(tok::l_paren)) { | 
|  | // Parse C++ direct initializer: '(' expression-list ')' | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren); | 
|  | T.consumeOpen(); | 
|  |  | 
|  | ExprVector Exprs; | 
|  |  | 
|  | SourceLocation LParLoc = T.getOpenLocation(); | 
|  | auto RunSignatureHelp = [this, OmpPrivParm, LParLoc, &Exprs]() { | 
|  | QualType PreferredType = | 
|  | Actions.CodeCompletion().ProduceConstructorSignatureHelp( | 
|  | OmpPrivParm->getType()->getCanonicalTypeInternal(), | 
|  | OmpPrivParm->getLocation(), Exprs, LParLoc, /*Braced=*/false); | 
|  | CalledSignatureHelp = true; | 
|  | return PreferredType; | 
|  | }; | 
|  | if (ParseExpressionList(Exprs, [&] { | 
|  | PreferredType.enterFunctionArgument(Tok.getLocation(), | 
|  | RunSignatureHelp); | 
|  | })) { | 
|  | if (PP.isCodeCompletionReached() && !CalledSignatureHelp) | 
|  | RunSignatureHelp(); | 
|  | Actions.ActOnInitializerError(OmpPrivParm); | 
|  | SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); | 
|  | } else { | 
|  | // Match the ')'. | 
|  | SourceLocation RLoc = Tok.getLocation(); | 
|  | if (!T.consumeClose()) | 
|  | RLoc = T.getCloseLocation(); | 
|  |  | 
|  | ExprResult Initializer = | 
|  | Actions.ActOnParenListExpr(T.getOpenLocation(), RLoc, Exprs); | 
|  | Actions.AddInitializerToDecl(OmpPrivParm, Initializer.get(), | 
|  | /*DirectInit=*/true); | 
|  | } | 
|  | } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { | 
|  | // Parse C++0x braced-init-list. | 
|  | Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); | 
|  |  | 
|  | ExprResult Init(ParseBraceInitializer()); | 
|  |  | 
|  | if (Init.isInvalid()) { | 
|  | Actions.ActOnInitializerError(OmpPrivParm); | 
|  | } else { | 
|  | Actions.AddInitializerToDecl(OmpPrivParm, Init.get(), | 
|  | /*DirectInit=*/true); | 
|  | } | 
|  | } else { | 
|  | Actions.ActOnUninitializedDecl(OmpPrivParm); | 
|  | } | 
|  | } | 
|  |  | 
|  | Parser::DeclGroupPtrTy | 
|  | Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) { | 
|  | bool IsCorrect = true; | 
|  | unsigned OMPVersion = Actions.getLangOpts().OpenMP; | 
|  | // Parse '(' | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume( | 
|  | diag::err_expected_lparen_after, | 
|  | getOpenMPDirectiveName(OMPD_declare_mapper, OMPVersion).data())) { | 
|  | SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); | 
|  | return DeclGroupPtrTy(); | 
|  | } | 
|  |  | 
|  | // Parse <mapper-identifier> | 
|  | auto &DeclNames = Actions.getASTContext().DeclarationNames; | 
|  | DeclarationName MapperId; | 
|  | if (PP.LookAhead(0).is(tok::colon)) { | 
|  | if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_default)) { | 
|  | Diag(Tok.getLocation(), diag::err_omp_mapper_illegal_identifier); | 
|  | IsCorrect = false; | 
|  | } else { | 
|  | MapperId = DeclNames.getIdentifier(Tok.getIdentifierInfo()); | 
|  | } | 
|  | ConsumeToken(); | 
|  | // Consume ':'. | 
|  | ExpectAndConsume(tok::colon); | 
|  | } else { | 
|  | // If no mapper identifier is provided, its name is "default" by default | 
|  | MapperId = | 
|  | DeclNames.getIdentifier(&Actions.getASTContext().Idents.get("default")); | 
|  | } | 
|  |  | 
|  | if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) | 
|  | return DeclGroupPtrTy(); | 
|  |  | 
|  | // Parse <type> <var> | 
|  | DeclarationName VName; | 
|  | QualType MapperType; | 
|  | SourceRange Range; | 
|  | TypeResult ParsedType = parseOpenMPDeclareMapperVarDecl(Range, VName, AS); | 
|  | if (ParsedType.isUsable()) | 
|  | MapperType = Actions.OpenMP().ActOnOpenMPDeclareMapperType(Range.getBegin(), | 
|  | ParsedType); | 
|  | if (MapperType.isNull()) | 
|  | IsCorrect = false; | 
|  | if (!IsCorrect) { | 
|  | SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch); | 
|  | return DeclGroupPtrTy(); | 
|  | } | 
|  |  | 
|  | // Consume ')'. | 
|  | IsCorrect &= !T.consumeClose(); | 
|  | if (!IsCorrect) { | 
|  | SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch); | 
|  | return DeclGroupPtrTy(); | 
|  | } | 
|  |  | 
|  | Scope *OuterScope = getCurScope(); | 
|  | // Enter scope. | 
|  | DeclarationNameInfo DirName; | 
|  | SourceLocation Loc = Tok.getLocation(); | 
|  | unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | | 
|  | Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; | 
|  | ParseScope OMPDirectiveScope(this, ScopeFlags); | 
|  | Actions.OpenMP().StartOpenMPDSABlock(OMPD_declare_mapper, DirName, | 
|  | getCurScope(), Loc); | 
|  |  | 
|  | // Add the mapper variable declaration. | 
|  | ExprResult MapperVarRef = | 
|  | Actions.OpenMP().ActOnOpenMPDeclareMapperDirectiveVarDecl( | 
|  | getCurScope(), MapperType, Range.getBegin(), VName); | 
|  |  | 
|  | // Parse map clauses. | 
|  | SmallVector<OMPClause *, 6> Clauses; | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | OpenMPClauseKind CKind = Tok.isAnnotation() | 
|  | ? OMPC_unknown | 
|  | : getOpenMPClauseKind(PP.getSpelling(Tok)); | 
|  | Actions.OpenMP().StartOpenMPClause(CKind); | 
|  | OMPClause *Clause = | 
|  | ParseOpenMPClause(OMPD_declare_mapper, CKind, Clauses.empty()); | 
|  | if (Clause) | 
|  | Clauses.push_back(Clause); | 
|  | else | 
|  | IsCorrect = false; | 
|  | // Skip ',' if any. | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | Actions.OpenMP().EndOpenMPClause(); | 
|  | } | 
|  | if (Clauses.empty()) { | 
|  | Diag(Tok, diag::err_omp_expected_clause) | 
|  | << getOpenMPDirectiveName(OMPD_declare_mapper, OMPVersion); | 
|  | IsCorrect = false; | 
|  | } | 
|  |  | 
|  | // This needs to be called within the scope because | 
|  | // processImplicitMapsWithDefaultMappers may add clauses when analyzing nested | 
|  | // types. The scope used for calling ActOnOpenMPDeclareMapperDirective, | 
|  | // however, needs to be the outer one, otherwise declared mappers don't become | 
|  | // visible. | 
|  | DeclGroupPtrTy DG = Actions.OpenMP().ActOnOpenMPDeclareMapperDirective( | 
|  | OuterScope, Actions.getCurLexicalContext(), MapperId, MapperType, | 
|  | Range.getBegin(), VName, AS, MapperVarRef.get(), Clauses); | 
|  | // Exit scope. | 
|  | Actions.OpenMP().EndOpenMPDSABlock(nullptr); | 
|  | OMPDirectiveScope.Exit(); | 
|  | if (!IsCorrect) | 
|  | return DeclGroupPtrTy(); | 
|  |  | 
|  | return DG; | 
|  | } | 
|  |  | 
|  | TypeResult Parser::parseOpenMPDeclareMapperVarDecl(SourceRange &Range, | 
|  | DeclarationName &Name, | 
|  | AccessSpecifier AS) { | 
|  | // Parse the common declaration-specifiers piece. | 
|  | Parser::DeclSpecContext DSC = Parser::DeclSpecContext::DSC_type_specifier; | 
|  | DeclSpec DS(AttrFactory); | 
|  | ParseSpecifierQualifierList(DS, AS, DSC); | 
|  |  | 
|  | // Parse the declarator. | 
|  | DeclaratorContext Context = DeclaratorContext::Prototype; | 
|  | Declarator DeclaratorInfo(DS, ParsedAttributesView::none(), Context); | 
|  | ParseDeclarator(DeclaratorInfo); | 
|  | Range = DeclaratorInfo.getSourceRange(); | 
|  | if (DeclaratorInfo.getIdentifier() == nullptr) { | 
|  | Diag(Tok.getLocation(), diag::err_omp_mapper_expected_declarator); | 
|  | return true; | 
|  | } | 
|  | Name = Actions.GetNameForDeclarator(DeclaratorInfo).getName(); | 
|  |  | 
|  | return Actions.OpenMP().ActOnOpenMPDeclareMapperVarDecl(getCurScope(), | 
|  | DeclaratorInfo); | 
|  | } | 
|  |  | 
|  | /// Parses 'omp begin declare variant' directive. | 
|  | // The syntax is: | 
|  | // { #pragma omp begin declare variant clause } | 
|  | // <function-declaration-or-definition-sequence> | 
|  | // { #pragma omp end declare variant } | 
|  | // | 
|  | bool Parser::ParseOpenMPDeclareBeginVariantDirective(SourceLocation Loc) { | 
|  | OMPTraitInfo *ParentTI = | 
|  | Actions.OpenMP().getOMPTraitInfoForSurroundingScope(); | 
|  | ASTContext &ASTCtx = Actions.getASTContext(); | 
|  | OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo(); | 
|  | if (parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI)) { | 
|  | while (!SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) | 
|  | ; | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | (void)ConsumeAnnotationToken(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Skip last tokens. | 
|  | skipUntilPragmaOpenMPEnd(OMPD_begin_declare_variant); | 
|  |  | 
|  | ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false); | 
|  |  | 
|  | VariantMatchInfo VMI; | 
|  | TI.getAsVariantMatchInfo(ASTCtx, VMI); | 
|  |  | 
|  | std::function<void(StringRef)> DiagUnknownTrait = [this, | 
|  | Loc](StringRef ISATrait) { | 
|  | // TODO Track the selector locations in a way that is accessible here | 
|  | // to improve the diagnostic location. | 
|  | Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) << ISATrait; | 
|  | }; | 
|  | TargetOMPContext OMPCtx( | 
|  | ASTCtx, std::move(DiagUnknownTrait), | 
|  | /* CurrentFunctionDecl */ nullptr, | 
|  | /* ConstructTraits */ ArrayRef<llvm::omp::TraitProperty>(), | 
|  | Actions.OpenMP().getOpenMPDeviceNum()); | 
|  |  | 
|  | if (isVariantApplicableInContext(VMI, OMPCtx, | 
|  | /*DeviceOrImplementationSetOnly=*/true)) { | 
|  | Actions.OpenMP().ActOnOpenMPBeginDeclareVariant(Loc, TI); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Elide all the code till the matching end declare variant was found. | 
|  | unsigned Nesting = 1; | 
|  | SourceLocation DKLoc; | 
|  | OpenMPDirectiveKind DK = OMPD_unknown; | 
|  | do { | 
|  | DKLoc = Tok.getLocation(); | 
|  | DK = parseOpenMPDirectiveKind(*this); | 
|  | if (DK == OMPD_end_declare_variant) | 
|  | --Nesting; | 
|  | else if (DK == OMPD_begin_declare_variant) | 
|  | ++Nesting; | 
|  | if (!Nesting || isEofOrEom()) | 
|  | break; | 
|  | ConsumeAnyToken(); | 
|  | } while (true); | 
|  |  | 
|  | parseOMPEndDirective(OMPD_begin_declare_variant, OMPD_end_declare_variant, DK, | 
|  | Loc, DKLoc, /* SkipUntilOpenMPEnd */ true); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | /// RAII that recreates function context for correct parsing of clauses of | 
|  | /// 'declare simd' construct. | 
|  | /// OpenMP, 2.8.2 declare simd Construct | 
|  | /// The expressions appearing in the clauses of this directive are evaluated in | 
|  | /// the scope of the arguments of the function declaration or definition. | 
|  | class FNContextRAII final { | 
|  | Parser &P; | 
|  | Sema::CXXThisScopeRAII *ThisScope; | 
|  | Parser::MultiParseScope Scopes; | 
|  | bool HasFunScope = false; | 
|  | FNContextRAII() = delete; | 
|  | FNContextRAII(const FNContextRAII &) = delete; | 
|  | FNContextRAII &operator=(const FNContextRAII &) = delete; | 
|  |  | 
|  | public: | 
|  | FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr) : P(P), Scopes(P) { | 
|  | Decl *D = *Ptr.get().begin(); | 
|  | NamedDecl *ND = dyn_cast<NamedDecl>(D); | 
|  | RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext()); | 
|  | Sema &Actions = P.getActions(); | 
|  |  | 
|  | // Allow 'this' within late-parsed attributes. | 
|  | ThisScope = new Sema::CXXThisScopeRAII(Actions, RD, Qualifiers(), | 
|  | ND && ND->isCXXInstanceMember()); | 
|  |  | 
|  | // If the Decl is templatized, add template parameters to scope. | 
|  | // FIXME: Track CurTemplateDepth? | 
|  | P.ReenterTemplateScopes(Scopes, D); | 
|  |  | 
|  | // If the Decl is on a function, add function parameters to the scope. | 
|  | if (D->isFunctionOrFunctionTemplate()) { | 
|  | HasFunScope = true; | 
|  | Scopes.Enter(Scope::FnScope | Scope::DeclScope | | 
|  | Scope::CompoundStmtScope); | 
|  | Actions.ActOnReenterFunctionContext(Actions.getCurScope(), D); | 
|  | } | 
|  | } | 
|  | ~FNContextRAII() { | 
|  | if (HasFunScope) | 
|  | P.getActions().ActOnExitFunctionContext(); | 
|  | delete ThisScope; | 
|  | } | 
|  | }; | 
|  | } // namespace | 
|  |  | 
|  | /// Parses clauses for 'declare simd' directive. | 
|  | ///    clause: | 
|  | ///      'inbranch' | 'notinbranch' | 
|  | ///      'simdlen' '(' <expr> ')' | 
|  | ///      { 'uniform' '(' <argument_list> ')' } | 
|  | ///      { 'aligned '(' <argument_list> [ ':' <alignment> ] ')' } | 
|  | ///      { 'linear '(' <argument_list> [ ':' <step> ] ')' } | 
|  | static bool parseDeclareSimdClauses( | 
|  | Parser &P, OMPDeclareSimdDeclAttr::BranchStateTy &BS, ExprResult &SimdLen, | 
|  | SmallVectorImpl<Expr *> &Uniforms, SmallVectorImpl<Expr *> &Aligneds, | 
|  | SmallVectorImpl<Expr *> &Alignments, SmallVectorImpl<Expr *> &Linears, | 
|  | SmallVectorImpl<unsigned> &LinModifiers, SmallVectorImpl<Expr *> &Steps) { | 
|  | SourceRange BSRange; | 
|  | const Token &Tok = P.getCurToken(); | 
|  | bool IsError = false; | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | if (Tok.isNot(tok::identifier)) | 
|  | break; | 
|  | OMPDeclareSimdDeclAttr::BranchStateTy Out; | 
|  | IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | StringRef ClauseName = II->getName(); | 
|  | // Parse 'inranch|notinbranch' clauses. | 
|  | if (OMPDeclareSimdDeclAttr::ConvertStrToBranchStateTy(ClauseName, Out)) { | 
|  | if (BS != OMPDeclareSimdDeclAttr::BS_Undefined && BS != Out) { | 
|  | P.Diag(Tok, diag::err_omp_declare_simd_inbranch_notinbranch) | 
|  | << ClauseName | 
|  | << OMPDeclareSimdDeclAttr::ConvertBranchStateTyToStr(BS) << BSRange; | 
|  | IsError = true; | 
|  | } | 
|  | BS = Out; | 
|  | BSRange = SourceRange(Tok.getLocation(), Tok.getEndLoc()); | 
|  | P.ConsumeToken(); | 
|  | } else if (ClauseName == "simdlen") { | 
|  | if (SimdLen.isUsable()) { | 
|  | unsigned OMPVersion = P.getActions().getLangOpts().OpenMP; | 
|  | P.Diag(Tok, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(OMPD_declare_simd, OMPVersion) | 
|  | << ClauseName << 0; | 
|  | IsError = true; | 
|  | } | 
|  | P.ConsumeToken(); | 
|  | SourceLocation RLoc; | 
|  | SimdLen = P.ParseOpenMPParensExpr(ClauseName, RLoc); | 
|  | if (SimdLen.isInvalid()) | 
|  | IsError = true; | 
|  | } else { | 
|  | OpenMPClauseKind CKind = getOpenMPClauseKind(ClauseName); | 
|  | if (CKind == OMPC_uniform || CKind == OMPC_aligned || | 
|  | CKind == OMPC_linear) { | 
|  | SemaOpenMP::OpenMPVarListDataTy Data; | 
|  | SmallVectorImpl<Expr *> *Vars = &Uniforms; | 
|  | if (CKind == OMPC_aligned) { | 
|  | Vars = &Aligneds; | 
|  | } else if (CKind == OMPC_linear) { | 
|  | Data.ExtraModifier = OMPC_LINEAR_val; | 
|  | Vars = &Linears; | 
|  | } | 
|  |  | 
|  | P.ConsumeToken(); | 
|  | if (P.ParseOpenMPVarList(OMPD_declare_simd, | 
|  | getOpenMPClauseKind(ClauseName), *Vars, Data)) | 
|  | IsError = true; | 
|  | if (CKind == OMPC_aligned) { | 
|  | Alignments.append(Aligneds.size() - Alignments.size(), | 
|  | Data.DepModOrTailExpr); | 
|  | } else if (CKind == OMPC_linear) { | 
|  | assert(0 <= Data.ExtraModifier && | 
|  | Data.ExtraModifier <= OMPC_LINEAR_unknown && | 
|  | "Unexpected linear modifier."); | 
|  | if (P.getActions().OpenMP().CheckOpenMPLinearModifier( | 
|  | static_cast<OpenMPLinearClauseKind>(Data.ExtraModifier), | 
|  | Data.ExtraModifierLoc)) | 
|  | Data.ExtraModifier = OMPC_LINEAR_val; | 
|  | LinModifiers.append(Linears.size() - LinModifiers.size(), | 
|  | Data.ExtraModifier); | 
|  | Steps.append(Linears.size() - Steps.size(), Data.DepModOrTailExpr); | 
|  | } | 
|  | } else | 
|  | // TODO: add parsing of other clauses. | 
|  | break; | 
|  | } | 
|  | // Skip ',' if any. | 
|  | if (Tok.is(tok::comma)) | 
|  | P.ConsumeToken(); | 
|  | } | 
|  | return IsError; | 
|  | } | 
|  |  | 
|  | Parser::DeclGroupPtrTy | 
|  | Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr, | 
|  | CachedTokens &Toks, SourceLocation Loc) { | 
|  | PP.EnterToken(Tok, /*IsReinject*/ true); | 
|  | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | 
|  | /*IsReinject*/ true); | 
|  | // Consume the previously pushed token. | 
|  | ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); | 
|  | ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); | 
|  |  | 
|  | FNContextRAII FnContext(*this, Ptr); | 
|  | OMPDeclareSimdDeclAttr::BranchStateTy BS = | 
|  | OMPDeclareSimdDeclAttr::BS_Undefined; | 
|  | ExprResult Simdlen; | 
|  | SmallVector<Expr *, 4> Uniforms; | 
|  | SmallVector<Expr *, 4> Aligneds; | 
|  | SmallVector<Expr *, 4> Alignments; | 
|  | SmallVector<Expr *, 4> Linears; | 
|  | SmallVector<unsigned, 4> LinModifiers; | 
|  | SmallVector<Expr *, 4> Steps; | 
|  | bool IsError = | 
|  | parseDeclareSimdClauses(*this, BS, Simdlen, Uniforms, Aligneds, | 
|  | Alignments, Linears, LinModifiers, Steps); | 
|  | skipUntilPragmaOpenMPEnd(OMPD_declare_simd); | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | SourceLocation EndLoc = ConsumeAnnotationToken(); | 
|  | if (IsError) | 
|  | return Ptr; | 
|  | return Actions.OpenMP().ActOnOpenMPDeclareSimdDirective( | 
|  | Ptr, BS, Simdlen.get(), Uniforms, Aligneds, Alignments, Linears, | 
|  | LinModifiers, Steps, SourceRange(Loc, EndLoc)); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | /// Constant used in the diagnostics to distinguish the levels in an OpenMP | 
|  | /// contexts: selector-set={selector(trait, ...), ...}, .... | 
|  | enum OMPContextLvl { | 
|  | CONTEXT_SELECTOR_SET_LVL = 0, | 
|  | CONTEXT_SELECTOR_LVL = 1, | 
|  | CONTEXT_TRAIT_LVL = 2, | 
|  | }; | 
|  |  | 
|  | static StringRef stringLiteralParser(Parser &P) { | 
|  | ExprResult Res = P.ParseStringLiteralExpression(true); | 
|  | return Res.isUsable() ? Res.getAs<StringLiteral>()->getString() : ""; | 
|  | } | 
|  |  | 
|  | static StringRef getNameFromIdOrString(Parser &P, Token &Tok, | 
|  | OMPContextLvl Lvl) { | 
|  | if (Tok.is(tok::identifier) || Tok.is(tok::kw_for)) { | 
|  | llvm::SmallString<16> Buffer; | 
|  | StringRef Name = P.getPreprocessor().getSpelling(Tok, Buffer); | 
|  | (void)P.ConsumeToken(); | 
|  | return Name; | 
|  | } | 
|  |  | 
|  | if (tok::isStringLiteral(Tok.getKind())) | 
|  | return stringLiteralParser(P); | 
|  |  | 
|  | P.Diag(Tok.getLocation(), | 
|  | diag::warn_omp_declare_variant_string_literal_or_identifier) | 
|  | << Lvl; | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | static bool checkForDuplicates(Parser &P, StringRef Name, | 
|  | SourceLocation NameLoc, | 
|  | llvm::StringMap<SourceLocation> &Seen, | 
|  | OMPContextLvl Lvl) { | 
|  | auto Res = Seen.try_emplace(Name, NameLoc); | 
|  | if (Res.second) | 
|  | return false; | 
|  |  | 
|  | // Each trait-set-selector-name, trait-selector-name and trait-name can | 
|  | // only be specified once. | 
|  | P.Diag(NameLoc, diag::warn_omp_declare_variant_ctx_mutiple_use) | 
|  | << Lvl << Name; | 
|  | P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here) | 
|  | << Lvl << Name; | 
|  | return true; | 
|  | } | 
|  | } // namespace | 
|  |  | 
|  | void Parser::parseOMPTraitPropertyKind(OMPTraitProperty &TIProperty, | 
|  | llvm::omp::TraitSet Set, | 
|  | llvm::omp::TraitSelector Selector, | 
|  | llvm::StringMap<SourceLocation> &Seen) { | 
|  | TIProperty.Kind = TraitProperty::invalid; | 
|  |  | 
|  | SourceLocation NameLoc = Tok.getLocation(); | 
|  | StringRef Name; | 
|  | if (Selector == llvm::omp::TraitSelector::target_device_device_num) { | 
|  | Name = "number"; | 
|  | TIProperty.Kind = getOpenMPContextTraitPropertyKind(Set, Selector, Name); | 
|  | ExprResult DeviceNumExprResult = ParseExpression(); | 
|  | if (DeviceNumExprResult.isUsable()) { | 
|  | Expr *DeviceNumExpr = DeviceNumExprResult.get(); | 
|  | Actions.OpenMP().ActOnOpenMPDeviceNum(DeviceNumExpr); | 
|  | } | 
|  | return; | 
|  | } | 
|  | Name = getNameFromIdOrString(*this, Tok, CONTEXT_TRAIT_LVL); | 
|  | if (Name.empty()) { | 
|  | Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options) | 
|  | << CONTEXT_TRAIT_LVL << listOpenMPContextTraitProperties(Set, Selector); | 
|  | return; | 
|  | } | 
|  |  | 
|  | TIProperty.RawString = Name; | 
|  | TIProperty.Kind = getOpenMPContextTraitPropertyKind(Set, Selector, Name); | 
|  | if (TIProperty.Kind != TraitProperty::invalid) { | 
|  | if (checkForDuplicates(*this, Name, NameLoc, Seen, CONTEXT_TRAIT_LVL)) | 
|  | TIProperty.Kind = TraitProperty::invalid; | 
|  | return; | 
|  | } | 
|  |  | 
|  | // It follows diagnosis and helping notes. | 
|  | // FIXME: We should move the diagnosis string generation into libFrontend. | 
|  | Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_property) | 
|  | << Name << getOpenMPContextTraitSelectorName(Selector) | 
|  | << getOpenMPContextTraitSetName(Set); | 
|  |  | 
|  | TraitSet SetForName = getOpenMPContextTraitSetKind(Name); | 
|  | if (SetForName != TraitSet::invalid) { | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a) | 
|  | << Name << CONTEXT_SELECTOR_SET_LVL << CONTEXT_TRAIT_LVL; | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) | 
|  | << Name << "<selector-name>" | 
|  | << "(<property-name>)"; | 
|  | return; | 
|  | } | 
|  | TraitSelector SelectorForName = | 
|  | getOpenMPContextTraitSelectorKind(Name, SetForName); | 
|  | if (SelectorForName != TraitSelector::invalid) { | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a) | 
|  | << Name << CONTEXT_SELECTOR_LVL << CONTEXT_TRAIT_LVL; | 
|  | bool AllowsTraitScore = false; | 
|  | bool RequiresProperty = false; | 
|  | isValidTraitSelectorForTraitSet( | 
|  | SelectorForName, getOpenMPContextTraitSetForSelector(SelectorForName), | 
|  | AllowsTraitScore, RequiresProperty); | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) | 
|  | << getOpenMPContextTraitSetName( | 
|  | getOpenMPContextTraitSetForSelector(SelectorForName)) | 
|  | << Name << (RequiresProperty ? "(<property-name>)" : ""); | 
|  | return; | 
|  | } | 
|  | for (const auto &PotentialSet : | 
|  | {TraitSet::construct, TraitSet::user, TraitSet::implementation, | 
|  | TraitSet::device, TraitSet::target_device}) { | 
|  | TraitProperty PropertyForName = | 
|  | getOpenMPContextTraitPropertyKind(PotentialSet, Selector, Name); | 
|  | if (PropertyForName == TraitProperty::invalid) | 
|  | continue; | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) | 
|  | << getOpenMPContextTraitSetName( | 
|  | getOpenMPContextTraitSetForProperty(PropertyForName)) | 
|  | << getOpenMPContextTraitSelectorName( | 
|  | getOpenMPContextTraitSelectorForProperty(PropertyForName)) | 
|  | << ("(" + Name + ")").str(); | 
|  | return; | 
|  | } | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_options) | 
|  | << CONTEXT_TRAIT_LVL << listOpenMPContextTraitProperties(Set, Selector); | 
|  | } | 
|  |  | 
|  | static bool checkExtensionProperty(Parser &P, SourceLocation Loc, | 
|  | OMPTraitProperty &TIProperty, | 
|  | OMPTraitSelector &TISelector, | 
|  | llvm::StringMap<SourceLocation> &Seen) { | 
|  | assert(TISelector.Kind == | 
|  | llvm::omp::TraitSelector::implementation_extension && | 
|  | "Only for extension properties, e.g., " | 
|  | "`implementation={extension(PROPERTY)}`"); | 
|  | if (TIProperty.Kind == TraitProperty::invalid) | 
|  | return false; | 
|  |  | 
|  | if (TIProperty.Kind == | 
|  | TraitProperty::implementation_extension_disable_implicit_base) | 
|  | return true; | 
|  |  | 
|  | if (TIProperty.Kind == | 
|  | TraitProperty::implementation_extension_allow_templates) | 
|  | return true; | 
|  |  | 
|  | if (TIProperty.Kind == | 
|  | TraitProperty::implementation_extension_bind_to_declaration) | 
|  | return true; | 
|  |  | 
|  | auto IsMatchExtension = [](OMPTraitProperty &TP) { | 
|  | return (TP.Kind == | 
|  | llvm::omp::TraitProperty::implementation_extension_match_all || | 
|  | TP.Kind == | 
|  | llvm::omp::TraitProperty::implementation_extension_match_any || | 
|  | TP.Kind == | 
|  | llvm::omp::TraitProperty::implementation_extension_match_none); | 
|  | }; | 
|  |  | 
|  | if (IsMatchExtension(TIProperty)) { | 
|  | for (OMPTraitProperty &SeenProp : TISelector.Properties) | 
|  | if (IsMatchExtension(SeenProp)) { | 
|  | P.Diag(Loc, diag::err_omp_variant_ctx_second_match_extension); | 
|  | StringRef SeenName = llvm::omp::getOpenMPContextTraitPropertyName( | 
|  | SeenProp.Kind, SeenProp.RawString); | 
|  | SourceLocation SeenLoc = Seen[SeenName]; | 
|  | P.Diag(SeenLoc, diag::note_omp_declare_variant_ctx_used_here) | 
|  | << CONTEXT_TRAIT_LVL << SeenName; | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | llvm_unreachable("Unknown extension property!"); | 
|  | } | 
|  |  | 
|  | void Parser::parseOMPContextProperty(OMPTraitSelector &TISelector, | 
|  | llvm::omp::TraitSet Set, | 
|  | llvm::StringMap<SourceLocation> &Seen) { | 
|  | assert(TISelector.Kind != TraitSelector::user_condition && | 
|  | "User conditions are special properties not handled here!"); | 
|  |  | 
|  | SourceLocation PropertyLoc = Tok.getLocation(); | 
|  | OMPTraitProperty TIProperty; | 
|  | parseOMPTraitPropertyKind(TIProperty, Set, TISelector.Kind, Seen); | 
|  |  | 
|  | if (TISelector.Kind == llvm::omp::TraitSelector::implementation_extension) | 
|  | if (!checkExtensionProperty(*this, Tok.getLocation(), TIProperty, | 
|  | TISelector, Seen)) | 
|  | TIProperty.Kind = TraitProperty::invalid; | 
|  |  | 
|  | // If we have an invalid property here we already issued a warning. | 
|  | if (TIProperty.Kind == TraitProperty::invalid) { | 
|  | if (PropertyLoc != Tok.getLocation()) | 
|  | Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here) | 
|  | << CONTEXT_TRAIT_LVL; | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (isValidTraitPropertyForTraitSetAndSelector(TIProperty.Kind, | 
|  | TISelector.Kind, Set)) { | 
|  |  | 
|  | // If we make it here the property, selector, set, score, condition, ... are | 
|  | // all valid (or have been corrected). Thus we can record the property. | 
|  | TISelector.Properties.push_back(TIProperty); | 
|  | return; | 
|  | } | 
|  |  | 
|  | Diag(PropertyLoc, diag::warn_omp_ctx_incompatible_property_for_selector) | 
|  | << getOpenMPContextTraitPropertyName(TIProperty.Kind, | 
|  | TIProperty.RawString) | 
|  | << getOpenMPContextTraitSelectorName(TISelector.Kind) | 
|  | << getOpenMPContextTraitSetName(Set); | 
|  | Diag(PropertyLoc, diag::note_omp_ctx_compatible_set_and_selector_for_property) | 
|  | << getOpenMPContextTraitPropertyName(TIProperty.Kind, | 
|  | TIProperty.RawString) | 
|  | << getOpenMPContextTraitSelectorName( | 
|  | getOpenMPContextTraitSelectorForProperty(TIProperty.Kind)) | 
|  | << getOpenMPContextTraitSetName( | 
|  | getOpenMPContextTraitSetForProperty(TIProperty.Kind)); | 
|  | Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here) | 
|  | << CONTEXT_TRAIT_LVL; | 
|  | } | 
|  |  | 
|  | void Parser::parseOMPTraitSelectorKind(OMPTraitSelector &TISelector, | 
|  | llvm::omp::TraitSet Set, | 
|  | llvm::StringMap<SourceLocation> &Seen) { | 
|  | TISelector.Kind = TraitSelector::invalid; | 
|  |  | 
|  | SourceLocation NameLoc = Tok.getLocation(); | 
|  | StringRef Name = getNameFromIdOrString(*this, Tok, CONTEXT_SELECTOR_LVL); | 
|  | if (Name.empty()) { | 
|  | Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options) | 
|  | << CONTEXT_SELECTOR_LVL << listOpenMPContextTraitSelectors(Set); | 
|  | return; | 
|  | } | 
|  |  | 
|  | TISelector.Kind = getOpenMPContextTraitSelectorKind(Name, Set); | 
|  | if (TISelector.Kind != TraitSelector::invalid) { | 
|  | if (checkForDuplicates(*this, Name, NameLoc, Seen, CONTEXT_SELECTOR_LVL)) | 
|  | TISelector.Kind = TraitSelector::invalid; | 
|  | return; | 
|  | } | 
|  |  | 
|  | // It follows diagnosis and helping notes. | 
|  | Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_selector) | 
|  | << Name << getOpenMPContextTraitSetName(Set); | 
|  |  | 
|  | TraitSet SetForName = getOpenMPContextTraitSetKind(Name); | 
|  | if (SetForName != TraitSet::invalid) { | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a) | 
|  | << Name << CONTEXT_SELECTOR_SET_LVL << CONTEXT_SELECTOR_LVL; | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) | 
|  | << Name << "<selector-name>" | 
|  | << "<property-name>"; | 
|  | return; | 
|  | } | 
|  | for (const auto &PotentialSet : | 
|  | {TraitSet::construct, TraitSet::user, TraitSet::implementation, | 
|  | TraitSet::device, TraitSet::target_device}) { | 
|  | TraitProperty PropertyForName = getOpenMPContextTraitPropertyKind( | 
|  | PotentialSet, TraitSelector::invalid, Name); | 
|  | if (PropertyForName == TraitProperty::invalid) | 
|  | continue; | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a) | 
|  | << Name << CONTEXT_TRAIT_LVL << CONTEXT_SELECTOR_LVL; | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) | 
|  | << getOpenMPContextTraitSetName( | 
|  | getOpenMPContextTraitSetForProperty(PropertyForName)) | 
|  | << getOpenMPContextTraitSelectorName( | 
|  | getOpenMPContextTraitSelectorForProperty(PropertyForName)) | 
|  | << ("(" + Name + ")").str(); | 
|  | return; | 
|  | } | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_options) | 
|  | << CONTEXT_SELECTOR_LVL << listOpenMPContextTraitSelectors(Set); | 
|  | } | 
|  |  | 
|  | /// Parse optional 'score' '(' <expr> ')' ':'. | 
|  | static ExprResult parseContextScore(Parser &P) { | 
|  | ExprResult ScoreExpr; | 
|  | llvm::SmallString<16> Buffer; | 
|  | StringRef SelectorName = | 
|  | P.getPreprocessor().getSpelling(P.getCurToken(), Buffer); | 
|  | if (SelectorName != "score") | 
|  | return ScoreExpr; | 
|  | (void)P.ConsumeToken(); | 
|  | SourceLocation RLoc; | 
|  | ScoreExpr = P.ParseOpenMPParensExpr(SelectorName, RLoc); | 
|  | // Parse ':' | 
|  | if (P.getCurToken().is(tok::colon)) | 
|  | (void)P.ConsumeAnyToken(); | 
|  | else | 
|  | P.Diag(P.getCurToken(), diag::warn_omp_declare_variant_expected) | 
|  | << "':'" | 
|  | << "score expression"; | 
|  | return ScoreExpr; | 
|  | } | 
|  |  | 
|  | void Parser::parseOMPContextSelector( | 
|  | OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, | 
|  | llvm::StringMap<SourceLocation> &SeenSelectors) { | 
|  | unsigned short OuterPC = ParenCount; | 
|  |  | 
|  | // If anything went wrong we issue an error or warning and then skip the rest | 
|  | // of the selector. However, commas are ambiguous so we look for the nesting | 
|  | // of parentheses here as well. | 
|  | auto FinishSelector = [OuterPC, this]() -> void { | 
|  | bool Done = false; | 
|  | while (!Done) { | 
|  | while (!SkipUntil({tok::r_brace, tok::r_paren, tok::comma, | 
|  | tok::annot_pragma_openmp_end}, | 
|  | StopBeforeMatch)) | 
|  | ; | 
|  | if (Tok.is(tok::r_paren) && OuterPC > ParenCount) | 
|  | (void)ConsumeParen(); | 
|  | if (OuterPC <= ParenCount) { | 
|  | Done = true; | 
|  | break; | 
|  | } | 
|  | if (!Tok.is(tok::comma) && !Tok.is(tok::r_paren)) { | 
|  | Done = true; | 
|  | break; | 
|  | } | 
|  | (void)ConsumeAnyToken(); | 
|  | } | 
|  | Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here) | 
|  | << CONTEXT_SELECTOR_LVL; | 
|  | }; | 
|  |  | 
|  | SourceLocation SelectorLoc = Tok.getLocation(); | 
|  | parseOMPTraitSelectorKind(TISelector, Set, SeenSelectors); | 
|  | if (TISelector.Kind == TraitSelector::invalid) | 
|  | return FinishSelector(); | 
|  |  | 
|  | bool AllowsTraitScore = false; | 
|  | bool RequiresProperty = false; | 
|  | if (!isValidTraitSelectorForTraitSet(TISelector.Kind, Set, AllowsTraitScore, | 
|  | RequiresProperty)) { | 
|  | Diag(SelectorLoc, diag::warn_omp_ctx_incompatible_selector_for_set) | 
|  | << getOpenMPContextTraitSelectorName(TISelector.Kind) | 
|  | << getOpenMPContextTraitSetName(Set); | 
|  | Diag(SelectorLoc, diag::note_omp_ctx_compatible_set_for_selector) | 
|  | << getOpenMPContextTraitSelectorName(TISelector.Kind) | 
|  | << getOpenMPContextTraitSetName( | 
|  | getOpenMPContextTraitSetForSelector(TISelector.Kind)) | 
|  | << RequiresProperty; | 
|  | return FinishSelector(); | 
|  | } | 
|  |  | 
|  | if (!RequiresProperty) { | 
|  | TISelector.Properties.push_back( | 
|  | {getOpenMPContextTraitPropertyForSelector(TISelector.Kind), | 
|  | getOpenMPContextTraitSelectorName(TISelector.Kind)}); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!Tok.is(tok::l_paren)) { | 
|  | Diag(SelectorLoc, diag::warn_omp_ctx_selector_without_properties) | 
|  | << getOpenMPContextTraitSelectorName(TISelector.Kind) | 
|  | << getOpenMPContextTraitSetName(Set); | 
|  | return FinishSelector(); | 
|  | } | 
|  |  | 
|  | if (TISelector.Kind == TraitSelector::user_condition) { | 
|  | SourceLocation RLoc; | 
|  | ExprResult Condition = ParseOpenMPParensExpr("user condition", RLoc); | 
|  | if (!Condition.isUsable()) | 
|  | return FinishSelector(); | 
|  | TISelector.ScoreOrCondition = Condition.get(); | 
|  | TISelector.Properties.push_back( | 
|  | {TraitProperty::user_condition_unknown, "<condition>"}); | 
|  | return; | 
|  | } | 
|  |  | 
|  | BalancedDelimiterTracker BDT(*this, tok::l_paren, | 
|  | tok::annot_pragma_openmp_end); | 
|  | // Parse '('. | 
|  | (void)BDT.consumeOpen(); | 
|  |  | 
|  | SourceLocation ScoreLoc = Tok.getLocation(); | 
|  | ExprResult Score = parseContextScore(*this); | 
|  |  | 
|  | if (!AllowsTraitScore && !Score.isUnset()) { | 
|  | if (Score.isUsable()) { | 
|  | Diag(ScoreLoc, diag::warn_omp_ctx_incompatible_score_for_property) | 
|  | << getOpenMPContextTraitSelectorName(TISelector.Kind) | 
|  | << getOpenMPContextTraitSetName(Set) << Score.get(); | 
|  | } else { | 
|  | Diag(ScoreLoc, diag::warn_omp_ctx_incompatible_score_for_property) | 
|  | << getOpenMPContextTraitSelectorName(TISelector.Kind) | 
|  | << getOpenMPContextTraitSetName(Set) << "<invalid>"; | 
|  | } | 
|  | Score = ExprResult(); | 
|  | } | 
|  |  | 
|  | if (Score.isUsable()) | 
|  | TISelector.ScoreOrCondition = Score.get(); | 
|  |  | 
|  | llvm::StringMap<SourceLocation> SeenProperties; | 
|  | do { | 
|  | parseOMPContextProperty(TISelector, Set, SeenProperties); | 
|  | } while (TryConsumeToken(tok::comma)); | 
|  |  | 
|  | // Parse ')'. | 
|  | BDT.consumeClose(); | 
|  | } | 
|  |  | 
|  | void Parser::parseOMPTraitSetKind(OMPTraitSet &TISet, | 
|  | llvm::StringMap<SourceLocation> &Seen) { | 
|  | TISet.Kind = TraitSet::invalid; | 
|  |  | 
|  | SourceLocation NameLoc = Tok.getLocation(); | 
|  | StringRef Name = getNameFromIdOrString(*this, Tok, CONTEXT_SELECTOR_SET_LVL); | 
|  | if (Name.empty()) { | 
|  | Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options) | 
|  | << CONTEXT_SELECTOR_SET_LVL << listOpenMPContextTraitSets(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | TISet.Kind = getOpenMPContextTraitSetKind(Name); | 
|  | if (TISet.Kind != TraitSet::invalid) { | 
|  | if (checkForDuplicates(*this, Name, NameLoc, Seen, | 
|  | CONTEXT_SELECTOR_SET_LVL)) | 
|  | TISet.Kind = TraitSet::invalid; | 
|  | return; | 
|  | } | 
|  |  | 
|  | // It follows diagnosis and helping notes. | 
|  | Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_set) << Name; | 
|  |  | 
|  | TraitSelector SelectorForName = | 
|  | getOpenMPContextTraitSelectorKind(Name, TISet.Kind); | 
|  | if (SelectorForName != TraitSelector::invalid) { | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a) | 
|  | << Name << CONTEXT_SELECTOR_LVL << CONTEXT_SELECTOR_SET_LVL; | 
|  | bool AllowsTraitScore = false; | 
|  | bool RequiresProperty = false; | 
|  | isValidTraitSelectorForTraitSet( | 
|  | SelectorForName, getOpenMPContextTraitSetForSelector(SelectorForName), | 
|  | AllowsTraitScore, RequiresProperty); | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) | 
|  | << getOpenMPContextTraitSetName( | 
|  | getOpenMPContextTraitSetForSelector(SelectorForName)) | 
|  | << Name << (RequiresProperty ? "(<property-name>)" : ""); | 
|  | return; | 
|  | } | 
|  | for (const auto &PotentialSet : | 
|  | {TraitSet::construct, TraitSet::user, TraitSet::implementation, | 
|  | TraitSet::device, TraitSet::target_device}) { | 
|  | TraitProperty PropertyForName = getOpenMPContextTraitPropertyKind( | 
|  | PotentialSet, TraitSelector::invalid, Name); | 
|  | if (PropertyForName == TraitProperty::invalid) | 
|  | continue; | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a) | 
|  | << Name << CONTEXT_TRAIT_LVL << CONTEXT_SELECTOR_SET_LVL; | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_try) | 
|  | << getOpenMPContextTraitSetName( | 
|  | getOpenMPContextTraitSetForProperty(PropertyForName)) | 
|  | << getOpenMPContextTraitSelectorName( | 
|  | getOpenMPContextTraitSelectorForProperty(PropertyForName)) | 
|  | << ("(" + Name + ")").str(); | 
|  | return; | 
|  | } | 
|  | Diag(NameLoc, diag::note_omp_declare_variant_ctx_options) | 
|  | << CONTEXT_SELECTOR_SET_LVL << listOpenMPContextTraitSets(); | 
|  | } | 
|  |  | 
|  | void Parser::parseOMPContextSelectorSet( | 
|  | OMPTraitSet &TISet, llvm::StringMap<SourceLocation> &SeenSets) { | 
|  | auto OuterBC = BraceCount; | 
|  |  | 
|  | // If anything went wrong we issue an error or warning and then skip the rest | 
|  | // of the set. However, commas are ambiguous so we look for the nesting | 
|  | // of braces here as well. | 
|  | auto FinishSelectorSet = [this, OuterBC]() -> void { | 
|  | bool Done = false; | 
|  | while (!Done) { | 
|  | while (!SkipUntil({tok::comma, tok::r_brace, tok::r_paren, | 
|  | tok::annot_pragma_openmp_end}, | 
|  | StopBeforeMatch)) | 
|  | ; | 
|  | if (Tok.is(tok::r_brace) && OuterBC > BraceCount) | 
|  | (void)ConsumeBrace(); | 
|  | if (OuterBC <= BraceCount) { | 
|  | Done = true; | 
|  | break; | 
|  | } | 
|  | if (!Tok.is(tok::comma) && !Tok.is(tok::r_brace)) { | 
|  | Done = true; | 
|  | break; | 
|  | } | 
|  | (void)ConsumeAnyToken(); | 
|  | } | 
|  | Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here) | 
|  | << CONTEXT_SELECTOR_SET_LVL; | 
|  | }; | 
|  |  | 
|  | parseOMPTraitSetKind(TISet, SeenSets); | 
|  | if (TISet.Kind == TraitSet::invalid) | 
|  | return FinishSelectorSet(); | 
|  |  | 
|  | // Parse '='. | 
|  | if (!TryConsumeToken(tok::equal)) | 
|  | Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected) | 
|  | << "=" | 
|  | << ("context set name \"" + getOpenMPContextTraitSetName(TISet.Kind) + | 
|  | "\"") | 
|  | .str(); | 
|  |  | 
|  | // Parse '{'. | 
|  | if (Tok.is(tok::l_brace)) { | 
|  | (void)ConsumeBrace(); | 
|  | } else { | 
|  | Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected) | 
|  | << "{" | 
|  | << ("'=' that follows the context set name \"" + | 
|  | getOpenMPContextTraitSetName(TISet.Kind) + "\"") | 
|  | .str(); | 
|  | } | 
|  |  | 
|  | llvm::StringMap<SourceLocation> SeenSelectors; | 
|  | do { | 
|  | OMPTraitSelector TISelector; | 
|  | parseOMPContextSelector(TISelector, TISet.Kind, SeenSelectors); | 
|  | if (TISelector.Kind != TraitSelector::invalid && | 
|  | !TISelector.Properties.empty()) | 
|  | TISet.Selectors.push_back(TISelector); | 
|  | } while (TryConsumeToken(tok::comma)); | 
|  |  | 
|  | // Parse '}'. | 
|  | if (Tok.is(tok::r_brace)) { | 
|  | (void)ConsumeBrace(); | 
|  | } else { | 
|  | Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected) | 
|  | << "}" | 
|  | << ("context selectors for the context set \"" + | 
|  | getOpenMPContextTraitSetName(TISet.Kind) + "\"") | 
|  | .str(); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool Parser::parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo &TI) { | 
|  | llvm::StringMap<SourceLocation> SeenSets; | 
|  | do { | 
|  | OMPTraitSet TISet; | 
|  | parseOMPContextSelectorSet(TISet, SeenSets); | 
|  | if (TISet.Kind != TraitSet::invalid && !TISet.Selectors.empty()) | 
|  | TI.Sets.push_back(TISet); | 
|  | } while (TryConsumeToken(tok::comma)); | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, | 
|  | CachedTokens &Toks, | 
|  | SourceLocation Loc) { | 
|  | unsigned OMPVersion = Actions.getLangOpts().OpenMP; | 
|  | PP.EnterToken(Tok, /*IsReinject*/ true); | 
|  | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | 
|  | /*IsReinject*/ true); | 
|  | // Consume the previously pushed token. | 
|  | ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); | 
|  | ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); | 
|  |  | 
|  | FNContextRAII FnContext(*this, Ptr); | 
|  | // Parse function declaration id. | 
|  | SourceLocation RLoc; | 
|  | // Parse with IsAddressOfOperand set to true to parse methods as DeclRefExprs | 
|  | // instead of MemberExprs. | 
|  | ExprResult AssociatedFunction; | 
|  | { | 
|  | // Do not mark function as is used to prevent its emission if this is the | 
|  | // only place where it is used. | 
|  | EnterExpressionEvaluationContext Unevaluated( | 
|  | Actions, Sema::ExpressionEvaluationContext::Unevaluated); | 
|  | AssociatedFunction = ParseOpenMPParensExpr( | 
|  | getOpenMPDirectiveName(OMPD_declare_variant, OMPVersion), RLoc, | 
|  | /*IsAddressOfOperand=*/true); | 
|  | } | 
|  | if (!AssociatedFunction.isUsable()) { | 
|  | if (!Tok.is(tok::annot_pragma_openmp_end)) | 
|  | while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) | 
|  | ; | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | (void)ConsumeAnnotationToken(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | OMPTraitInfo *ParentTI = | 
|  | Actions.OpenMP().getOMPTraitInfoForSurroundingScope(); | 
|  | ASTContext &ASTCtx = Actions.getASTContext(); | 
|  | OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo(); | 
|  | SmallVector<Expr *, 6> AdjustNothing; | 
|  | SmallVector<Expr *, 6> AdjustNeedDevicePtr; | 
|  | SmallVector<Expr *, 6> AdjustNeedDeviceAddr; | 
|  | SmallVector<OMPInteropInfo, 3> AppendArgs; | 
|  | SourceLocation AdjustArgsLoc, AppendArgsLoc; | 
|  |  | 
|  | // At least one clause is required. | 
|  | if (Tok.is(tok::annot_pragma_openmp_end)) { | 
|  | Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause) | 
|  | << (getLangOpts().OpenMP < 51 ? 0 : 1); | 
|  | } | 
|  |  | 
|  | bool IsError = false; | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | OpenMPClauseKind CKind = Tok.isAnnotation() | 
|  | ? OMPC_unknown | 
|  | : getOpenMPClauseKind(PP.getSpelling(Tok)); | 
|  | if (!isAllowedClauseForDirective(OMPD_declare_variant, CKind, | 
|  | getLangOpts().OpenMP)) { | 
|  | Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause) | 
|  | << (getLangOpts().OpenMP < 51 ? 0 : 1); | 
|  | IsError = true; | 
|  | } | 
|  | if (!IsError) { | 
|  | switch (CKind) { | 
|  | case OMPC_match: | 
|  | IsError = parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI); | 
|  | break; | 
|  | case OMPC_adjust_args: { | 
|  | AdjustArgsLoc = Tok.getLocation(); | 
|  | ConsumeToken(); | 
|  | SemaOpenMP::OpenMPVarListDataTy Data; | 
|  | SmallVector<Expr *> Vars; | 
|  | IsError = ParseOpenMPVarList(OMPD_declare_variant, OMPC_adjust_args, | 
|  | Vars, Data); | 
|  | if (!IsError) { | 
|  | switch (Data.ExtraModifier) { | 
|  | case OMPC_ADJUST_ARGS_nothing: | 
|  | llvm::append_range(AdjustNothing, Vars); | 
|  | break; | 
|  | case OMPC_ADJUST_ARGS_need_device_ptr: | 
|  | llvm::append_range(AdjustNeedDevicePtr, Vars); | 
|  | break; | 
|  | case OMPC_ADJUST_ARGS_need_device_addr: | 
|  | llvm::append_range(AdjustNeedDeviceAddr, Vars); | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("Unexpected 'adjust_args' clause modifier."); | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | case OMPC_append_args: | 
|  | if (!AppendArgs.empty()) { | 
|  | Diag(AppendArgsLoc, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(OMPD_declare_variant, OMPVersion) | 
|  | << getOpenMPClauseName(CKind) << 0; | 
|  | IsError = true; | 
|  | } | 
|  | if (!IsError) { | 
|  | AppendArgsLoc = Tok.getLocation(); | 
|  | ConsumeToken(); | 
|  | IsError = parseOpenMPAppendArgs(AppendArgs); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("Unexpected clause for declare variant."); | 
|  | } | 
|  | } | 
|  | if (IsError) { | 
|  | while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) | 
|  | ; | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | (void)ConsumeAnnotationToken(); | 
|  | return; | 
|  | } | 
|  | // Skip ',' if any. | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | } | 
|  |  | 
|  | std::optional<std::pair<FunctionDecl *, Expr *>> DeclVarData = | 
|  | Actions.OpenMP().checkOpenMPDeclareVariantFunction( | 
|  | Ptr, AssociatedFunction.get(), TI, AppendArgs.size(), | 
|  | SourceRange(Loc, Tok.getLocation())); | 
|  |  | 
|  | if (DeclVarData && !TI.Sets.empty()) | 
|  | Actions.OpenMP().ActOnOpenMPDeclareVariantDirective( | 
|  | DeclVarData->first, DeclVarData->second, TI, AdjustNothing, | 
|  | AdjustNeedDevicePtr, AdjustNeedDeviceAddr, AppendArgs, AdjustArgsLoc, | 
|  | AppendArgsLoc, SourceRange(Loc, Tok.getLocation())); | 
|  |  | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | (void)ConsumeAnnotationToken(); | 
|  | } | 
|  |  | 
|  | bool Parser::parseOpenMPAppendArgs( | 
|  | SmallVectorImpl<OMPInteropInfo> &InteropInfos) { | 
|  | bool HasError = false; | 
|  | // Parse '('. | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, | 
|  | getOpenMPClauseName(OMPC_append_args).data())) | 
|  | return true; | 
|  |  | 
|  | // Parse the list of append-ops, each is; | 
|  | // interop(interop-type[,interop-type]...) | 
|  | while (Tok.is(tok::identifier) && Tok.getIdentifierInfo()->isStr("interop")) { | 
|  | ConsumeToken(); | 
|  | BalancedDelimiterTracker IT(*this, tok::l_paren, | 
|  | tok::annot_pragma_openmp_end); | 
|  | if (IT.expectAndConsume(diag::err_expected_lparen_after, "interop")) | 
|  | return true; | 
|  |  | 
|  | OMPInteropInfo InteropInfo; | 
|  | if (ParseOMPInteropInfo(InteropInfo, OMPC_append_args)) | 
|  | HasError = true; | 
|  | else | 
|  | InteropInfos.push_back(InteropInfo); | 
|  |  | 
|  | IT.consumeClose(); | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | } | 
|  | if (!HasError && InteropInfos.empty()) { | 
|  | HasError = true; | 
|  | Diag(Tok.getLocation(), diag::err_omp_unexpected_append_op); | 
|  | SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | } | 
|  | HasError = T.consumeClose() || HasError; | 
|  | return HasError; | 
|  | } | 
|  |  | 
|  | bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc, | 
|  | OMPTraitInfo &TI, | 
|  | OMPTraitInfo *ParentTI) { | 
|  | // Parse 'match'. | 
|  | OpenMPClauseKind CKind = Tok.isAnnotation() | 
|  | ? OMPC_unknown | 
|  | : getOpenMPClauseKind(PP.getSpelling(Tok)); | 
|  | if (CKind != OMPC_match) { | 
|  | Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause) | 
|  | << (getLangOpts().OpenMP < 51 ? 0 : 1); | 
|  | return true; | 
|  | } | 
|  | (void)ConsumeToken(); | 
|  | // Parse '('. | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, | 
|  | getOpenMPClauseName(OMPC_match).data())) | 
|  | return true; | 
|  |  | 
|  | // Parse inner context selectors. | 
|  | parseOMPContextSelectors(Loc, TI); | 
|  |  | 
|  | // Parse ')' | 
|  | (void)T.consumeClose(); | 
|  |  | 
|  | if (!ParentTI) | 
|  | return false; | 
|  |  | 
|  | // Merge the parent/outer trait info into the one we just parsed and diagnose | 
|  | // problems. | 
|  | // TODO: Keep some source location in the TI to provide better diagnostics. | 
|  | // TODO: Perform some kind of equivalence check on the condition and score | 
|  | //       expressions. | 
|  | for (const OMPTraitSet &ParentSet : ParentTI->Sets) { | 
|  | bool MergedSet = false; | 
|  | for (OMPTraitSet &Set : TI.Sets) { | 
|  | if (Set.Kind != ParentSet.Kind) | 
|  | continue; | 
|  | MergedSet = true; | 
|  | for (const OMPTraitSelector &ParentSelector : ParentSet.Selectors) { | 
|  | bool MergedSelector = false; | 
|  | for (OMPTraitSelector &Selector : Set.Selectors) { | 
|  | if (Selector.Kind != ParentSelector.Kind) | 
|  | continue; | 
|  | MergedSelector = true; | 
|  | for (const OMPTraitProperty &ParentProperty : | 
|  | ParentSelector.Properties) { | 
|  | bool MergedProperty = false; | 
|  | for (OMPTraitProperty &Property : Selector.Properties) { | 
|  | // Ignore "equivalent" properties. | 
|  | if (Property.Kind != ParentProperty.Kind) | 
|  | continue; | 
|  |  | 
|  | // If the kind is the same but the raw string not, we don't want | 
|  | // to skip out on the property. | 
|  | MergedProperty |= Property.RawString == ParentProperty.RawString; | 
|  |  | 
|  | if (Property.RawString == ParentProperty.RawString && | 
|  | Selector.ScoreOrCondition == ParentSelector.ScoreOrCondition) | 
|  | continue; | 
|  |  | 
|  | if (Selector.Kind == llvm::omp::TraitSelector::user_condition) { | 
|  | Diag(Loc, diag::err_omp_declare_variant_nested_user_condition); | 
|  | } else if (Selector.ScoreOrCondition != | 
|  | ParentSelector.ScoreOrCondition) { | 
|  | Diag(Loc, diag::err_omp_declare_variant_duplicate_nested_trait) | 
|  | << getOpenMPContextTraitPropertyName( | 
|  | ParentProperty.Kind, ParentProperty.RawString) | 
|  | << getOpenMPContextTraitSelectorName(ParentSelector.Kind) | 
|  | << getOpenMPContextTraitSetName(ParentSet.Kind); | 
|  | } | 
|  | } | 
|  | if (!MergedProperty) | 
|  | Selector.Properties.push_back(ParentProperty); | 
|  | } | 
|  | } | 
|  | if (!MergedSelector) | 
|  | Set.Selectors.push_back(ParentSelector); | 
|  | } | 
|  | } | 
|  | if (!MergedSet) | 
|  | TI.Sets.push_back(ParentSet); | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void Parser::ParseOpenMPClauses(OpenMPDirectiveKind DKind, | 
|  | SmallVectorImpl<OMPClause *> &Clauses, | 
|  | SourceLocation Loc) { | 
|  | std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses; | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | OpenMPClauseKind CKind = Tok.isAnnotation() | 
|  | ? OMPC_unknown | 
|  | : getOpenMPClauseKind(PP.getSpelling(Tok)); | 
|  | Actions.OpenMP().StartOpenMPClause(CKind); | 
|  | OMPClause *Clause = | 
|  | ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]); | 
|  | SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | SeenClauses[unsigned(CKind)] = true; | 
|  | if (Clause != nullptr) | 
|  | Clauses.push_back(Clause); | 
|  | if (Tok.is(tok::annot_pragma_openmp_end)) { | 
|  | Actions.OpenMP().EndOpenMPClause(); | 
|  | break; | 
|  | } | 
|  | // Skip ',' if any. | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | Actions.OpenMP().EndOpenMPClause(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void Parser::ParseOpenMPAssumesDirective(OpenMPDirectiveKind DKind, | 
|  | SourceLocation Loc) { | 
|  | SmallVector<std::string, 4> Assumptions; | 
|  | bool SkippedClauses = false; | 
|  |  | 
|  | auto SkipBraces = [&](llvm::StringRef Spelling, bool IssueNote) { | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, | 
|  | tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, Spelling.data())) | 
|  | return; | 
|  | T.skipToEnd(); | 
|  | if (IssueNote && T.getCloseLocation().isValid()) | 
|  | Diag(T.getCloseLocation(), | 
|  | diag::note_omp_assumption_clause_continue_here); | 
|  | }; | 
|  |  | 
|  | /// Helper to determine which AssumptionClauseMapping (ACM) in the | 
|  | /// AssumptionClauseMappings table matches \p RawString. The return value is | 
|  | /// the index of the matching ACM into the table or -1 if there was no match. | 
|  | auto MatchACMClause = [&](StringRef RawString) { | 
|  | llvm::StringSwitch<int> SS(RawString); | 
|  | unsigned ACMIdx = 0; | 
|  | for (const AssumptionClauseMappingInfo &ACMI : AssumptionClauseMappings) { | 
|  | if (ACMI.StartsWith) | 
|  | SS.StartsWith(ACMI.Identifier, ACMIdx++); | 
|  | else | 
|  | SS.Case(ACMI.Identifier, ACMIdx++); | 
|  | } | 
|  | return SS.Default(-1); | 
|  | }; | 
|  |  | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | IdentifierInfo *II = nullptr; | 
|  | SourceLocation StartLoc = Tok.getLocation(); | 
|  | int Idx = -1; | 
|  | if (Tok.isAnyIdentifier()) { | 
|  | II = Tok.getIdentifierInfo(); | 
|  | Idx = MatchACMClause(II->getName()); | 
|  | } | 
|  | ConsumeAnyToken(); | 
|  |  | 
|  | bool NextIsLPar = Tok.is(tok::l_paren); | 
|  | // Handle unknown clauses by skipping them. | 
|  | if (Idx == -1) { | 
|  | unsigned OMPVersion = Actions.getLangOpts().OpenMP; | 
|  | Diag(StartLoc, diag::warn_omp_unknown_assumption_clause_missing_id) | 
|  | << llvm::omp::getOpenMPDirectiveName(DKind, OMPVersion) | 
|  | << llvm::omp::getAllAssumeClauseOptions() << NextIsLPar; | 
|  | if (NextIsLPar) | 
|  | SkipBraces(II ? II->getName() : "", /* IssueNote */ true); | 
|  | SkippedClauses = true; | 
|  | continue; | 
|  | } | 
|  | const AssumptionClauseMappingInfo &ACMI = AssumptionClauseMappings[Idx]; | 
|  | if (ACMI.HasDirectiveList || ACMI.HasExpression) { | 
|  | // TODO: We ignore absent, contains, and holds assumptions for now. We | 
|  | //       also do not verify the content in the parenthesis at all. | 
|  | SkippedClauses = true; | 
|  | SkipBraces(II->getName(), /* IssueNote */ false); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (NextIsLPar) { | 
|  | Diag(Tok.getLocation(), | 
|  | diag::warn_omp_unknown_assumption_clause_without_args) | 
|  | << II; | 
|  | SkipBraces(II->getName(), /* IssueNote */ true); | 
|  | } | 
|  |  | 
|  | assert(II && "Expected an identifier clause!"); | 
|  | std::string Assumption = II->getName().str(); | 
|  | if (ACMI.StartsWith) | 
|  | Assumption = "ompx_" + Assumption.substr(ACMI.Identifier.size()); | 
|  | else | 
|  | Assumption = "omp_" + Assumption; | 
|  | Assumptions.push_back(Assumption); | 
|  | } | 
|  |  | 
|  | Actions.OpenMP().ActOnOpenMPAssumesDirective(Loc, DKind, Assumptions, | 
|  | SkippedClauses); | 
|  | } | 
|  |  | 
|  | void Parser::ParseOpenMPEndAssumesDirective(SourceLocation Loc) { | 
|  | if (Actions.OpenMP().isInOpenMPAssumeScope()) | 
|  | Actions.OpenMP().ActOnOpenMPEndAssumesDirective(); | 
|  | else | 
|  | Diag(Loc, diag::err_expected_begin_assumes); | 
|  | } | 
|  |  | 
|  | /// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. | 
|  | /// | 
|  | ///    default-clause: | 
|  | ///         'default' '(' 'none' | 'shared'  | 'private' | 'firstprivate' ') | 
|  | /// | 
|  | ///    proc_bind-clause: | 
|  | ///         'proc_bind' '(' 'master' | 'close' | 'spread' ') | 
|  | /// | 
|  | ///    device_type-clause: | 
|  | ///         'device_type' '(' 'host' | 'nohost' | 'any' )' | 
|  | namespace { | 
|  | struct SimpleClauseData { | 
|  | unsigned Type; | 
|  | SourceLocation Loc; | 
|  | SourceLocation LOpen; | 
|  | SourceLocation TypeLoc; | 
|  | SourceLocation RLoc; | 
|  | SimpleClauseData(unsigned Type, SourceLocation Loc, SourceLocation LOpen, | 
|  | SourceLocation TypeLoc, SourceLocation RLoc) | 
|  | : Type(Type), Loc(Loc), LOpen(LOpen), TypeLoc(TypeLoc), RLoc(RLoc) {} | 
|  | }; | 
|  | } // anonymous namespace | 
|  |  | 
|  | static std::optional<SimpleClauseData> | 
|  | parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) { | 
|  | const Token &Tok = P.getCurToken(); | 
|  | SourceLocation Loc = Tok.getLocation(); | 
|  | SourceLocation LOpen = P.ConsumeToken(); | 
|  | // Parse '('. | 
|  | BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, | 
|  | getOpenMPClauseName(Kind).data())) | 
|  | return std::nullopt; | 
|  |  | 
|  | unsigned Type = getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : P.getPreprocessor().getSpelling(Tok), | 
|  | P.getLangOpts()); | 
|  | SourceLocation TypeLoc = Tok.getLocation(); | 
|  | if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && | 
|  | Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | P.ConsumeAnyToken(); | 
|  |  | 
|  | // Parse ')'. | 
|  | SourceLocation RLoc = Tok.getLocation(); | 
|  | if (!T.consumeClose()) | 
|  | RLoc = T.getCloseLocation(); | 
|  |  | 
|  | return SimpleClauseData(Type, Loc, LOpen, TypeLoc, RLoc); | 
|  | } | 
|  |  | 
|  | void Parser::ParseOMPDeclareTargetClauses( | 
|  | SemaOpenMP::DeclareTargetContextInfo &DTCI) { | 
|  | SourceLocation DeviceTypeLoc; | 
|  | bool RequiresToOrLinkOrIndirectClause = false; | 
|  | bool HasToOrLinkOrIndirectClause = false; | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | OMPDeclareTargetDeclAttr::MapTypeTy MT = OMPDeclareTargetDeclAttr::MT_To; | 
|  | bool HasIdentifier = Tok.is(tok::identifier); | 
|  | if (HasIdentifier) { | 
|  | // If we see any clause we need a to or link clause. | 
|  | RequiresToOrLinkOrIndirectClause = true; | 
|  | IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | StringRef ClauseName = II->getName(); | 
|  | bool IsDeviceTypeClause = | 
|  | getLangOpts().OpenMP >= 50 && | 
|  | getOpenMPClauseKind(ClauseName) == OMPC_device_type; | 
|  |  | 
|  | bool IsIndirectClause = getLangOpts().OpenMP >= 51 && | 
|  | getOpenMPClauseKind(ClauseName) == OMPC_indirect; | 
|  | if (DTCI.Indirect && IsIndirectClause) { | 
|  | unsigned OMPVersion = Actions.getLangOpts().OpenMP; | 
|  | Diag(Tok, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(OMPD_declare_target, OMPVersion) | 
|  | << getOpenMPClauseName(OMPC_indirect) << 0; | 
|  | break; | 
|  | } | 
|  | bool IsToEnterOrLinkClause = | 
|  | OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT); | 
|  | assert((!IsDeviceTypeClause || !IsToEnterOrLinkClause) && | 
|  | "Cannot be both!"); | 
|  |  | 
|  | // Starting with OpenMP 5.2 the `to` clause has been replaced by the | 
|  | // `enter` clause. | 
|  | if (getLangOpts().OpenMP >= 52 && ClauseName == "to") { | 
|  | Diag(Tok, diag::err_omp_declare_target_unexpected_to_clause); | 
|  | break; | 
|  | } | 
|  | if (getLangOpts().OpenMP <= 51 && ClauseName == "enter") { | 
|  | Diag(Tok, diag::err_omp_declare_target_unexpected_enter_clause); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (!IsDeviceTypeClause && !IsIndirectClause && | 
|  | DTCI.Kind == OMPD_begin_declare_target) { | 
|  | Diag(Tok, diag::err_omp_declare_target_unexpected_clause) | 
|  | << ClauseName << (getLangOpts().OpenMP >= 51 ? 3 : 0); | 
|  | break; | 
|  | } | 
|  | if (!IsDeviceTypeClause && !IsToEnterOrLinkClause && !IsIndirectClause) { | 
|  | Diag(Tok, getLangOpts().OpenMP >= 52 | 
|  | ? diag::err_omp_declare_target_unexpected_clause_52 | 
|  | : diag::err_omp_declare_target_unexpected_clause) | 
|  | << ClauseName | 
|  | << (getLangOpts().OpenMP >= 51 | 
|  | ? 4 | 
|  | : getLangOpts().OpenMP >= 50 ? 2 : 1); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (IsToEnterOrLinkClause || IsIndirectClause) | 
|  | HasToOrLinkOrIndirectClause = true; | 
|  |  | 
|  | if (IsIndirectClause) { | 
|  | if (!ParseOpenMPIndirectClause(DTCI, /*ParseOnly*/ false)) | 
|  | break; | 
|  | continue; | 
|  | } | 
|  | // Parse 'device_type' clause and go to next clause if any. | 
|  | if (IsDeviceTypeClause) { | 
|  | std::optional<SimpleClauseData> DevTypeData = | 
|  | parseOpenMPSimpleClause(*this, OMPC_device_type); | 
|  | if (DevTypeData) { | 
|  | if (DeviceTypeLoc.isValid()) { | 
|  | // We already saw another device_type clause, diagnose it. | 
|  | Diag(DevTypeData->Loc, | 
|  | diag::warn_omp_more_one_device_type_clause); | 
|  | break; | 
|  | } | 
|  | switch (static_cast<OpenMPDeviceType>(DevTypeData->Type)) { | 
|  | case OMPC_DEVICE_TYPE_any: | 
|  | DTCI.DT = OMPDeclareTargetDeclAttr::DT_Any; | 
|  | break; | 
|  | case OMPC_DEVICE_TYPE_host: | 
|  | DTCI.DT = OMPDeclareTargetDeclAttr::DT_Host; | 
|  | break; | 
|  | case OMPC_DEVICE_TYPE_nohost: | 
|  | DTCI.DT = OMPDeclareTargetDeclAttr::DT_NoHost; | 
|  | break; | 
|  | case OMPC_DEVICE_TYPE_unknown: | 
|  | llvm_unreachable("Unexpected device_type"); | 
|  | } | 
|  | DeviceTypeLoc = DevTypeData->Loc; | 
|  | } | 
|  | continue; | 
|  | } | 
|  | ConsumeToken(); | 
|  | } | 
|  |  | 
|  | if (DTCI.Kind == OMPD_declare_target || HasIdentifier) { | 
|  | auto &&Callback = [this, MT, &DTCI](CXXScopeSpec &SS, | 
|  | DeclarationNameInfo NameInfo) { | 
|  | NamedDecl *ND = Actions.OpenMP().lookupOpenMPDeclareTargetName( | 
|  | getCurScope(), SS, NameInfo); | 
|  | if (!ND) | 
|  | return; | 
|  | SemaOpenMP::DeclareTargetContextInfo::MapInfo MI{MT, NameInfo.getLoc()}; | 
|  | bool FirstMapping = DTCI.ExplicitlyMapped.try_emplace(ND, MI).second; | 
|  | if (!FirstMapping) | 
|  | Diag(NameInfo.getLoc(), diag::err_omp_declare_target_multiple) | 
|  | << NameInfo.getName(); | 
|  | }; | 
|  | if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback, | 
|  | /*AllowScopeSpecifier=*/true)) | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (Tok.is(tok::l_paren)) { | 
|  | Diag(Tok, | 
|  | diag::err_omp_begin_declare_target_unexpected_implicit_to_clause); | 
|  | break; | 
|  | } | 
|  | if (!HasIdentifier && Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | Diag(Tok, | 
|  | getLangOpts().OpenMP >= 52 | 
|  | ? diag::err_omp_declare_target_wrong_clause_after_implicit_enter | 
|  | : diag::err_omp_declare_target_wrong_clause_after_implicit_to); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Consume optional ','. | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | } | 
|  |  | 
|  | if (DTCI.Indirect && DTCI.DT != OMPDeclareTargetDeclAttr::DT_Any) | 
|  | Diag(DeviceTypeLoc, diag::err_omp_declare_target_indirect_device_type); | 
|  |  | 
|  | // For declare target require at least 'to' or 'link' to be present. | 
|  | if (DTCI.Kind == OMPD_declare_target && RequiresToOrLinkOrIndirectClause && | 
|  | !HasToOrLinkOrIndirectClause) | 
|  | Diag(DTCI.Loc, | 
|  | getLangOpts().OpenMP >= 52 | 
|  | ? diag::err_omp_declare_target_missing_enter_or_link_clause | 
|  | : diag::err_omp_declare_target_missing_to_or_link_clause) | 
|  | << (getLangOpts().OpenMP >= 51 ? 1 : 0); | 
|  |  | 
|  | SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); | 
|  | } | 
|  |  | 
|  | void Parser::skipUntilPragmaOpenMPEnd(OpenMPDirectiveKind DKind) { | 
|  | // The last seen token is annot_pragma_openmp_end - need to check for | 
|  | // extra tokens. | 
|  | if (Tok.is(tok::annot_pragma_openmp_end)) | 
|  | return; | 
|  |  | 
|  | unsigned OMPVersion = Actions.getLangOpts().OpenMP; | 
|  | Diag(Tok, diag::warn_omp_extra_tokens_at_eol) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion); | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | } | 
|  |  | 
|  | void Parser::parseOMPEndDirective(OpenMPDirectiveKind BeginKind, | 
|  | OpenMPDirectiveKind ExpectedKind, | 
|  | OpenMPDirectiveKind FoundKind, | 
|  | SourceLocation BeginLoc, | 
|  | SourceLocation FoundLoc, | 
|  | bool SkipUntilOpenMPEnd) { | 
|  | int DiagSelection = ExpectedKind == OMPD_end_declare_target ? 0 : 1; | 
|  |  | 
|  | if (FoundKind == ExpectedKind) { | 
|  | ConsumeAnyToken(); | 
|  | skipUntilPragmaOpenMPEnd(ExpectedKind); | 
|  | return; | 
|  | } | 
|  |  | 
|  | unsigned OMPVersion = Actions.getLangOpts().OpenMP; | 
|  | Diag(FoundLoc, diag::err_expected_end_declare_target_or_variant) | 
|  | << DiagSelection; | 
|  | Diag(BeginLoc, diag::note_matching) | 
|  | << ("'#pragma omp " + getOpenMPDirectiveName(BeginKind, OMPVersion) + "'") | 
|  | .str(); | 
|  | if (SkipUntilOpenMPEnd) | 
|  | SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); | 
|  | } | 
|  |  | 
|  | void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind BeginDKind, | 
|  | OpenMPDirectiveKind EndDKind, | 
|  | SourceLocation DKLoc) { | 
|  | parseOMPEndDirective(BeginDKind, OMPD_end_declare_target, EndDKind, DKLoc, | 
|  | Tok.getLocation(), | 
|  | /* SkipUntilOpenMPEnd */ false); | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | if (Tok.is(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnnotationToken(); | 
|  | } | 
|  |  | 
|  | Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( | 
|  | AccessSpecifier &AS, ParsedAttributes &Attrs, bool Delayed, | 
|  | DeclSpec::TST TagType, Decl *Tag) { | 
|  | assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) && | 
|  | "Not an OpenMP directive!"); | 
|  | ParsingOpenMPDirectiveRAII DirScope(*this); | 
|  | ParenBraceBracketBalancer BalancerRAIIObj(*this); | 
|  | unsigned OMPVersion = Actions.getLangOpts().OpenMP; | 
|  |  | 
|  | SourceLocation Loc; | 
|  | OpenMPDirectiveKind DKind; | 
|  | if (Delayed) { | 
|  | TentativeParsingAction TPA(*this); | 
|  | Loc = ConsumeAnnotationToken(); | 
|  | DKind = parseOpenMPDirectiveKind(*this); | 
|  | if (DKind == OMPD_declare_reduction || DKind == OMPD_declare_mapper) { | 
|  | // Need to delay parsing until completion of the parent class. | 
|  | TPA.Revert(); | 
|  | CachedTokens Toks; | 
|  | unsigned Cnt = 1; | 
|  | Toks.push_back(Tok); | 
|  | while (Cnt && Tok.isNot(tok::eof)) { | 
|  | (void)ConsumeAnyToken(); | 
|  | if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp)) | 
|  | ++Cnt; | 
|  | else if (Tok.is(tok::annot_pragma_openmp_end)) | 
|  | --Cnt; | 
|  | Toks.push_back(Tok); | 
|  | } | 
|  | // Skip last annot_pragma_openmp_end. | 
|  | if (Cnt == 0) | 
|  | (void)ConsumeAnyToken(); | 
|  | auto *LP = new LateParsedPragma(this, AS); | 
|  | LP->takeToks(Toks); | 
|  | getCurrentClass().LateParsedDeclarations.push_back(LP); | 
|  | return nullptr; | 
|  | } | 
|  | TPA.Commit(); | 
|  | } else { | 
|  | Loc = ConsumeAnnotationToken(); | 
|  | DKind = parseOpenMPDirectiveKind(*this); | 
|  | } | 
|  |  | 
|  | switch (DKind) { | 
|  | case OMPD_threadprivate: { | 
|  | ConsumeToken(); | 
|  | DeclDirectiveListParserHelper Helper(this, DKind); | 
|  | if (!ParseOpenMPSimpleVarList(DKind, Helper, | 
|  | /*AllowScopeSpecifier=*/true)) { | 
|  | skipUntilPragmaOpenMPEnd(DKind); | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | ConsumeAnnotationToken(); | 
|  | return Actions.OpenMP().ActOnOpenMPThreadprivateDirective( | 
|  | Loc, Helper.getIdentifiers()); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case OMPD_allocate: { | 
|  | ConsumeToken(); | 
|  | DeclDirectiveListParserHelper Helper(this, DKind); | 
|  | if (!ParseOpenMPSimpleVarList(DKind, Helper, | 
|  | /*AllowScopeSpecifier=*/true)) { | 
|  | SmallVector<OMPClause *, 1> Clauses; | 
|  | if (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses; | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | OpenMPClauseKind CKind = | 
|  | Tok.isAnnotation() ? OMPC_unknown | 
|  | : getOpenMPClauseKind(PP.getSpelling(Tok)); | 
|  | Actions.OpenMP().StartOpenMPClause(CKind); | 
|  | OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind, | 
|  | !SeenClauses[unsigned(CKind)]); | 
|  | SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | SeenClauses[unsigned(CKind)] = true; | 
|  | if (Clause != nullptr) | 
|  | Clauses.push_back(Clause); | 
|  | if (Tok.is(tok::annot_pragma_openmp_end)) { | 
|  | Actions.OpenMP().EndOpenMPClause(); | 
|  | break; | 
|  | } | 
|  | // Skip ',' if any. | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | Actions.OpenMP().EndOpenMPClause(); | 
|  | } | 
|  | skipUntilPragmaOpenMPEnd(DKind); | 
|  | } | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | ConsumeAnnotationToken(); | 
|  | return Actions.OpenMP().ActOnOpenMPAllocateDirective( | 
|  | Loc, Helper.getIdentifiers(), Clauses); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case OMPD_requires: { | 
|  | SourceLocation StartLoc = ConsumeToken(); | 
|  | SmallVector<OMPClause *, 5> Clauses; | 
|  | llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1); | 
|  | if (Tok.is(tok::annot_pragma_openmp_end)) { | 
|  | Diag(Tok, diag::err_omp_expected_clause) | 
|  | << getOpenMPDirectiveName(OMPD_requires, OMPVersion); | 
|  | break; | 
|  | } | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | OpenMPClauseKind CKind = Tok.isAnnotation() | 
|  | ? OMPC_unknown | 
|  | : getOpenMPClauseKind(PP.getSpelling(Tok)); | 
|  | Actions.OpenMP().StartOpenMPClause(CKind); | 
|  | OMPClause *Clause = ParseOpenMPClause(OMPD_requires, CKind, | 
|  | !SeenClauses[unsigned(CKind)]); | 
|  | SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | SeenClauses[unsigned(CKind)] = true; | 
|  | if (Clause != nullptr) | 
|  | Clauses.push_back(Clause); | 
|  | if (Tok.is(tok::annot_pragma_openmp_end)) { | 
|  | Actions.OpenMP().EndOpenMPClause(); | 
|  | break; | 
|  | } | 
|  | // Skip ',' if any. | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | Actions.OpenMP().EndOpenMPClause(); | 
|  | } | 
|  | // Consume final annot_pragma_openmp_end | 
|  | if (Clauses.empty()) { | 
|  | Diag(Tok, diag::err_omp_expected_clause) | 
|  | << getOpenMPDirectiveName(OMPD_requires, OMPVersion); | 
|  | ConsumeAnnotationToken(); | 
|  | return nullptr; | 
|  | } | 
|  | ConsumeAnnotationToken(); | 
|  | return Actions.OpenMP().ActOnOpenMPRequiresDirective(StartLoc, Clauses); | 
|  | } | 
|  | case OMPD_error: { | 
|  | SmallVector<OMPClause *, 1> Clauses; | 
|  | SourceLocation StartLoc = ConsumeToken(); | 
|  | ParseOpenMPClauses(DKind, Clauses, StartLoc); | 
|  | Actions.OpenMP().ActOnOpenMPErrorDirective(Clauses, StartLoc, | 
|  | SourceLocation(), | 
|  | /*InExContext = */ false); | 
|  | break; | 
|  | } | 
|  | case OMPD_assumes: | 
|  | case OMPD_begin_assumes: | 
|  | ParseOpenMPAssumesDirective(DKind, ConsumeToken()); | 
|  | break; | 
|  | case OMPD_end_assumes: | 
|  | ParseOpenMPEndAssumesDirective(ConsumeToken()); | 
|  | break; | 
|  | case OMPD_declare_reduction: | 
|  | ConsumeToken(); | 
|  | if (DeclGroupPtrTy Res = ParseOpenMPDeclareReductionDirective(AS)) { | 
|  | skipUntilPragmaOpenMPEnd(OMPD_declare_reduction); | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | ConsumeAnnotationToken(); | 
|  | return Res; | 
|  | } | 
|  | break; | 
|  | case OMPD_declare_mapper: { | 
|  | ConsumeToken(); | 
|  | if (DeclGroupPtrTy Res = ParseOpenMPDeclareMapperDirective(AS)) { | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | ConsumeAnnotationToken(); | 
|  | return Res; | 
|  | } | 
|  | break; | 
|  | } | 
|  | case OMPD_begin_declare_variant: { | 
|  | ConsumeToken(); | 
|  | if (!ParseOpenMPDeclareBeginVariantDirective(Loc)) { | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | if (!isEofOrEom()) | 
|  | ConsumeAnnotationToken(); | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  | case OMPD_end_declare_variant: { | 
|  | ConsumeToken(); | 
|  | if (Actions.OpenMP().isInOpenMPDeclareVariantScope()) | 
|  | Actions.OpenMP().ActOnOpenMPEndDeclareVariant(); | 
|  | else | 
|  | Diag(Loc, diag::err_expected_begin_declare_variant); | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | ConsumeAnnotationToken(); | 
|  | return nullptr; | 
|  | } | 
|  | case OMPD_declare_variant: | 
|  | case OMPD_declare_simd: { | 
|  | // The syntax is: | 
|  | // { #pragma omp declare {simd|variant} } | 
|  | // <function-declaration-or-definition> | 
|  | // | 
|  | CachedTokens Toks; | 
|  | Toks.push_back(Tok); | 
|  | ConsumeToken(); | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | Toks.push_back(Tok); | 
|  | ConsumeAnyToken(); | 
|  | } | 
|  | Toks.push_back(Tok); | 
|  | ConsumeAnyToken(); | 
|  |  | 
|  | DeclGroupPtrTy Ptr; | 
|  | if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp)) { | 
|  | Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, Delayed, | 
|  | TagType, Tag); | 
|  | } else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) { | 
|  | // Here we expect to see some function declaration. | 
|  | if (AS == AS_none) { | 
|  | assert(TagType == DeclSpec::TST_unspecified); | 
|  | ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); | 
|  | MaybeParseCXX11Attributes(Attrs); | 
|  | ParsingDeclSpec PDS(*this); | 
|  | Ptr = ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs, &PDS); | 
|  | } else { | 
|  | Ptr = | 
|  | ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag); | 
|  | } | 
|  | } | 
|  | if (!Ptr) { | 
|  | Diag(Loc, diag::err_omp_decl_in_declare_simd_variant) | 
|  | << (DKind == OMPD_declare_simd ? 0 : 1); | 
|  | return DeclGroupPtrTy(); | 
|  | } | 
|  | if (DKind == OMPD_declare_simd) | 
|  | return ParseOMPDeclareSimdClauses(Ptr, Toks, Loc); | 
|  | assert(DKind == OMPD_declare_variant && | 
|  | "Expected declare variant directive only"); | 
|  | ParseOMPDeclareVariantClauses(Ptr, Toks, Loc); | 
|  | return Ptr; | 
|  | } | 
|  | case OMPD_begin_declare_target: | 
|  | case OMPD_declare_target: { | 
|  | SourceLocation DTLoc = ConsumeAnyToken(); | 
|  | bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end); | 
|  | SemaOpenMP::DeclareTargetContextInfo DTCI(DKind, DTLoc); | 
|  | if (DKind == OMPD_declare_target && !HasClauses && | 
|  | getLangOpts().OpenMP >= 52) | 
|  | Diag(DTLoc, diag::warn_omp_deprecated_declare_target_delimited_form); | 
|  | if (HasClauses) | 
|  | ParseOMPDeclareTargetClauses(DTCI); | 
|  | bool HasImplicitMappings = DKind == OMPD_begin_declare_target || | 
|  | !HasClauses || | 
|  | (DTCI.ExplicitlyMapped.empty() && DTCI.Indirect); | 
|  |  | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | ConsumeAnyToken(); | 
|  |  | 
|  | if (HasImplicitMappings) { | 
|  | Actions.OpenMP().ActOnStartOpenMPDeclareTargetContext(DTCI); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | Actions.OpenMP().ActOnFinishedOpenMPDeclareTargetContext(DTCI); | 
|  | llvm::SmallVector<Decl *, 4> Decls; | 
|  | for (auto &It : DTCI.ExplicitlyMapped) | 
|  | Decls.push_back(It.first); | 
|  | return Actions.BuildDeclaratorGroup(Decls); | 
|  | } | 
|  | case OMPD_end_declare_target: { | 
|  | if (!Actions.OpenMP().isInOpenMPDeclareTargetContext()) { | 
|  | Diag(Tok, diag::err_omp_unexpected_directive) | 
|  | << 1 << getOpenMPDirectiveName(DKind, OMPVersion); | 
|  | break; | 
|  | } | 
|  | const SemaOpenMP::DeclareTargetContextInfo &DTCI = | 
|  | Actions.OpenMP().ActOnOpenMPEndDeclareTargetDirective(); | 
|  | ParseOMPEndDeclareTargetDirective(DTCI.Kind, DKind, DTCI.Loc); | 
|  | return nullptr; | 
|  | } | 
|  | case OMPD_assume: { | 
|  | Diag(Tok, diag::err_omp_unexpected_directive) | 
|  | << 1 << getOpenMPDirectiveName(DKind, OMPVersion); | 
|  | break; | 
|  | } | 
|  | case OMPD_unknown: | 
|  | Diag(Tok, diag::err_omp_unknown_directive); | 
|  | break; | 
|  | default: | 
|  | switch (getDirectiveCategory(DKind)) { | 
|  | case Category::Executable: | 
|  | case Category::Meta: | 
|  | case Category::Subsidiary: | 
|  | case Category::Utility: | 
|  | Diag(Tok, diag::err_omp_unexpected_directive) | 
|  | << 1 << getOpenMPDirectiveName(DKind, OMPVersion); | 
|  | break; | 
|  | case Category::Declarative: | 
|  | case Category::Informational: | 
|  | break; | 
|  | } | 
|  | } | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | ConsumeAnyToken(); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | StmtResult Parser::ParseOpenMPExecutableDirective( | 
|  | ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc, | 
|  | bool ReadDirectiveWithinMetadirective) { | 
|  | assert(isOpenMPExecutableDirective(DKind) && "Unexpected directive category"); | 
|  | unsigned OMPVersion = Actions.getLangOpts().OpenMP; | 
|  |  | 
|  | bool HasAssociatedStatement = true; | 
|  | Association Assoc = getDirectiveAssociation(DKind); | 
|  |  | 
|  | // OMPD_ordered has None as association, but it comes in two variants, | 
|  | // the second of which is associated with a block. | 
|  | // OMPD_scan and OMPD_section are both "separating", but section is treated | 
|  | // as if it was associated with a statement, while scan is not. | 
|  | if (DKind != OMPD_ordered && DKind != OMPD_section && | 
|  | (Assoc == Association::None || Assoc == Association::Separating)) { | 
|  | if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == | 
|  | ParsedStmtContext()) { | 
|  | Diag(Tok, diag::err_omp_immediate_directive) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) << 0; | 
|  | if (DKind == OMPD_error) { | 
|  | SkipUntil(tok::annot_pragma_openmp_end); | 
|  | return StmtError(); | 
|  | } | 
|  | } | 
|  | HasAssociatedStatement = false; | 
|  | } | 
|  |  | 
|  | SourceLocation EndLoc; | 
|  | SmallVector<OMPClause *, 5> Clauses; | 
|  | llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1); | 
|  | DeclarationNameInfo DirName; | 
|  | OpenMPDirectiveKind CancelRegion = OMPD_unknown; | 
|  | unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | | 
|  | Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; | 
|  |  | 
|  | // Special processing for flush and depobj clauses. | 
|  | Token ImplicitTok; | 
|  | bool ImplicitClauseAllowed = false; | 
|  | if (DKind == OMPD_flush || DKind == OMPD_depobj) { | 
|  | ImplicitTok = Tok; | 
|  | ImplicitClauseAllowed = true; | 
|  | } | 
|  | ConsumeToken(); | 
|  | // Parse directive name of the 'critical' directive if any. | 
|  | if (DKind == OMPD_critical) { | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, | 
|  | tok::annot_pragma_openmp_end); | 
|  | if (!T.consumeOpen()) { | 
|  | if (Tok.isAnyIdentifier()) { | 
|  | DirName = | 
|  | DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation()); | 
|  | ConsumeAnyToken(); | 
|  | } else { | 
|  | Diag(Tok, diag::err_omp_expected_identifier_for_critical); | 
|  | } | 
|  | T.consumeClose(); | 
|  | } | 
|  | } else if (DKind == OMPD_cancellation_point || DKind == OMPD_cancel) { | 
|  | CancelRegion = parseOpenMPDirectiveKind(*this); | 
|  | if (Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | } | 
|  |  | 
|  | if (isOpenMPLoopDirective(DKind)) | 
|  | ScopeFlags |= Scope::OpenMPLoopDirectiveScope; | 
|  | if (isOpenMPSimdDirective(DKind)) | 
|  | ScopeFlags |= Scope::OpenMPSimdDirectiveScope; | 
|  | ParseScope OMPDirectiveScope(this, ScopeFlags); | 
|  | Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), | 
|  | Loc); | 
|  |  | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | // If we are parsing for a directive within a metadirective, the directive | 
|  | // ends with a ')'. | 
|  | if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) { | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | break; | 
|  | } | 
|  | bool HasImplicitClause = false; | 
|  | if (ImplicitClauseAllowed && Tok.is(tok::l_paren)) { | 
|  | HasImplicitClause = true; | 
|  | // Push copy of the current token back to stream to properly parse | 
|  | // pseudo-clause OMPFlushClause or OMPDepobjClause. | 
|  | PP.EnterToken(Tok, /*IsReinject*/ true); | 
|  | PP.EnterToken(ImplicitTok, /*IsReinject*/ true); | 
|  | ConsumeAnyToken(); | 
|  | } | 
|  | OpenMPClauseKind CKind = Tok.isAnnotation() | 
|  | ? OMPC_unknown | 
|  | : getOpenMPClauseKind(PP.getSpelling(Tok)); | 
|  | if (HasImplicitClause) { | 
|  | assert(CKind == OMPC_unknown && "Must be unknown implicit clause."); | 
|  | if (DKind == OMPD_flush) { | 
|  | CKind = OMPC_flush; | 
|  | } else { | 
|  | assert(DKind == OMPD_depobj && "Expected flush or depobj directives."); | 
|  | CKind = OMPC_depobj; | 
|  | } | 
|  | } | 
|  | // No more implicit clauses allowed. | 
|  | ImplicitClauseAllowed = false; | 
|  | Actions.OpenMP().StartOpenMPClause(CKind); | 
|  | HasImplicitClause = false; | 
|  | OMPClause *Clause = | 
|  | ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]); | 
|  | SeenClauses[unsigned(CKind)] = true; | 
|  | if (Clause) | 
|  | Clauses.push_back(Clause); | 
|  |  | 
|  | // Skip ',' if any. | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | Actions.OpenMP().EndOpenMPClause(); | 
|  | } | 
|  | // End location of the directive. | 
|  | EndLoc = Tok.getLocation(); | 
|  | // Consume final annot_pragma_openmp_end. | 
|  | ConsumeAnnotationToken(); | 
|  |  | 
|  | if (DKind == OMPD_ordered) { | 
|  | // If the depend or doacross clause is specified, the ordered construct | 
|  | // is a stand-alone directive. | 
|  | for (auto CK : {OMPC_depend, OMPC_doacross}) { | 
|  | if (SeenClauses[unsigned(CK)]) { | 
|  | if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == | 
|  | ParsedStmtContext()) { | 
|  | Diag(Loc, diag::err_omp_immediate_directive) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) << 1 | 
|  | << getOpenMPClauseName(CK); | 
|  | } | 
|  | HasAssociatedStatement = false; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if ((DKind == OMPD_tile || DKind == OMPD_stripe) && | 
|  | !SeenClauses[unsigned(OMPC_sizes)]) { | 
|  | Diag(Loc, diag::err_omp_required_clause) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) << "sizes"; | 
|  | } | 
|  |  | 
|  | StmtResult AssociatedStmt; | 
|  | if (HasAssociatedStatement) { | 
|  | // The body is a block scope like in Lambdas and Blocks. | 
|  | Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope()); | 
|  | // FIXME: We create a bogus CompoundStmt scope to hold the contents of | 
|  | // the captured region. Code elsewhere assumes that any FunctionScopeInfo | 
|  | // should have at least one compound statement scope within it. | 
|  | ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false); | 
|  | { | 
|  | Sema::CompoundScopeRAII Scope(Actions); | 
|  | AssociatedStmt = ParseStatement(); | 
|  |  | 
|  | if (AssociatedStmt.isUsable() && isOpenMPLoopDirective(DKind) && | 
|  | getLangOpts().OpenMPIRBuilder) | 
|  | AssociatedStmt = | 
|  | Actions.OpenMP().ActOnOpenMPLoopnest(AssociatedStmt.get()); | 
|  | } | 
|  | AssociatedStmt = | 
|  | Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); | 
|  | } else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data || | 
|  | DKind == OMPD_target_exit_data) { | 
|  | Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope()); | 
|  | AssociatedStmt = (Sema::CompoundScopeRAII(Actions), | 
|  | Actions.ActOnCompoundStmt(Loc, Loc, {}, | 
|  | /*isStmtExpr=*/false)); | 
|  | AssociatedStmt = | 
|  | Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); | 
|  | } | 
|  |  | 
|  | StmtResult Directive = Actions.OpenMP().ActOnOpenMPExecutableDirective( | 
|  | DKind, DirName, CancelRegion, Clauses, AssociatedStmt.get(), Loc, EndLoc); | 
|  |  | 
|  | // Exit scope. | 
|  | Actions.OpenMP().EndOpenMPDSABlock(Directive.get()); | 
|  | OMPDirectiveScope.Exit(); | 
|  |  | 
|  | return Directive; | 
|  | } | 
|  |  | 
|  | StmtResult Parser::ParseOpenMPInformationalDirective( | 
|  | ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc, | 
|  | bool ReadDirectiveWithinMetadirective) { | 
|  | assert(isOpenMPInformationalDirective(DKind) && | 
|  | "Unexpected directive category"); | 
|  |  | 
|  | bool HasAssociatedStatement = true; | 
|  |  | 
|  | SmallVector<OMPClause *, 5> Clauses; | 
|  | llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1); | 
|  | DeclarationNameInfo DirName; | 
|  | unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | | 
|  | Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; | 
|  | ParseScope OMPDirectiveScope(this, ScopeFlags); | 
|  |  | 
|  | Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), | 
|  | Loc); | 
|  |  | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) { | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | break; | 
|  | } | 
|  |  | 
|  | OpenMPClauseKind CKind = Tok.isAnnotation() | 
|  | ? OMPC_unknown | 
|  | : getOpenMPClauseKind(PP.getSpelling(Tok)); | 
|  | Actions.OpenMP().StartOpenMPClause(CKind); | 
|  | OMPClause *Clause = | 
|  | ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]); | 
|  | SeenClauses[unsigned(CKind)] = true; | 
|  | if (Clause) | 
|  | Clauses.push_back(Clause); | 
|  |  | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | Actions.OpenMP().EndOpenMPClause(); | 
|  | } | 
|  |  | 
|  | SourceLocation EndLoc = Tok.getLocation(); | 
|  | ConsumeAnnotationToken(); | 
|  |  | 
|  | StmtResult AssociatedStmt; | 
|  | if (HasAssociatedStatement) { | 
|  | Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope()); | 
|  | ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false); | 
|  | { | 
|  | Sema::CompoundScopeRAII Scope(Actions); | 
|  | AssociatedStmt = ParseStatement(); | 
|  | } | 
|  | AssociatedStmt = | 
|  | Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); | 
|  | } | 
|  |  | 
|  | StmtResult Directive = Actions.OpenMP().ActOnOpenMPInformationalDirective( | 
|  | DKind, DirName, Clauses, AssociatedStmt.get(), Loc, EndLoc); | 
|  |  | 
|  | Actions.OpenMP().EndOpenMPDSABlock(Directive.get()); | 
|  | OMPDirectiveScope.Exit(); | 
|  |  | 
|  | return Directive; | 
|  | } | 
|  |  | 
|  | StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( | 
|  | ParsedStmtContext StmtCtx, bool ReadDirectiveWithinMetadirective) { | 
|  | if (!ReadDirectiveWithinMetadirective) | 
|  | assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) && | 
|  | "Not an OpenMP directive!"); | 
|  | ParsingOpenMPDirectiveRAII DirScope(*this); | 
|  | ParenBraceBracketBalancer BalancerRAIIObj(*this); | 
|  | SourceLocation Loc = ReadDirectiveWithinMetadirective | 
|  | ? Tok.getLocation() | 
|  | : ConsumeAnnotationToken(); | 
|  | unsigned OMPVersion = Actions.getLangOpts().OpenMP; | 
|  | OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this); | 
|  | if (ReadDirectiveWithinMetadirective && DKind == OMPD_unknown) { | 
|  | Diag(Tok, diag::err_omp_unknown_directive); | 
|  | return StmtError(); | 
|  | } | 
|  |  | 
|  | StmtResult Directive = StmtError(); | 
|  |  | 
|  | bool IsExecutable = [&]() { | 
|  | if (DKind == OMPD_error) // OMPD_error is handled as executable | 
|  | return true; | 
|  | auto Res = getDirectiveCategory(DKind); | 
|  | return Res == Category::Executable || Res == Category::Subsidiary; | 
|  | }(); | 
|  |  | 
|  | if (IsExecutable) { | 
|  | Directive = ParseOpenMPExecutableDirective( | 
|  | StmtCtx, DKind, Loc, ReadDirectiveWithinMetadirective); | 
|  | assert(!Directive.isUnset() && "Executable directive remained unprocessed"); | 
|  | return Directive; | 
|  | } | 
|  |  | 
|  | switch (DKind) { | 
|  | case OMPD_nothing: | 
|  | ConsumeToken(); | 
|  | // If we are parsing the directive within a metadirective, the directive | 
|  | // ends with a ')'. | 
|  | if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | else | 
|  | skipUntilPragmaOpenMPEnd(DKind); | 
|  | if (Tok.is(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnnotationToken(); | 
|  | // return an empty statement | 
|  | return StmtEmpty(); | 
|  | case OMPD_metadirective: { | 
|  | ConsumeToken(); | 
|  | SmallVector<VariantMatchInfo, 4> VMIs; | 
|  |  | 
|  | // First iteration of parsing all clauses of metadirective. | 
|  | // This iteration only parses and collects all context selector ignoring the | 
|  | // associated directives. | 
|  | TentativeParsingAction TPA(*this); | 
|  | ASTContext &ASTContext = Actions.getASTContext(); | 
|  |  | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, | 
|  | tok::annot_pragma_openmp_end); | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | OpenMPClauseKind CKind = Tok.isAnnotation() | 
|  | ? OMPC_unknown | 
|  | : getOpenMPClauseKind(PP.getSpelling(Tok)); | 
|  | // Check if the clause is unrecognized. | 
|  | if (CKind == OMPC_unknown) { | 
|  | Diag(Tok, diag::err_omp_expected_clause) << "metadirective"; | 
|  | TPA.Revert(); | 
|  | SkipUntil(tok::annot_pragma_openmp_end); | 
|  | return Directive; | 
|  | } | 
|  | if (getLangOpts().OpenMP < 52 && CKind == OMPC_otherwise) | 
|  | Diag(Tok, diag::err_omp_unexpected_clause) | 
|  | << getOpenMPClauseName(CKind) << "metadirective"; | 
|  | if (CKind == OMPC_default && getLangOpts().OpenMP >= 52) | 
|  | Diag(Tok, diag::warn_omp_default_deprecated); | 
|  |  | 
|  | SourceLocation Loc = ConsumeToken(); | 
|  |  | 
|  | // Parse '('. | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, | 
|  | getOpenMPClauseName(CKind).data())) { | 
|  | TPA.Revert(); | 
|  | SkipUntil(tok::annot_pragma_openmp_end); | 
|  | return Directive; | 
|  | } | 
|  |  | 
|  | OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo(); | 
|  | if (CKind == OMPC_when) { | 
|  | // parse and get OMPTraitInfo to pass to the When clause | 
|  | parseOMPContextSelectors(Loc, TI); | 
|  | if (TI.Sets.size() == 0) { | 
|  | Diag(Tok, diag::err_omp_expected_context_selector) << "when clause"; | 
|  | TPA.Commit(); | 
|  | return Directive; | 
|  | } | 
|  |  | 
|  | // Parse ':' | 
|  | if (Tok.is(tok::colon)) | 
|  | ConsumeAnyToken(); | 
|  | else { | 
|  | Diag(Tok, diag::err_omp_expected_colon) << "when clause"; | 
|  | TPA.Commit(); | 
|  | return Directive; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Skip Directive for now. We will parse directive in the second iteration | 
|  | int paren = 0; | 
|  | while (Tok.isNot(tok::r_paren) || paren != 0) { | 
|  | if (Tok.is(tok::l_paren)) | 
|  | paren++; | 
|  | if (Tok.is(tok::r_paren)) | 
|  | paren--; | 
|  | if (Tok.is(tok::annot_pragma_openmp_end)) { | 
|  | Diag(Tok, diag::err_omp_expected_punc) | 
|  | << getOpenMPClauseName(CKind) << 0; | 
|  | TPA.Commit(); | 
|  | return Directive; | 
|  | } | 
|  | ConsumeAnyToken(); | 
|  | } | 
|  | // Parse ')' | 
|  | if (Tok.is(tok::r_paren)) | 
|  | T.consumeClose(); | 
|  |  | 
|  | VariantMatchInfo VMI; | 
|  | TI.getAsVariantMatchInfo(ASTContext, VMI); | 
|  |  | 
|  | VMIs.push_back(VMI); | 
|  | } | 
|  |  | 
|  | TPA.Revert(); | 
|  | // End of the first iteration. Parser is reset to the start of metadirective | 
|  |  | 
|  | std::function<void(StringRef)> DiagUnknownTrait = | 
|  | [this, Loc](StringRef ISATrait) { | 
|  | // TODO Track the selector locations in a way that is accessible here | 
|  | // to improve the diagnostic location. | 
|  | Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) << ISATrait; | 
|  | }; | 
|  | TargetOMPContext OMPCtx(ASTContext, std::move(DiagUnknownTrait), | 
|  | /* CurrentFunctionDecl */ nullptr, | 
|  | ArrayRef<llvm::omp::TraitProperty>(), | 
|  | Actions.OpenMP().getOpenMPDeviceNum()); | 
|  |  | 
|  | // A single match is returned for OpenMP 5.0 | 
|  | int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx); | 
|  |  | 
|  | int Idx = 0; | 
|  | // In OpenMP 5.0 metadirective is either replaced by another directive or | 
|  | // ignored. | 
|  | // TODO: In OpenMP 5.1 generate multiple directives based upon the matches | 
|  | // found by getBestWhenMatchForContext. | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | // OpenMP 5.0 implementation - Skip to the best index found. | 
|  | if (Idx++ != BestIdx) { | 
|  | ConsumeToken();  // Consume clause name | 
|  | T.consumeOpen(); // Consume '(' | 
|  | int paren = 0; | 
|  | // Skip everything inside the clause | 
|  | while (Tok.isNot(tok::r_paren) || paren != 0) { | 
|  | if (Tok.is(tok::l_paren)) | 
|  | paren++; | 
|  | if (Tok.is(tok::r_paren)) | 
|  | paren--; | 
|  | ConsumeAnyToken(); | 
|  | } | 
|  | // Parse ')' | 
|  | if (Tok.is(tok::r_paren)) | 
|  | T.consumeClose(); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | OpenMPClauseKind CKind = Tok.isAnnotation() | 
|  | ? OMPC_unknown | 
|  | : getOpenMPClauseKind(PP.getSpelling(Tok)); | 
|  | SourceLocation Loc = ConsumeToken(); | 
|  |  | 
|  | // Parse '('. | 
|  | T.consumeOpen(); | 
|  |  | 
|  | // Skip ContextSelectors for when clause | 
|  | if (CKind == OMPC_when) { | 
|  | OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo(); | 
|  | // parse and skip the ContextSelectors | 
|  | parseOMPContextSelectors(Loc, TI); | 
|  |  | 
|  | // Parse ':' | 
|  | ConsumeAnyToken(); | 
|  | } | 
|  |  | 
|  | // If no directive is passed, skip in OpenMP 5.0. | 
|  | // TODO: Generate nothing directive from OpenMP 5.1. | 
|  | if (Tok.is(tok::r_paren)) { | 
|  | SkipUntil(tok::annot_pragma_openmp_end); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Parse Directive | 
|  | Directive = ParseOpenMPDeclarativeOrExecutableDirective( | 
|  | StmtCtx, | 
|  | /*ReadDirectiveWithinMetadirective=*/true); | 
|  | break; | 
|  | } | 
|  | // If no match is found and no otherwise clause is present, skip | 
|  | // OMP5.2 Chapter 7.4: If no otherwise clause is specified the effect is as | 
|  | // if one was specified without an associated directive variant. | 
|  | if (BestIdx == -1 && Idx > 0) { | 
|  | assert(Tok.is(tok::annot_pragma_openmp_end) && | 
|  | "Expecting the end of the pragma here"); | 
|  | ConsumeAnnotationToken(); | 
|  | return StmtEmpty(); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case OMPD_threadprivate: { | 
|  | // FIXME: Should this be permitted in C++? | 
|  | if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == | 
|  | ParsedStmtContext()) { | 
|  | Diag(Tok, diag::err_omp_immediate_directive) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) << 0; | 
|  | } | 
|  | ConsumeToken(); | 
|  | DeclDirectiveListParserHelper Helper(this, DKind); | 
|  | if (!ParseOpenMPSimpleVarList(DKind, Helper, | 
|  | /*AllowScopeSpecifier=*/false)) { | 
|  | skipUntilPragmaOpenMPEnd(DKind); | 
|  | DeclGroupPtrTy Res = Actions.OpenMP().ActOnOpenMPThreadprivateDirective( | 
|  | Loc, Helper.getIdentifiers()); | 
|  | Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); | 
|  | } | 
|  | SkipUntil(tok::annot_pragma_openmp_end); | 
|  | break; | 
|  | } | 
|  | case OMPD_allocate: { | 
|  | // FIXME: Should this be permitted in C++? | 
|  | if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == | 
|  | ParsedStmtContext()) { | 
|  | Diag(Tok, diag::err_omp_immediate_directive) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) << 0; | 
|  | } | 
|  | ConsumeToken(); | 
|  | DeclDirectiveListParserHelper Helper(this, DKind); | 
|  | if (!ParseOpenMPSimpleVarList(DKind, Helper, | 
|  | /*AllowScopeSpecifier=*/false)) { | 
|  | SmallVector<OMPClause *, 1> Clauses; | 
|  | if (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1); | 
|  | while (Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | OpenMPClauseKind CKind = | 
|  | Tok.isAnnotation() ? OMPC_unknown | 
|  | : getOpenMPClauseKind(PP.getSpelling(Tok)); | 
|  | Actions.OpenMP().StartOpenMPClause(CKind); | 
|  | OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind, | 
|  | !SeenClauses[unsigned(CKind)]); | 
|  | SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | SeenClauses[unsigned(CKind)] = true; | 
|  | if (Clause != nullptr) | 
|  | Clauses.push_back(Clause); | 
|  | if (Tok.is(tok::annot_pragma_openmp_end)) { | 
|  | Actions.OpenMP().EndOpenMPClause(); | 
|  | break; | 
|  | } | 
|  | // Skip ',' if any. | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | Actions.OpenMP().EndOpenMPClause(); | 
|  | } | 
|  | skipUntilPragmaOpenMPEnd(DKind); | 
|  | } | 
|  | DeclGroupPtrTy Res = Actions.OpenMP().ActOnOpenMPAllocateDirective( | 
|  | Loc, Helper.getIdentifiers(), Clauses); | 
|  | Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); | 
|  | } | 
|  | SkipUntil(tok::annot_pragma_openmp_end); | 
|  | break; | 
|  | } | 
|  | case OMPD_declare_reduction: | 
|  | ConsumeToken(); | 
|  | if (DeclGroupPtrTy Res = | 
|  | ParseOpenMPDeclareReductionDirective(/*AS=*/AS_none)) { | 
|  | skipUntilPragmaOpenMPEnd(OMPD_declare_reduction); | 
|  | ConsumeAnyToken(); | 
|  | Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); | 
|  | } else { | 
|  | SkipUntil(tok::annot_pragma_openmp_end); | 
|  | } | 
|  | break; | 
|  | case OMPD_declare_mapper: { | 
|  | ConsumeToken(); | 
|  | if (DeclGroupPtrTy Res = | 
|  | ParseOpenMPDeclareMapperDirective(/*AS=*/AS_none)) { | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | ConsumeAnnotationToken(); | 
|  | Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); | 
|  | } else { | 
|  | SkipUntil(tok::annot_pragma_openmp_end); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case OMPD_declare_target: { | 
|  | SourceLocation DTLoc = ConsumeAnyToken(); | 
|  | bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end); | 
|  | SemaOpenMP::DeclareTargetContextInfo DTCI(DKind, DTLoc); | 
|  | if (HasClauses) | 
|  | ParseOMPDeclareTargetClauses(DTCI); | 
|  | bool HasImplicitMappings = | 
|  | !HasClauses || (DTCI.ExplicitlyMapped.empty() && DTCI.Indirect); | 
|  |  | 
|  | if (HasImplicitMappings) { | 
|  | Diag(Tok, diag::err_omp_unexpected_directive) | 
|  | << 1 << getOpenMPDirectiveName(DKind, OMPVersion); | 
|  | SkipUntil(tok::annot_pragma_openmp_end); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | ConsumeAnyToken(); | 
|  |  | 
|  | Actions.OpenMP().ActOnFinishedOpenMPDeclareTargetContext(DTCI); | 
|  | break; | 
|  | } | 
|  | case OMPD_begin_declare_variant: { | 
|  | ConsumeToken(); | 
|  | if (!ParseOpenMPDeclareBeginVariantDirective(Loc)) { | 
|  | // Skip the last annot_pragma_openmp_end. | 
|  | if (!isEofOrEom()) | 
|  | ConsumeAnnotationToken(); | 
|  | } | 
|  | return Directive; | 
|  | } | 
|  | case OMPD_end_declare_variant: { | 
|  | ConsumeToken(); | 
|  | if (Actions.OpenMP().isInOpenMPDeclareVariantScope()) | 
|  | Actions.OpenMP().ActOnOpenMPEndDeclareVariant(); | 
|  | else | 
|  | Diag(Loc, diag::err_expected_begin_declare_variant); | 
|  | ConsumeAnnotationToken(); | 
|  | break; | 
|  | } | 
|  | case OMPD_declare_simd: | 
|  | case OMPD_begin_declare_target: | 
|  | case OMPD_end_declare_target: | 
|  | case OMPD_requires: | 
|  | case OMPD_declare_variant: | 
|  | Diag(Tok, diag::err_omp_unexpected_directive) | 
|  | << 1 << getOpenMPDirectiveName(DKind, OMPVersion); | 
|  | SkipUntil(tok::annot_pragma_openmp_end); | 
|  | break; | 
|  | case OMPD_assume: { | 
|  | ConsumeToken(); | 
|  | Directive = ParseOpenMPInformationalDirective( | 
|  | StmtCtx, DKind, Loc, ReadDirectiveWithinMetadirective); | 
|  | assert(!Directive.isUnset() && | 
|  | "Informational directive remains unprocessed"); | 
|  | return Directive; | 
|  | } | 
|  | case OMPD_unknown: | 
|  | default: | 
|  | Diag(Tok, diag::err_omp_unknown_directive); | 
|  | SkipUntil(tok::annot_pragma_openmp_end); | 
|  | break; | 
|  | } | 
|  | return Directive; | 
|  | } | 
|  |  | 
|  | bool Parser::ParseOpenMPSimpleVarList( | 
|  | OpenMPDirectiveKind Kind, | 
|  | const llvm::function_ref<void(CXXScopeSpec &, DeclarationNameInfo)> | 
|  | &Callback, | 
|  | bool AllowScopeSpecifier) { | 
|  | unsigned OMPVersion = Actions.getLangOpts().OpenMP; | 
|  | // Parse '('. | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, | 
|  | getOpenMPDirectiveName(Kind, OMPVersion).data())) | 
|  | return true; | 
|  | bool IsCorrect = true; | 
|  | bool NoIdentIsFound = true; | 
|  |  | 
|  | // Read tokens while ')' or annot_pragma_openmp_end is not found. | 
|  | while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | CXXScopeSpec SS; | 
|  | UnqualifiedId Name; | 
|  | // Read var name. | 
|  | Token PrevTok = Tok; | 
|  | NoIdentIsFound = false; | 
|  |  | 
|  | if (AllowScopeSpecifier && getLangOpts().CPlusPlus && | 
|  | ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, | 
|  | /*ObjectHasErrors=*/false, false)) { | 
|  | IsCorrect = false; | 
|  | SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | } else if (ParseUnqualifiedId(SS, /*ObjectType=*/nullptr, | 
|  | /*ObjectHadErrors=*/false, false, false, | 
|  | false, false, nullptr, Name)) { | 
|  | IsCorrect = false; | 
|  | SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) && | 
|  | Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | IsCorrect = false; | 
|  | SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | Diag(PrevTok.getLocation(), diag::err_expected) | 
|  | << tok::identifier | 
|  | << SourceRange(PrevTok.getLocation(), PrevTokLocation); | 
|  | } else { | 
|  | Callback(SS, Actions.GetNameFromUnqualifiedId(Name)); | 
|  | } | 
|  | // Consume ','. | 
|  | if (Tok.is(tok::comma)) { | 
|  | ConsumeToken(); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (NoIdentIsFound) { | 
|  | Diag(Tok, diag::err_expected) << tok::identifier; | 
|  | IsCorrect = false; | 
|  | } | 
|  |  | 
|  | // Parse ')'. | 
|  | IsCorrect = !T.consumeClose() && IsCorrect; | 
|  |  | 
|  | return !IsCorrect; | 
|  | } | 
|  |  | 
|  | OMPClause *Parser::ParseOpenMPSizesClause() { | 
|  | SourceLocation ClauseNameLoc, OpenLoc, CloseLoc; | 
|  | SmallVector<Expr *, 4> ValExprs; | 
|  | if (ParseOpenMPExprListClause(OMPC_sizes, ClauseNameLoc, OpenLoc, CloseLoc, | 
|  | ValExprs)) | 
|  | return nullptr; | 
|  |  | 
|  | return Actions.OpenMP().ActOnOpenMPSizesClause(ValExprs, ClauseNameLoc, | 
|  | OpenLoc, CloseLoc); | 
|  | } | 
|  |  | 
|  | OMPClause *Parser::ParseOpenMPPermutationClause() { | 
|  | SourceLocation ClauseNameLoc, OpenLoc, CloseLoc; | 
|  | SmallVector<Expr *> ArgExprs; | 
|  | if (ParseOpenMPExprListClause(OMPC_permutation, ClauseNameLoc, OpenLoc, | 
|  | CloseLoc, ArgExprs, | 
|  | /*ReqIntConst=*/true)) | 
|  | return nullptr; | 
|  |  | 
|  | return Actions.OpenMP().ActOnOpenMPPermutationClause(ArgExprs, ClauseNameLoc, | 
|  | OpenLoc, CloseLoc); | 
|  | } | 
|  |  | 
|  | OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) { | 
|  | SourceLocation Loc = Tok.getLocation(); | 
|  | ConsumeAnyToken(); | 
|  |  | 
|  | // Parse '('. | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, "uses_allocator")) | 
|  | return nullptr; | 
|  | SmallVector<SemaOpenMP::UsesAllocatorsData, 4> Data; | 
|  | do { | 
|  | CXXScopeSpec SS; | 
|  | Token Replacement; | 
|  | ExprResult Allocator = | 
|  | getLangOpts().CPlusPlus | 
|  | ? ParseCXXIdExpression() | 
|  | : tryParseCXXIdExpression(SS, /*isAddressOfOperand=*/false, | 
|  | Replacement); | 
|  | if (Allocator.isInvalid()) { | 
|  | SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | break; | 
|  | } | 
|  | SemaOpenMP::UsesAllocatorsData &D = Data.emplace_back(); | 
|  | D.Allocator = Allocator.get(); | 
|  | if (Tok.is(tok::l_paren)) { | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, | 
|  | tok::annot_pragma_openmp_end); | 
|  | T.consumeOpen(); | 
|  | ExprResult AllocatorTraits = | 
|  | getLangOpts().CPlusPlus ? ParseCXXIdExpression() : ParseExpression(); | 
|  | T.consumeClose(); | 
|  | if (AllocatorTraits.isInvalid()) { | 
|  | SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | break; | 
|  | } | 
|  | D.AllocatorTraits = AllocatorTraits.get(); | 
|  | D.LParenLoc = T.getOpenLocation(); | 
|  | D.RParenLoc = T.getCloseLocation(); | 
|  | } | 
|  | if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren)) | 
|  | Diag(Tok, diag::err_omp_expected_punc) << "uses_allocators" << 0; | 
|  | // Parse ',' | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeAnyToken(); | 
|  | } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)); | 
|  | T.consumeClose(); | 
|  | return Actions.OpenMP().ActOnOpenMPUsesAllocatorClause( | 
|  | Loc, T.getOpenLocation(), T.getCloseLocation(), Data); | 
|  | } | 
|  |  | 
|  | OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, | 
|  | OpenMPClauseKind CKind, bool FirstClause) { | 
|  | OMPClauseKind = CKind; | 
|  | OMPClause *Clause = nullptr; | 
|  | bool ErrorFound = false; | 
|  | bool WrongDirective = false; | 
|  | unsigned OMPVersion = Actions.getLangOpts().OpenMP; | 
|  |  | 
|  | // Check if clause is allowed for the given directive. | 
|  | if (CKind != OMPC_unknown && | 
|  | !isAllowedClauseForDirective(DKind, CKind, getLangOpts().OpenMP)) { | 
|  | Diag(Tok, diag::err_omp_unexpected_clause) | 
|  | << getOpenMPClauseName(CKind) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion); | 
|  | ErrorFound = true; | 
|  | WrongDirective = true; | 
|  | } | 
|  |  | 
|  | switch (CKind) { | 
|  | case OMPC_final: | 
|  | case OMPC_num_threads: | 
|  | case OMPC_safelen: | 
|  | case OMPC_simdlen: | 
|  | case OMPC_collapse: | 
|  | case OMPC_ordered: | 
|  | case OMPC_priority: | 
|  | case OMPC_grainsize: | 
|  | case OMPC_num_tasks: | 
|  | case OMPC_hint: | 
|  | case OMPC_allocator: | 
|  | case OMPC_depobj: | 
|  | case OMPC_detach: | 
|  | case OMPC_novariants: | 
|  | case OMPC_nocontext: | 
|  | case OMPC_filter: | 
|  | case OMPC_partial: | 
|  | case OMPC_align: | 
|  | case OMPC_message: | 
|  | case OMPC_ompx_dyn_cgroup_mem: | 
|  | // OpenMP [2.5, Restrictions] | 
|  | //  At most one num_threads clause can appear on the directive. | 
|  | // OpenMP [2.8.1, simd construct, Restrictions] | 
|  | //  Only one safelen  clause can appear on a simd directive. | 
|  | //  Only one simdlen  clause can appear on a simd directive. | 
|  | //  Only one collapse clause can appear on a simd directive. | 
|  | // OpenMP [2.11.1, task Construct, Restrictions] | 
|  | //  At most one if clause can appear on the directive. | 
|  | //  At most one final clause can appear on the directive. | 
|  | // OpenMP [teams Construct, Restrictions] | 
|  | //  At most one num_teams clause can appear on the directive. | 
|  | //  At most one thread_limit clause can appear on the directive. | 
|  | // OpenMP [2.9.1, task Construct, Restrictions] | 
|  | // At most one priority clause can appear on the directive. | 
|  | // OpenMP [2.9.2, taskloop Construct, Restrictions] | 
|  | // At most one grainsize clause can appear on the directive. | 
|  | // OpenMP [2.9.2, taskloop Construct, Restrictions] | 
|  | // At most one num_tasks clause can appear on the directive. | 
|  | // OpenMP [2.11.3, allocate Directive, Restrictions] | 
|  | // At most one allocator clause can appear on the directive. | 
|  | // OpenMP 5.0, 2.10.1 task Construct, Restrictions. | 
|  | // At most one detach clause can appear on the directive. | 
|  | // OpenMP 5.1, 2.3.6 dispatch Construct, Restrictions. | 
|  | // At most one novariants clause can appear on a dispatch directive. | 
|  | // At most one nocontext clause can appear on a dispatch directive. | 
|  | // OpenMP [5.1, error directive, Restrictions] | 
|  | // At most one message clause can appear on the directive | 
|  | if (!FirstClause) { | 
|  | Diag(Tok, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) | 
|  | << getOpenMPClauseName(CKind) << 0; | 
|  | ErrorFound = true; | 
|  | } | 
|  |  | 
|  | if ((CKind == OMPC_ordered || CKind == OMPC_partial) && | 
|  | PP.LookAhead(/*N=*/0).isNot(tok::l_paren)) | 
|  | Clause = ParseOpenMPClause(CKind, WrongDirective); | 
|  | else if (CKind == OMPC_grainsize || CKind == OMPC_num_tasks || | 
|  | CKind == OMPC_num_threads) | 
|  | Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective); | 
|  | else | 
|  | Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective); | 
|  | break; | 
|  | case OMPC_fail: | 
|  | case OMPC_default: | 
|  | case OMPC_proc_bind: | 
|  | case OMPC_atomic_default_mem_order: | 
|  | case OMPC_at: | 
|  | case OMPC_severity: | 
|  | case OMPC_bind: | 
|  | // OpenMP [2.14.3.1, Restrictions] | 
|  | //  Only a single default clause may be specified on a parallel, task or | 
|  | //  teams directive. | 
|  | // OpenMP [2.5, parallel Construct, Restrictions] | 
|  | //  At most one proc_bind clause can appear on the directive. | 
|  | // OpenMP [5.0, Requires directive, Restrictions] | 
|  | //  At most one atomic_default_mem_order clause can appear | 
|  | //  on the directive | 
|  | // OpenMP [5.1, error directive, Restrictions] | 
|  | //  At most one at clause can appear on the directive | 
|  | //  At most one severity clause can appear on the directive | 
|  | // OpenMP 5.1, 2.11.7 loop Construct, Restrictions. | 
|  | // At most one bind clause can appear on a loop directive. | 
|  | if (!FirstClause) { | 
|  | Diag(Tok, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) | 
|  | << getOpenMPClauseName(CKind) << 0; | 
|  | ErrorFound = true; | 
|  | } | 
|  |  | 
|  | Clause = ParseOpenMPSimpleClause(CKind, WrongDirective); | 
|  | break; | 
|  | case OMPC_device: | 
|  | case OMPC_schedule: | 
|  | case OMPC_dist_schedule: | 
|  | case OMPC_defaultmap: | 
|  | case OMPC_order: | 
|  | // OpenMP [2.7.1, Restrictions, p. 3] | 
|  | //  Only one schedule clause can appear on a loop directive. | 
|  | // OpenMP 4.5 [2.10.4, Restrictions, p. 106] | 
|  | //  At most one defaultmap clause can appear on the directive. | 
|  | // OpenMP 5.0 [2.12.5, target construct, Restrictions] | 
|  | //  At most one device clause can appear on the directive. | 
|  | // OpenMP 5.1 [2.11.3, order clause, Restrictions] | 
|  | //  At most one order clause may appear on a construct. | 
|  | if ((getLangOpts().OpenMP < 50 || CKind != OMPC_defaultmap) && | 
|  | (CKind != OMPC_order || getLangOpts().OpenMP >= 51) && !FirstClause) { | 
|  | Diag(Tok, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) | 
|  | << getOpenMPClauseName(CKind) << 0; | 
|  | ErrorFound = true; | 
|  | } | 
|  | [[fallthrough]]; | 
|  | case OMPC_if: | 
|  | Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective); | 
|  | break; | 
|  | case OMPC_holds: | 
|  | Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective); | 
|  | break; | 
|  | case OMPC_nowait: | 
|  | case OMPC_untied: | 
|  | case OMPC_mergeable: | 
|  | case OMPC_read: | 
|  | case OMPC_write: | 
|  | case OMPC_capture: | 
|  | case OMPC_compare: | 
|  | case OMPC_seq_cst: | 
|  | case OMPC_acq_rel: | 
|  | case OMPC_acquire: | 
|  | case OMPC_release: | 
|  | case OMPC_relaxed: | 
|  | case OMPC_weak: | 
|  | case OMPC_threads: | 
|  | case OMPC_simd: | 
|  | case OMPC_nogroup: | 
|  | case OMPC_unified_address: | 
|  | case OMPC_unified_shared_memory: | 
|  | case OMPC_reverse_offload: | 
|  | case OMPC_dynamic_allocators: | 
|  | case OMPC_full: | 
|  | // OpenMP [2.7.1, Restrictions, p. 9] | 
|  | //  Only one ordered clause can appear on a loop directive. | 
|  | // OpenMP [2.7.1, Restrictions, C/C++, p. 4] | 
|  | //  Only one nowait clause can appear on a for directive. | 
|  | // OpenMP [5.0, Requires directive, Restrictions] | 
|  | //   Each of the requires clauses can appear at most once on the directive. | 
|  | if (!FirstClause) { | 
|  | Diag(Tok, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) | 
|  | << getOpenMPClauseName(CKind) << 0; | 
|  | ErrorFound = true; | 
|  | } | 
|  |  | 
|  | Clause = ParseOpenMPClause(CKind, WrongDirective); | 
|  | break; | 
|  | case OMPC_self_maps: | 
|  | // OpenMP [6.0, self_maps clause] | 
|  | if (getLangOpts().OpenMP < 60) { | 
|  | Diag(Tok, diag::err_omp_expected_clause) | 
|  | << getOpenMPDirectiveName(OMPD_requires, OMPVersion); | 
|  | ErrorFound = true; | 
|  | } | 
|  | if (!FirstClause) { | 
|  | Diag(Tok, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) | 
|  | << getOpenMPClauseName(CKind) << 0; | 
|  | ErrorFound = true; | 
|  | } | 
|  | Clause = ParseOpenMPClause(CKind, WrongDirective); | 
|  | break; | 
|  | case OMPC_update: | 
|  | if (!FirstClause) { | 
|  | Diag(Tok, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) | 
|  | << getOpenMPClauseName(CKind) << 0; | 
|  | ErrorFound = true; | 
|  | } | 
|  |  | 
|  | Clause = (DKind == OMPD_depobj) | 
|  | ? ParseOpenMPSimpleClause(CKind, WrongDirective) | 
|  | : ParseOpenMPClause(CKind, WrongDirective); | 
|  | break; | 
|  | case OMPC_num_teams: | 
|  | case OMPC_thread_limit: | 
|  | if (!FirstClause) { | 
|  | Diag(Tok, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) | 
|  | << getOpenMPClauseName(CKind) << 0; | 
|  | ErrorFound = true; | 
|  | } | 
|  | [[fallthrough]]; | 
|  | case OMPC_private: | 
|  | case OMPC_firstprivate: | 
|  | case OMPC_lastprivate: | 
|  | case OMPC_shared: | 
|  | case OMPC_reduction: | 
|  | case OMPC_task_reduction: | 
|  | case OMPC_in_reduction: | 
|  | case OMPC_linear: | 
|  | case OMPC_aligned: | 
|  | case OMPC_copyin: | 
|  | case OMPC_copyprivate: | 
|  | case OMPC_flush: | 
|  | case OMPC_depend: | 
|  | case OMPC_map: | 
|  | case OMPC_to: | 
|  | case OMPC_from: | 
|  | case OMPC_use_device_ptr: | 
|  | case OMPC_use_device_addr: | 
|  | case OMPC_is_device_ptr: | 
|  | case OMPC_has_device_addr: | 
|  | case OMPC_allocate: | 
|  | case OMPC_nontemporal: | 
|  | case OMPC_inclusive: | 
|  | case OMPC_exclusive: | 
|  | case OMPC_affinity: | 
|  | case OMPC_doacross: | 
|  | case OMPC_enter: | 
|  | if (getLangOpts().OpenMP >= 52 && DKind == OMPD_ordered && | 
|  | CKind == OMPC_depend) | 
|  | Diag(Tok, diag::warn_omp_depend_in_ordered_deprecated); | 
|  | Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective); | 
|  | break; | 
|  | case OMPC_sizes: | 
|  | if (!FirstClause) { | 
|  | Diag(Tok, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) | 
|  | << getOpenMPClauseName(CKind) << 0; | 
|  | ErrorFound = true; | 
|  | } | 
|  |  | 
|  | Clause = ParseOpenMPSizesClause(); | 
|  | break; | 
|  | case OMPC_permutation: | 
|  | if (!FirstClause) { | 
|  | Diag(Tok, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) | 
|  | << getOpenMPClauseName(CKind) << 0; | 
|  | ErrorFound = true; | 
|  | } | 
|  | Clause = ParseOpenMPPermutationClause(); | 
|  | break; | 
|  | case OMPC_uses_allocators: | 
|  | Clause = ParseOpenMPUsesAllocatorClause(DKind); | 
|  | break; | 
|  | case OMPC_destroy: | 
|  | if (DKind != OMPD_interop) { | 
|  | if (!FirstClause) { | 
|  | Diag(Tok, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) | 
|  | << getOpenMPClauseName(CKind) << 0; | 
|  | ErrorFound = true; | 
|  | } | 
|  | Clause = ParseOpenMPClause(CKind, WrongDirective); | 
|  | break; | 
|  | } | 
|  | [[fallthrough]]; | 
|  | case OMPC_init: | 
|  | case OMPC_use: | 
|  | Clause = ParseOpenMPInteropClause(CKind, WrongDirective); | 
|  | break; | 
|  | case OMPC_device_type: | 
|  | case OMPC_unknown: | 
|  | skipUntilPragmaOpenMPEnd(DKind); | 
|  | break; | 
|  | case OMPC_threadprivate: | 
|  | case OMPC_uniform: | 
|  | case OMPC_match: | 
|  | if (!WrongDirective) | 
|  | Diag(Tok, diag::err_omp_unexpected_clause) | 
|  | << getOpenMPClauseName(CKind) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion); | 
|  | SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch); | 
|  | break; | 
|  | case OMPC_absent: | 
|  | case OMPC_contains: { | 
|  | SourceLocation Loc = ConsumeToken(); | 
|  | SourceLocation LLoc = Tok.getLocation(); | 
|  | SourceLocation RLoc; | 
|  | llvm::SmallVector<OpenMPDirectiveKind, 4> DKVec; | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren); | 
|  | T.consumeOpen(); | 
|  | do { | 
|  | OpenMPDirectiveKind DK = getOpenMPDirectiveKind(PP.getSpelling(Tok)); | 
|  | if (DK == OMPD_unknown) { | 
|  | skipUntilPragmaOpenMPEnd(OMPD_assume); | 
|  | Diag(Tok, diag::err_omp_unexpected_clause) | 
|  | << getOpenMPClauseName(CKind) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion); | 
|  | break; | 
|  | } | 
|  | if (isOpenMPExecutableDirective(DK)) { | 
|  | DKVec.push_back(DK); | 
|  | ConsumeToken(); | 
|  | } else { | 
|  | Diag(Tok, diag::err_omp_unexpected_clause) | 
|  | << getOpenMPClauseName(CKind) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion); | 
|  | } | 
|  | } while (TryConsumeToken(tok::comma)); | 
|  | RLoc = Tok.getLocation(); | 
|  | T.consumeClose(); | 
|  | Clause = Actions.OpenMP().ActOnOpenMPDirectivePresenceClause( | 
|  | CKind, DKVec, Loc, LLoc, RLoc); | 
|  | break; | 
|  | } | 
|  | case OMPC_no_openmp: | 
|  | case OMPC_no_openmp_routines: | 
|  | case OMPC_no_openmp_constructs: | 
|  | case OMPC_no_parallelism: { | 
|  | if (!FirstClause) { | 
|  | Diag(Tok, diag::err_omp_more_one_clause) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion) | 
|  | << getOpenMPClauseName(CKind) << 0; | 
|  | ErrorFound = true; | 
|  | } | 
|  | SourceLocation Loc = ConsumeToken(); | 
|  | Clause = Actions.OpenMP().ActOnOpenMPNullaryAssumptionClause( | 
|  | CKind, Loc, Tok.getLocation()); | 
|  | break; | 
|  | } | 
|  | case OMPC_ompx_attribute: | 
|  | Clause = ParseOpenMPOMPXAttributesClause(WrongDirective); | 
|  | break; | 
|  | case OMPC_ompx_bare: | 
|  | if (DKind == llvm::omp::Directive::OMPD_target) { | 
|  | // Flang splits the combined directives which requires OMPD_target to be | 
|  | // marked as accepting the `ompx_bare` clause in `OMP.td`. Thus, we need | 
|  | // to explicitly check whether this clause is applied to an `omp target` | 
|  | // without `teams` and emit an error. | 
|  | Diag(Tok, diag::err_omp_unexpected_clause) | 
|  | << getOpenMPClauseName(CKind) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion); | 
|  | ErrorFound = true; | 
|  | WrongDirective = true; | 
|  | } | 
|  | if (WrongDirective) | 
|  | Diag(Tok, diag::note_ompx_bare_clause) | 
|  | << getOpenMPClauseName(CKind) << "target teams"; | 
|  | if (!ErrorFound && !getLangOpts().OpenMPExtensions) { | 
|  | Diag(Tok, diag::err_omp_unexpected_clause_extension_only) | 
|  | << getOpenMPClauseName(CKind) | 
|  | << getOpenMPDirectiveName(DKind, OMPVersion); | 
|  | ErrorFound = true; | 
|  | } | 
|  | Clause = ParseOpenMPClause(CKind, WrongDirective); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | return ErrorFound ? nullptr : Clause; | 
|  | } | 
|  |  | 
|  | /// Parses simple expression in parens for single-expression clauses of OpenMP | 
|  | /// constructs. | 
|  | /// \param RLoc Returned location of right paren. | 
|  | ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName, | 
|  | SourceLocation &RLoc, | 
|  | bool IsAddressOfOperand) { | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, ClauseName.data())) | 
|  | return ExprError(); | 
|  |  | 
|  | SourceLocation ELoc = Tok.getLocation(); | 
|  | ExprResult LHS( | 
|  | ParseCastExpression(CastParseKind::AnyCastExpr, IsAddressOfOperand, | 
|  | TypoCorrectionTypeBehavior::AllowNonTypes)); | 
|  | ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); | 
|  | Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false); | 
|  |  | 
|  | // Parse ')'. | 
|  | RLoc = Tok.getLocation(); | 
|  | if (!T.consumeClose()) | 
|  | RLoc = T.getCloseLocation(); | 
|  |  | 
|  | return Val; | 
|  | } | 
|  |  | 
|  | OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind, | 
|  | bool ParseOnly) { | 
|  | SourceLocation Loc = ConsumeToken(); | 
|  | SourceLocation LLoc = Tok.getLocation(); | 
|  | SourceLocation RLoc; | 
|  |  | 
|  | ExprResult Val = ParseOpenMPParensExpr(getOpenMPClauseName(Kind), RLoc); | 
|  |  | 
|  | if (Val.isInvalid()) | 
|  | return nullptr; | 
|  |  | 
|  | if (ParseOnly) | 
|  | return nullptr; | 
|  | return Actions.OpenMP().ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc, | 
|  | LLoc, RLoc); | 
|  | } | 
|  |  | 
|  | bool Parser::ParseOpenMPIndirectClause( | 
|  | SemaOpenMP::DeclareTargetContextInfo &DTCI, bool ParseOnly) { | 
|  | SourceLocation Loc = ConsumeToken(); | 
|  | SourceLocation RLoc; | 
|  |  | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | if (ParseOnly) | 
|  | return false; | 
|  | DTCI.Indirect = nullptr; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | ExprResult Val = | 
|  | ParseOpenMPParensExpr(getOpenMPClauseName(OMPC_indirect), RLoc); | 
|  | if (Val.isInvalid()) | 
|  | return false; | 
|  |  | 
|  | if (ParseOnly) | 
|  | return false; | 
|  |  | 
|  | if (!Val.get()->isValueDependent() && !Val.get()->isTypeDependent() && | 
|  | !Val.get()->isInstantiationDependent() && | 
|  | !Val.get()->containsUnexpandedParameterPack()) { | 
|  | ExprResult Ret = Actions.CheckBooleanCondition(Loc, Val.get()); | 
|  | if (Ret.isInvalid()) | 
|  | return false; | 
|  | llvm::APSInt Result; | 
|  | Ret = Actions.VerifyIntegerConstantExpression(Val.get(), &Result, | 
|  | AllowFoldKind::Allow); | 
|  | if (Ret.isInvalid()) | 
|  | return false; | 
|  | DTCI.Indirect = Val.get(); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Parser::ParseOMPInteropInfo(OMPInteropInfo &InteropInfo, | 
|  | OpenMPClauseKind Kind) { | 
|  | const Token &Tok = getCurToken(); | 
|  | bool HasError = false; | 
|  | bool IsTarget = false; | 
|  | bool IsTargetSync = false; | 
|  |  | 
|  | while (Tok.is(tok::identifier)) { | 
|  | // Currently prefer_type is only allowed with 'init' and it must be first. | 
|  | bool PreferTypeAllowed = Kind == OMPC_init && | 
|  | InteropInfo.PreferTypes.empty() && !IsTarget && | 
|  | !IsTargetSync; | 
|  | if (Tok.getIdentifierInfo()->isStr("target")) { | 
|  | // OpenMP 5.1 [2.15.1, interop Construct, Restrictions] | 
|  | // Each interop-type may be specified on an action-clause at most | 
|  | // once. | 
|  | if (IsTarget) | 
|  | Diag(Tok, diag::warn_omp_more_one_interop_type) << "target"; | 
|  | IsTarget = true; | 
|  | ConsumeToken(); | 
|  | } else if (Tok.getIdentifierInfo()->isStr("targetsync")) { | 
|  | if (IsTargetSync) | 
|  | Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync"; | 
|  | IsTargetSync = true; | 
|  | ConsumeToken(); | 
|  | } else if (Tok.getIdentifierInfo()->isStr("prefer_type") && | 
|  | PreferTypeAllowed) { | 
|  | ConsumeToken(); | 
|  | BalancedDelimiterTracker PT(*this, tok::l_paren, | 
|  | tok::annot_pragma_openmp_end); | 
|  | if (PT.expectAndConsume(diag::err_expected_lparen_after, "prefer_type")) | 
|  | HasError = true; | 
|  |  | 
|  | while (Tok.isNot(tok::r_paren)) { | 
|  | SourceLocation Loc = Tok.getLocation(); | 
|  | ExprResult LHS = ParseCastExpression(CastParseKind::AnyCastExpr); | 
|  | ExprResult PTExpr = ParseRHSOfBinaryExpression(LHS, prec::Conditional); | 
|  | PTExpr = Actions.ActOnFinishFullExpr(PTExpr.get(), Loc, | 
|  | /*DiscardedValue=*/false); | 
|  | if (PTExpr.isUsable()) { | 
|  | InteropInfo.PreferTypes.push_back(PTExpr.get()); | 
|  | } else { | 
|  | HasError = true; | 
|  | SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | } | 
|  |  | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | } | 
|  | PT.consumeClose(); | 
|  | } else { | 
|  | HasError = true; | 
|  | Diag(Tok, diag::err_omp_expected_interop_type); | 
|  | ConsumeToken(); | 
|  | } | 
|  | if (!Tok.is(tok::comma)) | 
|  | break; | 
|  | ConsumeToken(); | 
|  | } | 
|  |  | 
|  | if (!HasError && !IsTarget && !IsTargetSync) { | 
|  | Diag(Tok, diag::err_omp_expected_interop_type); | 
|  | HasError = true; | 
|  | } | 
|  |  | 
|  | if (Kind == OMPC_init) { | 
|  | if (Tok.isNot(tok::colon) && (IsTarget || IsTargetSync)) | 
|  | Diag(Tok, diag::warn_pragma_expected_colon) << "interop types"; | 
|  | if (Tok.is(tok::colon)) | 
|  | ConsumeToken(); | 
|  | } | 
|  |  | 
|  | // As of OpenMP 5.1,there are two interop-types, "target" and | 
|  | // "targetsync". Either or both are allowed for a single interop. | 
|  | InteropInfo.IsTarget = IsTarget; | 
|  | InteropInfo.IsTargetSync = IsTargetSync; | 
|  |  | 
|  | return HasError; | 
|  | } | 
|  |  | 
|  | OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind, | 
|  | bool ParseOnly) { | 
|  | SourceLocation Loc = ConsumeToken(); | 
|  | // Parse '('. | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, | 
|  | getOpenMPClauseName(Kind).data())) | 
|  | return nullptr; | 
|  |  | 
|  | bool InteropError = false; | 
|  | OMPInteropInfo InteropInfo; | 
|  | if (Kind == OMPC_init) | 
|  | InteropError = ParseOMPInteropInfo(InteropInfo, OMPC_init); | 
|  |  | 
|  | // Parse the variable. | 
|  | SourceLocation VarLoc = Tok.getLocation(); | 
|  | ExprResult InteropVarExpr = ParseAssignmentExpression(); | 
|  | if (!InteropVarExpr.isUsable()) { | 
|  | SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | } | 
|  |  | 
|  | // Parse ')'. | 
|  | SourceLocation RLoc = Tok.getLocation(); | 
|  | if (!T.consumeClose()) | 
|  | RLoc = T.getCloseLocation(); | 
|  |  | 
|  | if (ParseOnly || !InteropVarExpr.isUsable() || InteropError) | 
|  | return nullptr; | 
|  |  | 
|  | if (Kind == OMPC_init) | 
|  | return Actions.OpenMP().ActOnOpenMPInitClause( | 
|  | InteropVarExpr.get(), InteropInfo, Loc, T.getOpenLocation(), VarLoc, | 
|  | RLoc); | 
|  | if (Kind == OMPC_use) | 
|  | return Actions.OpenMP().ActOnOpenMPUseClause( | 
|  | InteropVarExpr.get(), Loc, T.getOpenLocation(), VarLoc, RLoc); | 
|  |  | 
|  | if (Kind == OMPC_destroy) | 
|  | return Actions.OpenMP().ActOnOpenMPDestroyClause( | 
|  | InteropVarExpr.get(), Loc, T.getOpenLocation(), VarLoc, RLoc); | 
|  |  | 
|  | llvm_unreachable("Unexpected interop variable clause."); | 
|  | } | 
|  |  | 
|  | OMPClause *Parser::ParseOpenMPOMPXAttributesClause(bool ParseOnly) { | 
|  | SourceLocation Loc = ConsumeToken(); | 
|  | // Parse '('. | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, | 
|  | getOpenMPClauseName(OMPC_ompx_attribute).data())) | 
|  | return nullptr; | 
|  |  | 
|  | ParsedAttributes ParsedAttrs(AttrFactory); | 
|  | ParseAttributes(PAKM_GNU | PAKM_CXX11, ParsedAttrs); | 
|  |  | 
|  | // Parse ')'. | 
|  | if (T.consumeClose()) | 
|  | return nullptr; | 
|  |  | 
|  | if (ParseOnly) | 
|  | return nullptr; | 
|  |  | 
|  | SmallVector<Attr *> Attrs; | 
|  | for (const ParsedAttr &PA : ParsedAttrs) { | 
|  | switch (PA.getKind()) { | 
|  | case ParsedAttr::AT_AMDGPUFlatWorkGroupSize: | 
|  | if (!PA.checkExactlyNumArgs(Actions, 2)) | 
|  | continue; | 
|  | if (auto *A = Actions.AMDGPU().CreateAMDGPUFlatWorkGroupSizeAttr( | 
|  | PA, PA.getArgAsExpr(0), PA.getArgAsExpr(1))) | 
|  | Attrs.push_back(A); | 
|  | continue; | 
|  | case ParsedAttr::AT_AMDGPUWavesPerEU: | 
|  | if (!PA.checkAtLeastNumArgs(Actions, 1) || | 
|  | !PA.checkAtMostNumArgs(Actions, 2)) | 
|  | continue; | 
|  | if (auto *A = Actions.AMDGPU().CreateAMDGPUWavesPerEUAttr( | 
|  | PA, PA.getArgAsExpr(0), | 
|  | PA.getNumArgs() > 1 ? PA.getArgAsExpr(1) : nullptr)) | 
|  | Attrs.push_back(A); | 
|  | continue; | 
|  | case ParsedAttr::AT_CUDALaunchBounds: | 
|  | if (!PA.checkAtLeastNumArgs(Actions, 1) || | 
|  | !PA.checkAtMostNumArgs(Actions, 2)) | 
|  | continue; | 
|  | if (auto *A = Actions.CreateLaunchBoundsAttr( | 
|  | PA, PA.getArgAsExpr(0), | 
|  | PA.getNumArgs() > 1 ? PA.getArgAsExpr(1) : nullptr, | 
|  | PA.getNumArgs() > 2 ? PA.getArgAsExpr(2) : nullptr)) | 
|  | Attrs.push_back(A); | 
|  | continue; | 
|  | default: | 
|  | Diag(Loc, diag::warn_omp_invalid_attribute_for_ompx_attributes) << PA; | 
|  | continue; | 
|  | }; | 
|  | } | 
|  |  | 
|  | return Actions.OpenMP().ActOnOpenMPXAttributeClause( | 
|  | Attrs, Loc, T.getOpenLocation(), T.getCloseLocation()); | 
|  | } | 
|  |  | 
|  | OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind, | 
|  | bool ParseOnly) { | 
|  | std::optional<SimpleClauseData> Val = parseOpenMPSimpleClause(*this, Kind); | 
|  | if (!Val || ParseOnly) | 
|  | return nullptr; | 
|  | if (getLangOpts().OpenMP < 51 && Kind == OMPC_default && | 
|  | (static_cast<DefaultKind>(Val->Type) == OMP_DEFAULT_private || | 
|  | static_cast<DefaultKind>(Val->Type) == | 
|  | OMP_DEFAULT_firstprivate)) { | 
|  | Diag(Val->LOpen, diag::err_omp_invalid_dsa) | 
|  | << getOpenMPClauseName(static_cast<DefaultKind>(Val->Type) == | 
|  | OMP_DEFAULT_private | 
|  | ? OMPC_private | 
|  | : OMPC_firstprivate) | 
|  | << getOpenMPClauseName(OMPC_default) << "5.1"; | 
|  | return nullptr; | 
|  | } | 
|  | return Actions.OpenMP().ActOnOpenMPSimpleClause( | 
|  | Kind, Val->Type, Val->TypeLoc, Val->LOpen, Val->Loc, Val->RLoc); | 
|  | } | 
|  |  | 
|  | OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind, bool ParseOnly) { | 
|  | SourceLocation Loc = Tok.getLocation(); | 
|  | ConsumeAnyToken(); | 
|  |  | 
|  | if (ParseOnly) | 
|  | return nullptr; | 
|  | return Actions.OpenMP().ActOnOpenMPClause(Kind, Loc, Tok.getLocation()); | 
|  | } | 
|  |  | 
|  | OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, | 
|  | OpenMPClauseKind Kind, | 
|  | bool ParseOnly) { | 
|  | SourceLocation Loc = ConsumeToken(); | 
|  | SourceLocation DelimLoc; | 
|  | // Parse '('. | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, | 
|  | getOpenMPClauseName(Kind).data())) | 
|  | return nullptr; | 
|  |  | 
|  | ExprResult Val; | 
|  | SmallVector<unsigned, 4> Arg; | 
|  | SmallVector<SourceLocation, 4> KLoc; | 
|  | if (Kind == OMPC_schedule) { | 
|  | enum { Modifier1, Modifier2, ScheduleKind, NumberOfElements }; | 
|  | Arg.resize(NumberOfElements); | 
|  | KLoc.resize(NumberOfElements); | 
|  | Arg[Modifier1] = OMPC_SCHEDULE_MODIFIER_unknown; | 
|  | Arg[Modifier2] = OMPC_SCHEDULE_MODIFIER_unknown; | 
|  | Arg[ScheduleKind] = OMPC_SCHEDULE_unknown; | 
|  | unsigned KindModifier = getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); | 
|  | if (KindModifier > OMPC_SCHEDULE_unknown) { | 
|  | // Parse 'modifier' | 
|  | Arg[Modifier1] = KindModifier; | 
|  | KLoc[Modifier1] = Tok.getLocation(); | 
|  | if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && | 
|  | Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | if (Tok.is(tok::comma)) { | 
|  | // Parse ',' 'modifier' | 
|  | ConsumeAnyToken(); | 
|  | KindModifier = getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); | 
|  | Arg[Modifier2] = KindModifier > OMPC_SCHEDULE_unknown | 
|  | ? KindModifier | 
|  | : (unsigned)OMPC_SCHEDULE_unknown; | 
|  | KLoc[Modifier2] = Tok.getLocation(); | 
|  | if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && | 
|  | Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | } | 
|  | // Parse ':' | 
|  | if (Tok.is(tok::colon)) | 
|  | ConsumeAnyToken(); | 
|  | else | 
|  | Diag(Tok, diag::warn_pragma_expected_colon) << "schedule modifier"; | 
|  | KindModifier = getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); | 
|  | } | 
|  | Arg[ScheduleKind] = KindModifier; | 
|  | KLoc[ScheduleKind] = Tok.getLocation(); | 
|  | if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && | 
|  | Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | if ((Arg[ScheduleKind] == OMPC_SCHEDULE_static || | 
|  | Arg[ScheduleKind] == OMPC_SCHEDULE_dynamic || | 
|  | Arg[ScheduleKind] == OMPC_SCHEDULE_guided) && | 
|  | Tok.is(tok::comma)) | 
|  | DelimLoc = ConsumeAnyToken(); | 
|  | } else if (Kind == OMPC_dist_schedule) { | 
|  | Arg.push_back(getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts())); | 
|  | KLoc.push_back(Tok.getLocation()); | 
|  | if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && | 
|  | Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | if (Arg.back() == OMPC_DIST_SCHEDULE_static && Tok.is(tok::comma)) | 
|  | DelimLoc = ConsumeAnyToken(); | 
|  | } else if (Kind == OMPC_defaultmap) { | 
|  | // Get a defaultmap modifier | 
|  | unsigned Modifier = getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); | 
|  |  | 
|  | // Set defaultmap modifier to unknown if it is either scalar, aggregate, or | 
|  | // pointer | 
|  | if (Modifier < OMPC_DEFAULTMAP_MODIFIER_unknown) | 
|  | Modifier = OMPC_DEFAULTMAP_MODIFIER_unknown; | 
|  | Arg.push_back(Modifier); | 
|  | KLoc.push_back(Tok.getLocation()); | 
|  | if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && | 
|  | Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | // Parse ':' | 
|  | if (Tok.is(tok::colon) || getLangOpts().OpenMP < 50) { | 
|  | if (Tok.is(tok::colon)) | 
|  | ConsumeAnyToken(); | 
|  | else if (Arg.back() != OMPC_DEFAULTMAP_MODIFIER_unknown) | 
|  | Diag(Tok, diag::warn_pragma_expected_colon) << "defaultmap modifier"; | 
|  | // Get a defaultmap kind | 
|  | Arg.push_back(getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts())); | 
|  | KLoc.push_back(Tok.getLocation()); | 
|  | if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && | 
|  | Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | } else { | 
|  | Arg.push_back(OMPC_DEFAULTMAP_unknown); | 
|  | KLoc.push_back(SourceLocation()); | 
|  | } | 
|  | } else if (Kind == OMPC_order) { | 
|  | enum { Modifier, OrderKind, NumberOfElements }; | 
|  | Arg.resize(NumberOfElements); | 
|  | KLoc.resize(NumberOfElements); | 
|  | Arg[Modifier] = OMPC_ORDER_MODIFIER_unknown; | 
|  | Arg[OrderKind] = OMPC_ORDER_unknown; | 
|  | unsigned KindModifier = getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); | 
|  | if (KindModifier > OMPC_ORDER_unknown) { | 
|  | // Parse 'modifier' | 
|  | Arg[Modifier] = KindModifier; | 
|  | KLoc[Modifier] = Tok.getLocation(); | 
|  | if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && | 
|  | Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | // Parse ':' | 
|  | if (Tok.is(tok::colon)) | 
|  | ConsumeAnyToken(); | 
|  | else | 
|  | Diag(Tok, diag::warn_pragma_expected_colon) << "order modifier"; | 
|  | KindModifier = getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); | 
|  | } | 
|  | Arg[OrderKind] = KindModifier; | 
|  | KLoc[OrderKind] = Tok.getLocation(); | 
|  | if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && | 
|  | Tok.isNot(tok::annot_pragma_openmp_end)) | 
|  | ConsumeAnyToken(); | 
|  | } else if (Kind == OMPC_device) { | 
|  | // Only target executable directives support extended device construct. | 
|  | if (isOpenMPTargetExecutionDirective(DKind) && getLangOpts().OpenMP >= 50 && | 
|  | NextToken().is(tok::colon)) { | 
|  | // Parse optional <device modifier> ':' | 
|  | Arg.push_back(getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts())); | 
|  | KLoc.push_back(Tok.getLocation()); | 
|  | ConsumeAnyToken(); | 
|  | // Parse ':' | 
|  | ConsumeAnyToken(); | 
|  | } else { | 
|  | Arg.push_back(OMPC_DEVICE_unknown); | 
|  | KLoc.emplace_back(); | 
|  | } | 
|  | } else if (Kind == OMPC_grainsize) { | 
|  | // Parse optional <grainsize modifier> ':' | 
|  | OpenMPGrainsizeClauseModifier Modifier = | 
|  | static_cast<OpenMPGrainsizeClauseModifier>(getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), | 
|  | getLangOpts())); | 
|  | if (getLangOpts().OpenMP >= 51) { | 
|  | if (NextToken().is(tok::colon)) { | 
|  | Arg.push_back(Modifier); | 
|  | KLoc.push_back(Tok.getLocation()); | 
|  | // Parse modifier | 
|  | ConsumeAnyToken(); | 
|  | // Parse ':' | 
|  | ConsumeAnyToken(); | 
|  | } else { | 
|  | if (Modifier == OMPC_GRAINSIZE_strict) { | 
|  | Diag(Tok, diag::err_modifier_expected_colon) << "strict"; | 
|  | // Parse modifier | 
|  | ConsumeAnyToken(); | 
|  | } | 
|  | Arg.push_back(OMPC_GRAINSIZE_unknown); | 
|  | KLoc.emplace_back(); | 
|  | } | 
|  | } else { | 
|  | Arg.push_back(OMPC_GRAINSIZE_unknown); | 
|  | KLoc.emplace_back(); | 
|  | } | 
|  | } else if (Kind == OMPC_num_tasks) { | 
|  | // Parse optional <num_tasks modifier> ':' | 
|  | OpenMPNumTasksClauseModifier Modifier = | 
|  | static_cast<OpenMPNumTasksClauseModifier>(getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), | 
|  | getLangOpts())); | 
|  | if (getLangOpts().OpenMP >= 51) { | 
|  | if (NextToken().is(tok::colon)) { | 
|  | Arg.push_back(Modifier); | 
|  | KLoc.push_back(Tok.getLocation()); | 
|  | // Parse modifier | 
|  | ConsumeAnyToken(); | 
|  | // Parse ':' | 
|  | ConsumeAnyToken(); | 
|  | } else { | 
|  | if (Modifier == OMPC_NUMTASKS_strict) { | 
|  | Diag(Tok, diag::err_modifier_expected_colon) << "strict"; | 
|  | // Parse modifier | 
|  | ConsumeAnyToken(); | 
|  | } | 
|  | Arg.push_back(OMPC_NUMTASKS_unknown); | 
|  | KLoc.emplace_back(); | 
|  | } | 
|  | } else { | 
|  | Arg.push_back(OMPC_NUMTASKS_unknown); | 
|  | KLoc.emplace_back(); | 
|  | } | 
|  | } else if (Kind == OMPC_num_threads) { | 
|  | // Parse optional <num_threads modifier> ':' | 
|  | OpenMPNumThreadsClauseModifier Modifier = | 
|  | static_cast<OpenMPNumThreadsClauseModifier>(getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), | 
|  | getLangOpts())); | 
|  | if (getLangOpts().OpenMP >= 60) { | 
|  | if (NextToken().is(tok::colon)) { | 
|  | Arg.push_back(Modifier); | 
|  | KLoc.push_back(Tok.getLocation()); | 
|  | // Parse modifier | 
|  | ConsumeAnyToken(); | 
|  | // Parse ':' | 
|  | ConsumeAnyToken(); | 
|  | } else { | 
|  | if (Modifier == OMPC_NUMTHREADS_strict) { | 
|  | Diag(Tok, diag::err_modifier_expected_colon) << "strict"; | 
|  | // Parse modifier | 
|  | ConsumeAnyToken(); | 
|  | } | 
|  | Arg.push_back(OMPC_NUMTHREADS_unknown); | 
|  | KLoc.emplace_back(); | 
|  | } | 
|  | } else { | 
|  | Arg.push_back(OMPC_NUMTHREADS_unknown); | 
|  | KLoc.emplace_back(); | 
|  | } | 
|  | } else { | 
|  | assert(Kind == OMPC_if); | 
|  | KLoc.push_back(Tok.getLocation()); | 
|  | TentativeParsingAction TPA(*this); | 
|  | auto DK = parseOpenMPDirectiveKind(*this); | 
|  | Arg.push_back(static_cast<unsigned>(DK)); | 
|  | if (DK != OMPD_unknown) { | 
|  | ConsumeToken(); | 
|  | if (Tok.is(tok::colon) && getLangOpts().OpenMP > 40) { | 
|  | TPA.Commit(); | 
|  | DelimLoc = ConsumeToken(); | 
|  | } else { | 
|  | TPA.Revert(); | 
|  | Arg.back() = unsigned(OMPD_unknown); | 
|  | } | 
|  | } else { | 
|  | TPA.Revert(); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool NeedAnExpression = (Kind == OMPC_schedule && DelimLoc.isValid()) || | 
|  | (Kind == OMPC_dist_schedule && DelimLoc.isValid()) || | 
|  | Kind == OMPC_if || Kind == OMPC_device || | 
|  | Kind == OMPC_grainsize || Kind == OMPC_num_tasks || | 
|  | Kind == OMPC_num_threads; | 
|  | if (NeedAnExpression) { | 
|  | SourceLocation ELoc = Tok.getLocation(); | 
|  | ExprResult LHS( | 
|  | ParseCastExpression(CastParseKind::AnyCastExpr, false, | 
|  | TypoCorrectionTypeBehavior::AllowNonTypes)); | 
|  | Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional); | 
|  | Val = | 
|  | Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false); | 
|  | } | 
|  |  | 
|  | // Parse ')'. | 
|  | SourceLocation RLoc = Tok.getLocation(); | 
|  | if (!T.consumeClose()) | 
|  | RLoc = T.getCloseLocation(); | 
|  |  | 
|  | if (NeedAnExpression && Val.isInvalid()) | 
|  | return nullptr; | 
|  |  | 
|  | if (ParseOnly) | 
|  | return nullptr; | 
|  | return Actions.OpenMP().ActOnOpenMPSingleExprWithArgClause( | 
|  | Kind, Arg, Val.get(), Loc, T.getOpenLocation(), KLoc, DelimLoc, RLoc); | 
|  | } | 
|  |  | 
|  | static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec, | 
|  | UnqualifiedId &ReductionId) { | 
|  | if (ReductionIdScopeSpec.isEmpty()) { | 
|  | auto OOK = OO_None; | 
|  | switch (P.getCurToken().getKind()) { | 
|  | case tok::plus: | 
|  | OOK = OO_Plus; | 
|  | break; | 
|  | case tok::minus: | 
|  | OOK = OO_Minus; | 
|  | break; | 
|  | case tok::star: | 
|  | OOK = OO_Star; | 
|  | break; | 
|  | case tok::amp: | 
|  | OOK = OO_Amp; | 
|  | break; | 
|  | case tok::pipe: | 
|  | OOK = OO_Pipe; | 
|  | break; | 
|  | case tok::caret: | 
|  | OOK = OO_Caret; | 
|  | break; | 
|  | case tok::ampamp: | 
|  | OOK = OO_AmpAmp; | 
|  | break; | 
|  | case tok::pipepipe: | 
|  | OOK = OO_PipePipe; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | if (OOK != OO_None) { | 
|  | SourceLocation OpLoc = P.ConsumeToken(); | 
|  | SourceLocation SymbolLocations[] = {OpLoc, OpLoc, SourceLocation()}; | 
|  | ReductionId.setOperatorFunctionId(OpLoc, OOK, SymbolLocations); | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return P.ParseUnqualifiedId( | 
|  | ReductionIdScopeSpec, /*ObjectType=*/nullptr, | 
|  | /*ObjectHadErrors=*/false, /*EnteringContext*/ false, | 
|  | /*AllowDestructorName*/ false, | 
|  | /*AllowConstructorName*/ false, | 
|  | /*AllowDeductionGuide*/ false, nullptr, ReductionId); | 
|  | } | 
|  |  | 
|  | /// Checks if the token is a valid map-type-modifier. | 
|  | /// FIXME: It will return an OpenMPMapClauseKind if that's what it parses. | 
|  | static OpenMPMapModifierKind isMapModifier(Parser &P) { | 
|  | Token Tok = P.getCurToken(); | 
|  | if (!Tok.is(tok::identifier)) | 
|  | return OMPC_MAP_MODIFIER_unknown; | 
|  |  | 
|  | Preprocessor &PP = P.getPreprocessor(); | 
|  | OpenMPMapModifierKind TypeModifier = | 
|  | static_cast<OpenMPMapModifierKind>(getOpenMPSimpleClauseType( | 
|  | OMPC_map, PP.getSpelling(Tok), P.getLangOpts())); | 
|  | return TypeModifier; | 
|  | } | 
|  |  | 
|  | bool Parser::parseMapperModifier(SemaOpenMP::OpenMPVarListDataTy &Data) { | 
|  | // Parse '('. | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::colon); | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, "mapper")) { | 
|  | SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | return true; | 
|  | } | 
|  | // Parse mapper-identifier | 
|  | if (getLangOpts().CPlusPlus) | 
|  | ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec, | 
|  | /*ObjectType=*/nullptr, | 
|  | /*ObjectHasErrors=*/false, | 
|  | /*EnteringContext=*/false); | 
|  | if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_default)) { | 
|  | Diag(Tok.getLocation(), diag::err_omp_mapper_illegal_identifier); | 
|  | SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | return true; | 
|  | } | 
|  | auto &DeclNames = Actions.getASTContext().DeclarationNames; | 
|  | Data.ReductionOrMapperId = DeclarationNameInfo( | 
|  | DeclNames.getIdentifier(Tok.getIdentifierInfo()), Tok.getLocation()); | 
|  | ConsumeToken(); | 
|  | // Parse ')'. | 
|  | return T.consumeClose(); | 
|  | } | 
|  |  | 
|  | static OpenMPMapClauseKind isMapType(Parser &P); | 
|  |  | 
|  | bool Parser::parseMapTypeModifiers(SemaOpenMP::OpenMPVarListDataTy &Data) { | 
|  | bool HasMapType = false; | 
|  | SourceLocation PreMapLoc = Tok.getLocation(); | 
|  | StringRef PreMapName = ""; | 
|  | while (getCurToken().isNot(tok::colon)) { | 
|  | OpenMPMapModifierKind TypeModifier = isMapModifier(*this); | 
|  | OpenMPMapClauseKind MapKind = isMapType(*this); | 
|  | if (TypeModifier == OMPC_MAP_MODIFIER_always || | 
|  | TypeModifier == OMPC_MAP_MODIFIER_close || | 
|  | TypeModifier == OMPC_MAP_MODIFIER_present || | 
|  | TypeModifier == OMPC_MAP_MODIFIER_ompx_hold) { | 
|  | Data.MapTypeModifiers.push_back(TypeModifier); | 
|  | Data.MapTypeModifiersLoc.push_back(Tok.getLocation()); | 
|  | if (PP.LookAhead(0).isNot(tok::comma) && | 
|  | PP.LookAhead(0).isNot(tok::colon) && getLangOpts().OpenMP >= 52) | 
|  | Diag(Tok.getLocation(), diag::err_omp_missing_comma) | 
|  | << "map type modifier"; | 
|  | ConsumeToken(); | 
|  | } else if (TypeModifier == OMPC_MAP_MODIFIER_mapper) { | 
|  | Data.MapTypeModifiers.push_back(TypeModifier); | 
|  | Data.MapTypeModifiersLoc.push_back(Tok.getLocation()); | 
|  | ConsumeToken(); | 
|  | if (parseMapperModifier(Data)) | 
|  | return true; | 
|  | if (Tok.isNot(tok::comma) && Tok.isNot(tok::colon) && | 
|  | getLangOpts().OpenMP >= 52) | 
|  | Diag(Data.MapTypeModifiersLoc.back(), diag::err_omp_missing_comma) | 
|  | << "map type modifier"; | 
|  |  | 
|  | } else if (getLangOpts().OpenMP >= 60 && MapKind != OMPC_MAP_unknown) { | 
|  | if (!HasMapType) { | 
|  | HasMapType = true; | 
|  | Data.ExtraModifier = MapKind; | 
|  | MapKind = OMPC_MAP_unknown; | 
|  | PreMapLoc = Tok.getLocation(); | 
|  | PreMapName = Tok.getIdentifierInfo()->getName(); | 
|  | } else { | 
|  | Diag(Tok, diag::err_omp_more_one_map_type); | 
|  | Diag(PreMapLoc, diag::note_previous_map_type_specified_here) | 
|  | << PreMapName; | 
|  | } | 
|  | ConsumeToken(); | 
|  | } else if (TypeModifier == OMPC_MAP_MODIFIER_self) { | 
|  | Data.MapTypeModifiers.push_back(TypeModifier); | 
|  | Data.MapTypeModifiersLoc.push_back(Tok.getLocation()); | 
|  | if (PP.LookAhead(0).isNot(tok::comma) && | 
|  | PP.LookAhead(0).isNot(tok::colon)) | 
|  | Diag(Tok.getLocation(), diag::err_omp_missing_comma) | 
|  | << "map type modifier"; | 
|  | if (getLangOpts().OpenMP < 60) | 
|  | Diag(Tok, diag::err_omp_unknown_map_type_modifier) | 
|  | << (getLangOpts().OpenMP >= 51 | 
|  | ? (getLangOpts().OpenMP >= 52 ? 2 : 1) | 
|  | : 0) | 
|  | << getLangOpts().OpenMPExtensions << 0; | 
|  | ConsumeToken(); | 
|  | } else { | 
|  | // For the case of unknown map-type-modifier or a map-type. | 
|  | // Map-type is followed by a colon; the function returns when it | 
|  | // encounters a token followed by a colon. | 
|  | if (Tok.is(tok::comma)) { | 
|  | Diag(Tok, diag::err_omp_map_type_modifier_missing); | 
|  | ConsumeToken(); | 
|  | continue; | 
|  | } | 
|  | // Potential map-type token as it is followed by a colon. | 
|  | if (PP.LookAhead(0).is(tok::colon)) { | 
|  | if (getLangOpts().OpenMP >= 60) { | 
|  | break; | 
|  | } else { | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | Diag(Tok, diag::err_omp_unknown_map_type_modifier) | 
|  | << (getLangOpts().OpenMP >= 51 ? (getLangOpts().OpenMP >= 52 ? 2 : 1) | 
|  | : 0) | 
|  | << getLangOpts().OpenMPExtensions | 
|  | << (getLangOpts().OpenMP >= 60 ? 1 : 0); | 
|  | ConsumeToken(); | 
|  | } | 
|  | if (getCurToken().is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | } | 
|  | if (getLangOpts().OpenMP >= 60 && !HasMapType) { | 
|  | if (!Tok.is(tok::colon)) { | 
|  | Diag(Tok, diag::err_omp_unknown_map_type); | 
|  | ConsumeToken(); | 
|  | } else { | 
|  | Data.ExtraModifier = OMPC_MAP_unknown; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// Checks if the token is a valid map-type. | 
|  | /// If it is not MapType kind, OMPC_MAP_unknown is returned. | 
|  | static OpenMPMapClauseKind isMapType(Parser &P) { | 
|  | Token Tok = P.getCurToken(); | 
|  | // The map-type token can be either an identifier or the C++ delete keyword. | 
|  | if (!Tok.isOneOf(tok::identifier, tok::kw_delete)) | 
|  | return OMPC_MAP_unknown; | 
|  | Preprocessor &PP = P.getPreprocessor(); | 
|  | unsigned MapType = | 
|  | getOpenMPSimpleClauseType(OMPC_map, PP.getSpelling(Tok), P.getLangOpts()); | 
|  | if (MapType == OMPC_MAP_to || MapType == OMPC_MAP_from || | 
|  | MapType == OMPC_MAP_tofrom || MapType == OMPC_MAP_alloc || | 
|  | MapType == OMPC_MAP_delete || MapType == OMPC_MAP_release) | 
|  | return static_cast<OpenMPMapClauseKind>(MapType); | 
|  | return OMPC_MAP_unknown; | 
|  | } | 
|  |  | 
|  | /// Parse map-type in map clause. | 
|  | /// map([ [map-type-modifier[,] [map-type-modifier[,] ...] map-type : ] list) | 
|  | /// where, map-type ::= to | from | tofrom | alloc | release | delete | 
|  | static void parseMapType(Parser &P, SemaOpenMP::OpenMPVarListDataTy &Data) { | 
|  | Token Tok = P.getCurToken(); | 
|  | if (Tok.is(tok::colon)) { | 
|  | P.Diag(Tok, diag::err_omp_map_type_missing); | 
|  | return; | 
|  | } | 
|  | Data.ExtraModifier = isMapType(P); | 
|  | if (Data.ExtraModifier == OMPC_MAP_unknown) | 
|  | P.Diag(Tok, diag::err_omp_unknown_map_type); | 
|  | P.ConsumeToken(); | 
|  | } | 
|  |  | 
|  | ExprResult Parser::ParseOpenMPIteratorsExpr() { | 
|  | assert(Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator" && | 
|  | "Expected 'iterator' token."); | 
|  | SourceLocation IteratorKwLoc = ConsumeToken(); | 
|  |  | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, "iterator")) | 
|  | return ExprError(); | 
|  |  | 
|  | SourceLocation LLoc = T.getOpenLocation(); | 
|  | SmallVector<SemaOpenMP::OMPIteratorData, 4> Data; | 
|  | while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) { | 
|  | // Check if the type parsing is required. | 
|  | ParsedType IteratorType; | 
|  | if (Tok.isNot(tok::identifier) || NextToken().isNot(tok::equal)) { | 
|  | // identifier '=' is not found - parse type. | 
|  | TypeResult TR = ParseTypeName(); | 
|  | if (TR.isInvalid()) { | 
|  | T.skipToEnd(); | 
|  | return ExprError(); | 
|  | } | 
|  | IteratorType = TR.get(); | 
|  | } | 
|  |  | 
|  | // Parse identifier. | 
|  | IdentifierInfo *II = nullptr; | 
|  | SourceLocation IdLoc; | 
|  | if (Tok.is(tok::identifier)) { | 
|  | II = Tok.getIdentifierInfo(); | 
|  | IdLoc = ConsumeToken(); | 
|  | } else { | 
|  | Diag(Tok, diag::err_expected_unqualified_id) << 0; | 
|  | } | 
|  |  | 
|  | // Parse '='. | 
|  | SourceLocation AssignLoc; | 
|  | if (Tok.is(tok::equal)) | 
|  | AssignLoc = ConsumeToken(); | 
|  | else | 
|  | Diag(Tok, diag::err_omp_expected_equal_in_iterator); | 
|  |  | 
|  | // Parse range-specification - <begin> ':' <end> [ ':' <step> ] | 
|  | ColonProtectionRAIIObject ColonRAII(*this); | 
|  | // Parse <begin> | 
|  | SourceLocation Loc = Tok.getLocation(); | 
|  | ExprResult LHS = ParseCastExpression(CastParseKind::AnyCastExpr); | 
|  | ExprResult Begin = ParseRHSOfBinaryExpression(LHS, prec::Conditional); | 
|  | Begin = Actions.ActOnFinishFullExpr(Begin.get(), Loc, | 
|  | /*DiscardedValue=*/false); | 
|  | // Parse ':'. | 
|  | SourceLocation ColonLoc; | 
|  | if (Tok.is(tok::colon)) | 
|  | ColonLoc = ConsumeToken(); | 
|  |  | 
|  | // Parse <end> | 
|  | Loc = Tok.getLocation(); | 
|  | LHS = ParseCastExpression(CastParseKind::AnyCastExpr); | 
|  | ExprResult End = ParseRHSOfBinaryExpression(LHS, prec::Conditional); | 
|  | End = Actions.ActOnFinishFullExpr(End.get(), Loc, | 
|  | /*DiscardedValue=*/false); | 
|  |  | 
|  | SourceLocation SecColonLoc; | 
|  | ExprResult Step; | 
|  | // Parse optional step. | 
|  | if (Tok.is(tok::colon)) { | 
|  | // Parse ':' | 
|  | SecColonLoc = ConsumeToken(); | 
|  | // Parse <step> | 
|  | Loc = Tok.getLocation(); | 
|  | LHS = ParseCastExpression(CastParseKind::AnyCastExpr); | 
|  | Step = ParseRHSOfBinaryExpression(LHS, prec::Conditional); | 
|  | Step = Actions.ActOnFinishFullExpr(Step.get(), Loc, | 
|  | /*DiscardedValue=*/false); | 
|  | } | 
|  |  | 
|  | // Parse ',' or ')' | 
|  | if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren)) | 
|  | Diag(Tok, diag::err_omp_expected_punc_after_iterator); | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  |  | 
|  | SemaOpenMP::OMPIteratorData &D = Data.emplace_back(); | 
|  | D.DeclIdent = II; | 
|  | D.DeclIdentLoc = IdLoc; | 
|  | D.Type = IteratorType; | 
|  | D.AssignLoc = AssignLoc; | 
|  | D.ColonLoc = ColonLoc; | 
|  | D.SecColonLoc = SecColonLoc; | 
|  | D.Range.Begin = Begin.get(); | 
|  | D.Range.End = End.get(); | 
|  | D.Range.Step = Step.get(); | 
|  | } | 
|  |  | 
|  | // Parse ')'. | 
|  | SourceLocation RLoc = Tok.getLocation(); | 
|  | if (!T.consumeClose()) | 
|  | RLoc = T.getCloseLocation(); | 
|  |  | 
|  | return Actions.OpenMP().ActOnOMPIteratorExpr(getCurScope(), IteratorKwLoc, | 
|  | LLoc, RLoc, Data); | 
|  | } | 
|  |  | 
|  | bool Parser::ParseOpenMPReservedLocator(OpenMPClauseKind Kind, | 
|  | SemaOpenMP::OpenMPVarListDataTy &Data, | 
|  | const LangOptions &LangOpts) { | 
|  | // Currently the only reserved locator is 'omp_all_memory' which is only | 
|  | // allowed on a depend clause. | 
|  | if (Kind != OMPC_depend || LangOpts.OpenMP < 51) | 
|  | return false; | 
|  |  | 
|  | if (Tok.is(tok::identifier) && | 
|  | Tok.getIdentifierInfo()->isStr("omp_all_memory")) { | 
|  |  | 
|  | if (Data.ExtraModifier == OMPC_DEPEND_outallmemory || | 
|  | Data.ExtraModifier == OMPC_DEPEND_inoutallmemory) | 
|  | Diag(Tok, diag::warn_omp_more_one_omp_all_memory); | 
|  | else if (Data.ExtraModifier != OMPC_DEPEND_out && | 
|  | Data.ExtraModifier != OMPC_DEPEND_inout) | 
|  | Diag(Tok, diag::err_omp_requires_out_inout_depend_type); | 
|  | else | 
|  | Data.ExtraModifier = Data.ExtraModifier == OMPC_DEPEND_out | 
|  | ? OMPC_DEPEND_outallmemory | 
|  | : OMPC_DEPEND_inoutallmemory; | 
|  | ConsumeToken(); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// Parse step size expression. Returns true if parsing is successfull, | 
|  | /// otherwise returns false. | 
|  | static bool parseStepSize(Parser &P, SemaOpenMP::OpenMPVarListDataTy &Data, | 
|  | OpenMPClauseKind CKind, SourceLocation ELoc) { | 
|  | ExprResult Tail = P.ParseAssignmentExpression(); | 
|  | Sema &Actions = P.getActions(); | 
|  | Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc, | 
|  | /*DiscardedValue*/ false); | 
|  | if (Tail.isUsable()) { | 
|  | Data.DepModOrTailExpr = Tail.get(); | 
|  | Token CurTok = P.getCurToken(); | 
|  | if (CurTok.isNot(tok::r_paren) && CurTok.isNot(tok::comma)) { | 
|  | P.Diag(CurTok, diag::err_expected_punc) << "step expression"; | 
|  | } | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// Parse 'allocate' clause modifiers. | 
|  | ///   If allocator-modifier exists, return an expression for it. For both | 
|  | ///   allocator and align modifiers, set Data fields as appropriate. | 
|  | static ExprResult | 
|  | parseOpenMPAllocateClauseModifiers(Parser &P, OpenMPClauseKind Kind, | 
|  | SemaOpenMP::OpenMPVarListDataTy &Data) { | 
|  | const Token &Tok = P.getCurToken(); | 
|  | Preprocessor &PP = P.getPreprocessor(); | 
|  | ExprResult Tail; | 
|  | ExprResult Val; | 
|  | SourceLocation RLoc; | 
|  | bool AllocatorSeen = false; | 
|  | bool AlignSeen = false; | 
|  | SourceLocation CurrentModifierLoc = Tok.getLocation(); | 
|  | auto CurrentModifier = static_cast<OpenMPAllocateClauseModifier>( | 
|  | getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), P.getLangOpts())); | 
|  |  | 
|  | // Modifiers did not exist before 5.1 | 
|  | if (P.getLangOpts().OpenMP < 51) | 
|  | return P.ParseAssignmentExpression(); | 
|  |  | 
|  | // An allocator-simple-modifier is exclusive and must appear alone. See | 
|  | // OpenMP6.0 spec, pg. 313, L1 on Modifiers, as well as Table 5.1, pg. 50, | 
|  | // description of "exclusive" property. If we don't recognized an explicit | 
|  | // simple-/complex- modifier, assume we're looking at expression | 
|  | // representing allocator and consider ourselves done. | 
|  | if (CurrentModifier == OMPC_ALLOCATE_unknown) | 
|  | return P.ParseAssignmentExpression(); | 
|  |  | 
|  | do { | 
|  | P.ConsumeToken(); | 
|  | if (Tok.is(tok::l_paren)) { | 
|  | switch (CurrentModifier) { | 
|  | case OMPC_ALLOCATE_allocator: { | 
|  | if (AllocatorSeen) { | 
|  | P.Diag(Tok, diag::err_omp_duplicate_modifier) | 
|  | << getOpenMPSimpleClauseTypeName(OMPC_allocate, CurrentModifier) | 
|  | << getOpenMPClauseName(Kind); | 
|  | } else { | 
|  | Data.AllocClauseModifiers.push_back(CurrentModifier); | 
|  | Data.AllocClauseModifiersLoc.push_back(CurrentModifierLoc); | 
|  | } | 
|  | BalancedDelimiterTracker AllocateT(P, tok::l_paren, | 
|  | tok::annot_pragma_openmp_end); | 
|  | AllocateT.consumeOpen(); | 
|  | Tail = P.ParseAssignmentExpression(); | 
|  | AllocateT.consumeClose(); | 
|  | AllocatorSeen = true; | 
|  | break; | 
|  | } | 
|  | case OMPC_ALLOCATE_align: { | 
|  | if (AlignSeen) { | 
|  | P.Diag(Tok, diag::err_omp_duplicate_modifier) | 
|  | << getOpenMPSimpleClauseTypeName(OMPC_allocate, CurrentModifier) | 
|  | << getOpenMPClauseName(Kind); | 
|  | } else { | 
|  | Data.AllocClauseModifiers.push_back(CurrentModifier); | 
|  | Data.AllocClauseModifiersLoc.push_back(CurrentModifierLoc); | 
|  | } | 
|  | Val = P.ParseOpenMPParensExpr(getOpenMPClauseName(Kind), RLoc); | 
|  | if (Val.isUsable()) | 
|  | Data.AllocateAlignment = Val.get(); | 
|  | AlignSeen = true; | 
|  | break; | 
|  | } | 
|  | default: | 
|  | llvm_unreachable("Unexpected allocate modifier"); | 
|  | } | 
|  | } else { | 
|  | P.Diag(Tok, diag::err_expected) << tok::l_paren; | 
|  | } | 
|  | if (Tok.isNot(tok::comma)) | 
|  | break; | 
|  | P.ConsumeToken(); | 
|  | CurrentModifierLoc = Tok.getLocation(); | 
|  | CurrentModifier = static_cast<OpenMPAllocateClauseModifier>( | 
|  | getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), P.getLangOpts())); | 
|  | // A modifier followed by a comma implies another modifier. | 
|  | if (CurrentModifier == OMPC_ALLOCATE_unknown) { | 
|  | P.Diag(Tok, diag::err_omp_expected_modifier) << getOpenMPClauseName(Kind); | 
|  | break; | 
|  | } | 
|  | } while (!AllocatorSeen || !AlignSeen); | 
|  | return Tail; | 
|  | } | 
|  |  | 
|  | bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, | 
|  | OpenMPClauseKind Kind, | 
|  | SmallVectorImpl<Expr *> &Vars, | 
|  | SemaOpenMP::OpenMPVarListDataTy &Data) { | 
|  | UnqualifiedId UnqualifiedReductionId; | 
|  | bool InvalidReductionId = false; | 
|  | bool IsInvalidMapperModifier = false; | 
|  |  | 
|  | // Parse '('. | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.expectAndConsume(diag::err_expected_lparen_after, | 
|  | getOpenMPClauseName(Kind).data())) | 
|  | return true; | 
|  |  | 
|  | bool HasIterator = false; | 
|  | bool InvalidIterator = false; | 
|  | bool NeedRParenForLinear = false; | 
|  | BalancedDelimiterTracker LinearT(*this, tok::l_paren, | 
|  | tok::annot_pragma_openmp_end); | 
|  | // Handle reduction-identifier for reduction clause. | 
|  | if (Kind == OMPC_reduction || Kind == OMPC_task_reduction || | 
|  | Kind == OMPC_in_reduction) { | 
|  | Data.ExtraModifier = OMPC_REDUCTION_unknown; | 
|  | if (Kind == OMPC_reduction && getLangOpts().OpenMP >= 50 && | 
|  | (Tok.is(tok::identifier) || Tok.is(tok::kw_default)) && | 
|  | NextToken().is(tok::comma)) { | 
|  | // Parse optional reduction modifier. | 
|  | Data.ExtraModifier = | 
|  | getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts()); | 
|  | Data.ExtraModifierLoc = Tok.getLocation(); | 
|  | ConsumeToken(); | 
|  | assert(Tok.is(tok::comma) && "Expected comma."); | 
|  | (void)ConsumeToken(); | 
|  | } | 
|  | // Handle original(private / shared) Modifier | 
|  | if (Kind == OMPC_reduction && getLangOpts().OpenMP >= 60 && | 
|  | Tok.is(tok::identifier) && PP.getSpelling(Tok) == "original" && | 
|  | NextToken().is(tok::l_paren)) { | 
|  | // Parse original(private) modifier. | 
|  | ConsumeToken(); | 
|  | BalancedDelimiterTracker ParenT(*this, tok::l_paren, tok::r_paren); | 
|  | ParenT.consumeOpen(); | 
|  | if (Tok.is(tok::kw_private)) { | 
|  | Data.OriginalSharingModifier = OMPC_ORIGINAL_SHARING_private; | 
|  | Data.OriginalSharingModifierLoc = Tok.getLocation(); | 
|  | ConsumeToken(); | 
|  | } else if (Tok.is(tok::identifier) && | 
|  | (PP.getSpelling(Tok) == "shared" || | 
|  | PP.getSpelling(Tok) == "default")) { | 
|  | Data.OriginalSharingModifier = OMPC_ORIGINAL_SHARING_shared; | 
|  | Data.OriginalSharingModifierLoc = Tok.getLocation(); | 
|  | ConsumeToken(); | 
|  | } else { | 
|  | Diag(Tok.getLocation(), diag::err_expected) | 
|  | << "'private or shared or default'"; | 
|  | SkipUntil(tok::r_paren); | 
|  | return false; | 
|  | } | 
|  | ParenT.consumeClose(); | 
|  | if (!Tok.is(tok::comma)) { | 
|  | Diag(Tok.getLocation(), diag::err_expected) << "',' (comma)"; | 
|  | return false; | 
|  | } | 
|  | (void)ConsumeToken(); | 
|  | } | 
|  | ColonProtectionRAIIObject ColonRAII(*this); | 
|  | if (getLangOpts().CPlusPlus) | 
|  | ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec, | 
|  | /*ObjectType=*/nullptr, | 
|  | /*ObjectHasErrors=*/false, | 
|  | /*EnteringContext=*/false); | 
|  | InvalidReductionId = ParseReductionId( | 
|  | *this, Data.ReductionOrMapperIdScopeSpec, UnqualifiedReductionId); | 
|  | if (InvalidReductionId) { | 
|  | SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | } | 
|  | if (Tok.is(tok::colon)) | 
|  | Data.ColonLoc = ConsumeToken(); | 
|  | else | 
|  | Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier"; | 
|  | if (!InvalidReductionId) | 
|  | Data.ReductionOrMapperId = | 
|  | Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId); | 
|  | } else if (Kind == OMPC_depend || Kind == OMPC_doacross) { | 
|  | if (getLangOpts().OpenMP >= 50) { | 
|  | if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") { | 
|  | // Handle optional dependence modifier. | 
|  | // iterator(iterators-definition) | 
|  | // where iterators-definition is iterator-specifier [, | 
|  | // iterators-definition ] | 
|  | // where iterator-specifier is [ iterator-type ] identifier = | 
|  | // range-specification | 
|  | HasIterator = true; | 
|  | EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope); | 
|  | ExprResult IteratorRes = ParseOpenMPIteratorsExpr(); | 
|  | Data.DepModOrTailExpr = IteratorRes.get(); | 
|  | // Parse ',' | 
|  | ExpectAndConsume(tok::comma); | 
|  | } | 
|  | } | 
|  | // Handle dependency type for depend clause. | 
|  | ColonProtectionRAIIObject ColonRAII(*this); | 
|  | Data.ExtraModifier = getOpenMPSimpleClauseType( | 
|  | Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "", | 
|  | getLangOpts()); | 
|  | Data.ExtraModifierLoc = Tok.getLocation(); | 
|  | if ((Kind == OMPC_depend && Data.ExtraModifier == OMPC_DEPEND_unknown) || | 
|  | (Kind == OMPC_doacross && | 
|  | Data.ExtraModifier == OMPC_DOACROSS_unknown)) { | 
|  | SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | } else { | 
|  | ConsumeToken(); | 
|  | // Special processing for depend(source) clause. | 
|  | if (DKind == OMPD_ordered && Kind == OMPC_depend && | 
|  | Data.ExtraModifier == OMPC_DEPEND_source) { | 
|  | // Parse ')'. | 
|  | T.consumeClose(); | 
|  | return false; | 
|  | } | 
|  | } | 
|  | if (Tok.is(tok::colon)) { | 
|  | Data.ColonLoc = ConsumeToken(); | 
|  | } else if (Kind != OMPC_doacross || Tok.isNot(tok::r_paren)) { | 
|  | Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren | 
|  | : diag::warn_pragma_expected_colon) | 
|  | << (Kind == OMPC_depend ? "dependency type" : "dependence-type"); | 
|  | } | 
|  | if (Kind == OMPC_doacross) { | 
|  | if (Tok.is(tok::identifier) && | 
|  | Tok.getIdentifierInfo()->isStr("omp_cur_iteration")) { | 
|  | Data.ExtraModifier = Data.ExtraModifier == OMPC_DOACROSS_source | 
|  | ? OMPC_DOACROSS_source_omp_cur_iteration | 
|  | : OMPC_DOACROSS_sink_omp_cur_iteration; | 
|  | ConsumeToken(); | 
|  | } | 
|  | if (Data.ExtraModifier == OMPC_DOACROSS_sink_omp_cur_iteration) { | 
|  | if (Tok.isNot(tok::minus)) { | 
|  | Diag(Tok, diag::err_omp_sink_and_source_iteration_not_allowd) | 
|  | << getOpenMPClauseName(Kind) << 0 << 0; | 
|  | SkipUntil(tok::r_paren); | 
|  | return false; | 
|  | } else { | 
|  | ConsumeToken(); | 
|  | SourceLocation Loc = Tok.getLocation(); | 
|  | uint64_t Value = 0; | 
|  | if (Tok.isNot(tok::numeric_constant) || | 
|  | (PP.parseSimpleIntegerLiteral(Tok, Value) && Value != 1)) { | 
|  | Diag(Loc, diag::err_omp_sink_and_source_iteration_not_allowd) | 
|  | << getOpenMPClauseName(Kind) << 0 << 0; | 
|  | SkipUntil(tok::r_paren); | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (Data.ExtraModifier == OMPC_DOACROSS_source_omp_cur_iteration) { | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | Diag(Tok, diag::err_omp_sink_and_source_iteration_not_allowd) | 
|  | << getOpenMPClauseName(Kind) << 1 << 1; | 
|  | SkipUntil(tok::r_paren); | 
|  | return false; | 
|  | } | 
|  | } | 
|  | // Only the 'sink' case has the expression list. | 
|  | if (Kind == OMPC_doacross && | 
|  | (Data.ExtraModifier == OMPC_DOACROSS_source || | 
|  | Data.ExtraModifier == OMPC_DOACROSS_source_omp_cur_iteration || | 
|  | Data.ExtraModifier == OMPC_DOACROSS_sink_omp_cur_iteration)) { | 
|  | // Parse ')'. | 
|  | T.consumeClose(); | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } else if (Kind == OMPC_linear) { | 
|  | // Try to parse modifier if any. | 
|  | Data.ExtraModifier = OMPC_LINEAR_val; | 
|  | if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) { | 
|  | Data.ExtraModifier = | 
|  | getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts()); | 
|  | Data.ExtraModifierLoc = ConsumeToken(); | 
|  | LinearT.consumeOpen(); | 
|  | NeedRParenForLinear = true; | 
|  | if (getLangOpts().OpenMP >= 52) | 
|  | Diag(Data.ExtraModifierLoc, diag::err_omp_deprecate_old_syntax) | 
|  | << "linear-modifier(list)" << getOpenMPClauseName(Kind) | 
|  | << "linear(list: [linear-modifier,] step(step-size))"; | 
|  | } | 
|  | } else if (Kind == OMPC_lastprivate) { | 
|  | // Try to parse modifier if any. | 
|  | Data.ExtraModifier = OMPC_LASTPRIVATE_unknown; | 
|  | // Conditional modifier allowed only in OpenMP 5.0 and not supported in | 
|  | // distribute and taskloop based directives. | 
|  | if ((getLangOpts().OpenMP >= 50 && !isOpenMPDistributeDirective(DKind) && | 
|  | !isOpenMPTaskLoopDirective(DKind)) && | 
|  | Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::colon)) { | 
|  | Data.ExtraModifier = | 
|  | getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts()); | 
|  | Data.ExtraModifierLoc = Tok.getLocation(); | 
|  | ConsumeToken(); | 
|  | assert(Tok.is(tok::colon) && "Expected colon."); | 
|  | Data.ColonLoc = ConsumeToken(); | 
|  | } | 
|  | } else if (Kind == OMPC_map) { | 
|  | // Handle optional iterator map modifier. | 
|  | if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") { | 
|  | HasIterator = true; | 
|  | EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope); | 
|  | Data.MapTypeModifiers.push_back(OMPC_MAP_MODIFIER_iterator); | 
|  | Data.MapTypeModifiersLoc.push_back(Tok.getLocation()); | 
|  | ExprResult IteratorRes = ParseOpenMPIteratorsExpr(); | 
|  | Data.IteratorExpr = IteratorRes.get(); | 
|  | // Parse ',' | 
|  | ExpectAndConsume(tok::comma); | 
|  | if (getLangOpts().OpenMP < 52) { | 
|  | Diag(Tok, diag::err_omp_unknown_map_type_modifier) | 
|  | << (getLangOpts().OpenMP >= 51 ? 1 : 0) | 
|  | << getLangOpts().OpenMPExtensions << 0; | 
|  | InvalidIterator = true; | 
|  | } | 
|  | } | 
|  | // Handle map type for map clause. | 
|  | ColonProtectionRAIIObject ColonRAII(*this); | 
|  |  | 
|  | // The first identifier may be a list item, a map-type or a | 
|  | // map-type-modifier. The map-type can also be delete which has the same | 
|  | // spelling of the C++ delete keyword. | 
|  | Data.ExtraModifier = OMPC_MAP_unknown; | 
|  | Data.ExtraModifierLoc = Tok.getLocation(); | 
|  |  | 
|  | // Check for presence of a colon in the map clause. | 
|  | TentativeParsingAction TPA(*this); | 
|  | bool ColonPresent = false; | 
|  | if (SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch)) { | 
|  | if (Tok.is(tok::colon)) | 
|  | ColonPresent = true; | 
|  | } | 
|  | TPA.Revert(); | 
|  | // Only parse map-type-modifier[s] and map-type if a colon is present in | 
|  | // the map clause. | 
|  | if (ColonPresent) { | 
|  | if (getLangOpts().OpenMP >= 60 && getCurToken().is(tok::colon)) | 
|  | Diag(Tok, diag::err_omp_map_modifier_specification_list); | 
|  | IsInvalidMapperModifier = parseMapTypeModifiers(Data); | 
|  | if (getLangOpts().OpenMP < 60 && !IsInvalidMapperModifier) | 
|  | parseMapType(*this, Data); | 
|  | else | 
|  | SkipUntil(tok::colon, tok::annot_pragma_openmp_end, StopBeforeMatch); | 
|  | } | 
|  | if (Data.ExtraModifier == OMPC_MAP_unknown) { | 
|  | Data.ExtraModifier = OMPC_MAP_tofrom; | 
|  | if (getLangOpts().OpenMP >= 52) { | 
|  | if (DKind == OMPD_target_enter_data) | 
|  | Data.ExtraModifier = OMPC_MAP_to; | 
|  | else if (DKind == OMPD_target_exit_data) | 
|  | Data.ExtraModifier = OMPC_MAP_from; | 
|  | } | 
|  | Data.IsMapTypeImplicit = true; | 
|  | } | 
|  |  | 
|  | if (Tok.is(tok::colon)) | 
|  | Data.ColonLoc = ConsumeToken(); | 
|  | } else if (Kind == OMPC_to || Kind == OMPC_from) { | 
|  | while (Tok.is(tok::identifier)) { | 
|  | auto Modifier = static_cast<OpenMPMotionModifierKind>( | 
|  | getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts())); | 
|  | if (Modifier == OMPC_MOTION_MODIFIER_unknown) | 
|  | break; | 
|  | Data.MotionModifiers.push_back(Modifier); | 
|  | Data.MotionModifiersLoc.push_back(Tok.getLocation()); | 
|  | ConsumeToken(); | 
|  | if (Modifier == OMPC_MOTION_MODIFIER_mapper) { | 
|  | IsInvalidMapperModifier = parseMapperModifier(Data); | 
|  | if (IsInvalidMapperModifier) | 
|  | break; | 
|  | } | 
|  | // OpenMP < 5.1 doesn't permit a ',' or additional modifiers. | 
|  | if (getLangOpts().OpenMP < 51) | 
|  | break; | 
|  | // OpenMP 5.1 accepts an optional ',' even if the next character is ':'. | 
|  | // TODO: Is that intentional? | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | } | 
|  | if (!Data.MotionModifiers.empty() && Tok.isNot(tok::colon)) { | 
|  | if (!IsInvalidMapperModifier) { | 
|  | if (getLangOpts().OpenMP < 51) | 
|  | Diag(Tok, diag::warn_pragma_expected_colon) << ")"; | 
|  | else | 
|  | Diag(Tok, diag::warn_pragma_expected_colon) << "motion modifier"; | 
|  | } | 
|  | SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | } | 
|  | // OpenMP 5.1 permits a ':' even without a preceding modifier.  TODO: Is | 
|  | // that intentional? | 
|  | if ((!Data.MotionModifiers.empty() || getLangOpts().OpenMP >= 51) && | 
|  | Tok.is(tok::colon)) | 
|  | Data.ColonLoc = ConsumeToken(); | 
|  | } else if (Kind == OMPC_allocate || | 
|  | (Kind == OMPC_affinity && Tok.is(tok::identifier) && | 
|  | PP.getSpelling(Tok) == "iterator")) { | 
|  | // Handle optional allocator and align modifiers followed by colon | 
|  | // delimiter. | 
|  | ColonProtectionRAIIObject ColonRAII(*this); | 
|  | TentativeParsingAction TPA(*this); | 
|  | // OpenMP 5.0, 2.10.1, task Construct. | 
|  | // where aff-modifier is one of the following: | 
|  | // iterator(iterators-definition) | 
|  | ExprResult Tail; | 
|  | if (Kind == OMPC_allocate) { | 
|  | Tail = parseOpenMPAllocateClauseModifiers(*this, Kind, Data); | 
|  | } else { | 
|  | HasIterator = true; | 
|  | EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope); | 
|  | Tail = ParseOpenMPIteratorsExpr(); | 
|  | } | 
|  | Tail = Actions.ActOnFinishFullExpr(Tail.get(), T.getOpenLocation(), | 
|  | /*DiscardedValue=*/false); | 
|  | if (Tail.isUsable() || Data.AllocateAlignment) { | 
|  | if (Tok.is(tok::colon)) { | 
|  | Data.DepModOrTailExpr = Tail.isUsable() ? Tail.get() : nullptr; | 
|  | Data.ColonLoc = ConsumeToken(); | 
|  | TPA.Commit(); | 
|  | } else { | 
|  | // Colon not found, parse only list of variables. | 
|  | TPA.Revert(); | 
|  | if (Kind == OMPC_allocate && Data.AllocClauseModifiers.size()) { | 
|  | SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | Diag(Tok, diag::err_modifier_expected_colon) << "allocate clause"; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | // Parsing was unsuccessfull, revert and skip to the end of clause or | 
|  | // directive. | 
|  | TPA.Revert(); | 
|  | SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | } | 
|  | } else if (Kind == OMPC_adjust_args) { | 
|  | // Handle adjust-op for adjust_args clause. | 
|  | ColonProtectionRAIIObject ColonRAII(*this); | 
|  | Data.ExtraModifier = getOpenMPSimpleClauseType( | 
|  | Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "", | 
|  | getLangOpts()); | 
|  | Data.ExtraModifierLoc = Tok.getLocation(); | 
|  | if (Data.ExtraModifier == OMPC_ADJUST_ARGS_unknown) { | 
|  | Diag(Tok, diag::err_omp_unknown_adjust_args_op) | 
|  | << (getLangOpts().OpenMP >= 60 ? 1 : 0); | 
|  | SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); | 
|  | } else { | 
|  | ConsumeToken(); | 
|  | if (Tok.is(tok::colon)) | 
|  | Data.ColonLoc = Tok.getLocation(); | 
|  | ExpectAndConsume(tok::colon, diag::warn_pragma_expected_colon, | 
|  | "adjust-op"); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool IsComma = | 
|  | (Kind != OMPC_reduction && Kind != OMPC_task_reduction && | 
|  | Kind != OMPC_in_reduction && Kind != OMPC_depend && | 
|  | Kind != OMPC_doacross && Kind != OMPC_map && Kind != OMPC_adjust_args) || | 
|  | (Kind == OMPC_reduction && !InvalidReductionId) || | 
|  | (Kind == OMPC_map && Data.ExtraModifier != OMPC_MAP_unknown) || | 
|  | (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown) || | 
|  | (Kind == OMPC_doacross && Data.ExtraModifier != OMPC_DOACROSS_unknown) || | 
|  | (Kind == OMPC_adjust_args && | 
|  | Data.ExtraModifier != OMPC_ADJUST_ARGS_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))) { | 
|  | ParseScope OMPListScope(this, Scope::OpenMPDirectiveScope); | 
|  | ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail); | 
|  | if (!ParseOpenMPReservedLocator(Kind, Data, getLangOpts())) { | 
|  | // Parse variable | 
|  | ExprResult VarExpr = ParseAssignmentExpression(); | 
|  | if (VarExpr.isUsable()) { | 
|  | Vars.push_back(VarExpr.get()); | 
|  | } else { | 
|  | SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | } | 
|  | } | 
|  | // Skip ',' if any | 
|  | IsComma = Tok.is(tok::comma); | 
|  | if (IsComma) | 
|  | ConsumeToken(); | 
|  | else if (Tok.isNot(tok::r_paren) && | 
|  | Tok.isNot(tok::annot_pragma_openmp_end) && | 
|  | (!MayHaveTail || Tok.isNot(tok::colon))) { | 
|  | unsigned OMPVersion = Actions.getLangOpts().OpenMP; | 
|  | Diag(Tok, diag::err_omp_expected_punc) | 
|  | << ((Kind == OMPC_flush) | 
|  | ? getOpenMPDirectiveName(OMPD_flush, OMPVersion) | 
|  | : getOpenMPClauseName(Kind)) | 
|  | << (Kind == OMPC_flush); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Parse ')' for linear clause with modifier. | 
|  | if (NeedRParenForLinear) | 
|  | LinearT.consumeClose(); | 
|  | // Parse ':' linear modifiers (val, uval, ref or step(step-size)) | 
|  | // or parse ':' alignment. | 
|  | const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon); | 
|  | bool StepFound = false; | 
|  | bool ModifierFound = false; | 
|  | if (MustHaveTail) { | 
|  | Data.ColonLoc = Tok.getLocation(); | 
|  | SourceLocation ELoc = ConsumeToken(); | 
|  |  | 
|  | if (getLangOpts().OpenMP >= 52 && Kind == OMPC_linear) { | 
|  | bool Malformed = false; | 
|  | while (Tok.isNot(tok::r_paren)) { | 
|  | if (Tok.is(tok::identifier)) { | 
|  | // identifier could be a linear kind (val, uval, ref) or step | 
|  | // modifier or step size | 
|  | OpenMPLinearClauseKind LinKind = | 
|  | static_cast<OpenMPLinearClauseKind>(getOpenMPSimpleClauseType( | 
|  | Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), | 
|  | getLangOpts())); | 
|  |  | 
|  | if (LinKind == OMPC_LINEAR_step) { | 
|  | if (StepFound) | 
|  | Diag(Tok, diag::err_omp_multiple_step_or_linear_modifier) << 0; | 
|  |  | 
|  | BalancedDelimiterTracker StepT(*this, tok::l_paren, | 
|  | tok::annot_pragma_openmp_end); | 
|  | SourceLocation StepModifierLoc = ConsumeToken(); | 
|  | // parse '(' | 
|  | if (StepT.consumeOpen()) | 
|  | Diag(StepModifierLoc, diag::err_expected_lparen_after) << "step"; | 
|  |  | 
|  | // parse step size expression | 
|  | StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation()); | 
|  | if (StepFound) | 
|  | Data.StepModifierLoc = StepModifierLoc; | 
|  |  | 
|  | // parse ')' | 
|  | StepT.consumeClose(); | 
|  | } else if (LinKind >= 0 && LinKind < OMPC_LINEAR_step) { | 
|  | if (ModifierFound) | 
|  | Diag(Tok, diag::err_omp_multiple_step_or_linear_modifier) << 1; | 
|  |  | 
|  | Data.ExtraModifier = LinKind; | 
|  | Data.ExtraModifierLoc = ConsumeToken(); | 
|  | ModifierFound = true; | 
|  | } else { | 
|  | StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation()); | 
|  | if (!StepFound) { | 
|  | Malformed = true; | 
|  | SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | } | 
|  | } | 
|  | } else { | 
|  | // parse an integer expression as step size | 
|  | StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation()); | 
|  | } | 
|  |  | 
|  | if (Tok.is(tok::comma)) | 
|  | ConsumeToken(); | 
|  | if (Tok.is(tok::r_paren) || Tok.is(tok::annot_pragma_openmp_end)) | 
|  | break; | 
|  | } | 
|  | if (!Malformed && !StepFound && !ModifierFound) | 
|  | Diag(ELoc, diag::err_expected_expression); | 
|  | } else { | 
|  | // for OMPC_aligned and OMPC_linear (with OpenMP <= 5.1) | 
|  | ExprResult Tail = ParseAssignmentExpression(); | 
|  | Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc, | 
|  | /*DiscardedValue*/ false); | 
|  | if (Tail.isUsable()) | 
|  | Data.DepModOrTailExpr = Tail.get(); | 
|  | else | 
|  | SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, | 
|  | StopBeforeMatch); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Parse ')'. | 
|  | Data.RLoc = Tok.getLocation(); | 
|  | if (!T.consumeClose()) | 
|  | Data.RLoc = T.getCloseLocation(); | 
|  | // Exit from scope when the iterator is used in depend clause. | 
|  | if (HasIterator) | 
|  | ExitScope(); | 
|  | return (Kind != OMPC_depend && Kind != OMPC_doacross && Kind != OMPC_map && | 
|  | Vars.empty()) || | 
|  | (MustHaveTail && !Data.DepModOrTailExpr && StepFound) || | 
|  | InvalidReductionId || IsInvalidMapperModifier || InvalidIterator; | 
|  | } | 
|  |  | 
|  | OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, | 
|  | OpenMPClauseKind Kind, | 
|  | bool ParseOnly) { | 
|  | SourceLocation Loc = Tok.getLocation(); | 
|  | SourceLocation LOpen = ConsumeToken(); | 
|  | SmallVector<Expr *, 4> Vars; | 
|  | SemaOpenMP::OpenMPVarListDataTy Data; | 
|  |  | 
|  | if (ParseOpenMPVarList(DKind, Kind, Vars, Data)) | 
|  | return nullptr; | 
|  |  | 
|  | if (ParseOnly) | 
|  | return nullptr; | 
|  | OMPVarListLocTy Locs(Loc, LOpen, Data.RLoc); | 
|  | return Actions.OpenMP().ActOnOpenMPVarListClause(Kind, Vars, Locs, Data); | 
|  | } | 
|  |  | 
|  | bool Parser::ParseOpenMPExprListClause(OpenMPClauseKind Kind, | 
|  | SourceLocation &ClauseNameLoc, | 
|  | SourceLocation &OpenLoc, | 
|  | SourceLocation &CloseLoc, | 
|  | SmallVectorImpl<Expr *> &Exprs, | 
|  | bool ReqIntConst) { | 
|  | assert(getOpenMPClauseName(Kind) == PP.getSpelling(Tok) && | 
|  | "Expected parsing to start at clause name"); | 
|  | ClauseNameLoc = ConsumeToken(); | 
|  |  | 
|  | // Parse inside of '(' and ')'. | 
|  | BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); | 
|  | if (T.consumeOpen()) { | 
|  | Diag(Tok, diag::err_expected) << tok::l_paren; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Parse the list with interleaved commas. | 
|  | do { | 
|  | ExprResult Val = | 
|  | ReqIntConst ? ParseConstantExpression() : ParseAssignmentExpression(); | 
|  | if (!Val.isUsable()) { | 
|  | // Encountered something other than an expression; abort to ')'. | 
|  | T.skipToEnd(); | 
|  | return true; | 
|  | } | 
|  | Exprs.push_back(Val.get()); | 
|  | } while (TryConsumeToken(tok::comma)); | 
|  |  | 
|  | bool Result = T.consumeClose(); | 
|  | OpenLoc = T.getOpenLocation(); | 
|  | CloseLoc = T.getCloseLocation(); | 
|  | return Result; | 
|  | } |