Path: blob/main/contrib/llvm-project/clang/lib/Parse/ParseOpenMP.cpp
35234 views
//===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7/// \file8/// This file implements parsing of all OpenMP directives and clauses.9///10//===----------------------------------------------------------------------===//1112#include "clang/AST/ASTContext.h"13#include "clang/AST/OpenMPClause.h"14#include "clang/AST/StmtOpenMP.h"15#include "clang/Basic/OpenMPKinds.h"16#include "clang/Basic/TargetInfo.h"17#include "clang/Basic/TokenKinds.h"18#include "clang/Parse/ParseDiagnostic.h"19#include "clang/Parse/Parser.h"20#include "clang/Parse/RAIIObjectsForParser.h"21#include "clang/Sema/EnterExpressionEvaluationContext.h"22#include "clang/Sema/Scope.h"23#include "clang/Sema/SemaAMDGPU.h"24#include "clang/Sema/SemaCodeCompletion.h"25#include "clang/Sema/SemaOpenMP.h"26#include "llvm/ADT/SmallBitVector.h"27#include "llvm/ADT/StringSwitch.h"28#include "llvm/Frontend/OpenMP/OMPAssume.h"29#include "llvm/Frontend/OpenMP/OMPContext.h"30#include <optional>3132using namespace clang;33using namespace llvm::omp;3435//===----------------------------------------------------------------------===//36// OpenMP declarative directives.37//===----------------------------------------------------------------------===//3839namespace {40enum OpenMPDirectiveKindEx {41OMPD_cancellation = llvm::omp::Directive_enumSize + 1,42OMPD_data,43OMPD_declare,44OMPD_end,45OMPD_end_declare,46OMPD_enter,47OMPD_exit,48OMPD_point,49OMPD_reduction,50OMPD_target_enter,51OMPD_target_exit,52OMPD_update,53OMPD_distribute_parallel,54OMPD_teams_distribute_parallel,55OMPD_target_teams_distribute_parallel,56OMPD_mapper,57OMPD_variant,58OMPD_begin,59OMPD_begin_declare,60};6162// Helper to unify the enum class OpenMPDirectiveKind with its extension63// the OpenMPDirectiveKindEx enum which allows to use them together as if they64// are unsigned values.65struct OpenMPDirectiveKindExWrapper {66OpenMPDirectiveKindExWrapper(unsigned Value) : Value(Value) {}67OpenMPDirectiveKindExWrapper(OpenMPDirectiveKind DK) : Value(unsigned(DK)) {}68bool operator==(OpenMPDirectiveKindExWrapper V) const {69return Value == V.Value;70}71bool operator!=(OpenMPDirectiveKindExWrapper V) const {72return Value != V.Value;73}74bool operator==(OpenMPDirectiveKind V) const { return Value == unsigned(V); }75bool operator!=(OpenMPDirectiveKind V) const { return Value != unsigned(V); }76bool operator<(OpenMPDirectiveKind V) const { return Value < unsigned(V); }77operator unsigned() const { return Value; }78operator OpenMPDirectiveKind() const { return OpenMPDirectiveKind(Value); }79unsigned Value;80};8182class DeclDirectiveListParserHelper final {83SmallVector<Expr *, 4> Identifiers;84Parser *P;85OpenMPDirectiveKind Kind;8687public:88DeclDirectiveListParserHelper(Parser *P, OpenMPDirectiveKind Kind)89: P(P), Kind(Kind) {}90void operator()(CXXScopeSpec &SS, DeclarationNameInfo NameInfo) {91ExprResult Res = P->getActions().OpenMP().ActOnOpenMPIdExpression(92P->getCurScope(), SS, NameInfo, Kind);93if (Res.isUsable())94Identifiers.push_back(Res.get());95}96llvm::ArrayRef<Expr *> getIdentifiers() const { return Identifiers; }97};98} // namespace99100// Map token string to extended OMP token kind that are101// OpenMPDirectiveKind + OpenMPDirectiveKindEx.102static unsigned getOpenMPDirectiveKindEx(StringRef S) {103OpenMPDirectiveKindExWrapper DKind = getOpenMPDirectiveKind(S);104if (DKind != OMPD_unknown)105return DKind;106107return llvm::StringSwitch<OpenMPDirectiveKindExWrapper>(S)108.Case("cancellation", OMPD_cancellation)109.Case("data", OMPD_data)110.Case("declare", OMPD_declare)111.Case("end", OMPD_end)112.Case("enter", OMPD_enter)113.Case("exit", OMPD_exit)114.Case("point", OMPD_point)115.Case("reduction", OMPD_reduction)116.Case("update", OMPD_update)117.Case("mapper", OMPD_mapper)118.Case("variant", OMPD_variant)119.Case("begin", OMPD_begin)120.Default(OMPD_unknown);121}122123static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) {124// Array of foldings: F[i][0] F[i][1] ===> F[i][2].125// E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd126// TODO: add other combined directives in topological order.127static const OpenMPDirectiveKindExWrapper F[][3] = {128{OMPD_begin, OMPD_declare, OMPD_begin_declare},129{OMPD_begin, OMPD_assumes, OMPD_begin_assumes},130{OMPD_end, OMPD_declare, OMPD_end_declare},131{OMPD_end, OMPD_assumes, OMPD_end_assumes},132{OMPD_cancellation, OMPD_point, OMPD_cancellation_point},133{OMPD_declare, OMPD_reduction, OMPD_declare_reduction},134{OMPD_declare, OMPD_mapper, OMPD_declare_mapper},135{OMPD_declare, OMPD_simd, OMPD_declare_simd},136{OMPD_declare, OMPD_target, OMPD_declare_target},137{OMPD_declare, OMPD_variant, OMPD_declare_variant},138{OMPD_begin_declare, OMPD_target, OMPD_begin_declare_target},139{OMPD_begin_declare, OMPD_variant, OMPD_begin_declare_variant},140{OMPD_end_declare, OMPD_variant, OMPD_end_declare_variant},141{OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel},142{OMPD_distribute_parallel, OMPD_for, OMPD_distribute_parallel_for},143{OMPD_distribute_parallel_for, OMPD_simd,144OMPD_distribute_parallel_for_simd},145{OMPD_distribute, OMPD_simd, OMPD_distribute_simd},146{OMPD_end_declare, OMPD_target, OMPD_end_declare_target},147{OMPD_target, OMPD_data, OMPD_target_data},148{OMPD_target, OMPD_enter, OMPD_target_enter},149{OMPD_target, OMPD_exit, OMPD_target_exit},150{OMPD_target, OMPD_update, OMPD_target_update},151{OMPD_target_enter, OMPD_data, OMPD_target_enter_data},152{OMPD_target_exit, OMPD_data, OMPD_target_exit_data},153{OMPD_for, OMPD_simd, OMPD_for_simd},154{OMPD_parallel, OMPD_for, OMPD_parallel_for},155{OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd},156{OMPD_parallel, OMPD_loop, OMPD_parallel_loop},157{OMPD_parallel, OMPD_sections, OMPD_parallel_sections},158{OMPD_taskloop, OMPD_simd, OMPD_taskloop_simd},159{OMPD_target, OMPD_parallel, OMPD_target_parallel},160{OMPD_target, OMPD_simd, OMPD_target_simd},161{OMPD_target_parallel, OMPD_loop, OMPD_target_parallel_loop},162{OMPD_target_parallel, OMPD_for, OMPD_target_parallel_for},163{OMPD_target_parallel_for, OMPD_simd, OMPD_target_parallel_for_simd},164{OMPD_teams, OMPD_distribute, OMPD_teams_distribute},165{OMPD_teams_distribute, OMPD_simd, OMPD_teams_distribute_simd},166{OMPD_teams_distribute, OMPD_parallel, OMPD_teams_distribute_parallel},167{OMPD_teams_distribute_parallel, OMPD_for,168OMPD_teams_distribute_parallel_for},169{OMPD_teams_distribute_parallel_for, OMPD_simd,170OMPD_teams_distribute_parallel_for_simd},171{OMPD_teams, OMPD_loop, OMPD_teams_loop},172{OMPD_target, OMPD_teams, OMPD_target_teams},173{OMPD_target_teams, OMPD_distribute, OMPD_target_teams_distribute},174{OMPD_target_teams, OMPD_loop, OMPD_target_teams_loop},175{OMPD_target_teams_distribute, OMPD_parallel,176OMPD_target_teams_distribute_parallel},177{OMPD_target_teams_distribute, OMPD_simd,178OMPD_target_teams_distribute_simd},179{OMPD_target_teams_distribute_parallel, OMPD_for,180OMPD_target_teams_distribute_parallel_for},181{OMPD_target_teams_distribute_parallel_for, OMPD_simd,182OMPD_target_teams_distribute_parallel_for_simd},183{OMPD_master, OMPD_taskloop, OMPD_master_taskloop},184{OMPD_masked, OMPD_taskloop, OMPD_masked_taskloop},185{OMPD_master_taskloop, OMPD_simd, OMPD_master_taskloop_simd},186{OMPD_masked_taskloop, OMPD_simd, OMPD_masked_taskloop_simd},187{OMPD_parallel, OMPD_master, OMPD_parallel_master},188{OMPD_parallel, OMPD_masked, OMPD_parallel_masked},189{OMPD_parallel_master, OMPD_taskloop, OMPD_parallel_master_taskloop},190{OMPD_parallel_masked, OMPD_taskloop, OMPD_parallel_masked_taskloop},191{OMPD_parallel_master_taskloop, OMPD_simd,192OMPD_parallel_master_taskloop_simd},193{OMPD_parallel_masked_taskloop, OMPD_simd,194OMPD_parallel_masked_taskloop_simd}};195enum { CancellationPoint = 0, DeclareReduction = 1, TargetData = 2 };196Token Tok = P.getCurToken();197OpenMPDirectiveKindExWrapper DKind =198Tok.isAnnotation()199? static_cast<unsigned>(OMPD_unknown)200: getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok));201if (DKind == OMPD_unknown)202return OMPD_unknown;203204for (const auto &I : F) {205if (DKind != I[0])206continue;207208Tok = P.getPreprocessor().LookAhead(0);209OpenMPDirectiveKindExWrapper SDKind =210Tok.isAnnotation()211? static_cast<unsigned>(OMPD_unknown)212: getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok));213if (SDKind == OMPD_unknown)214continue;215216if (SDKind == I[1]) {217P.ConsumeToken();218DKind = I[2];219}220}221return unsigned(DKind) < llvm::omp::Directive_enumSize222? static_cast<OpenMPDirectiveKind>(DKind)223: OMPD_unknown;224}225226static DeclarationName parseOpenMPReductionId(Parser &P) {227Token Tok = P.getCurToken();228Sema &Actions = P.getActions();229OverloadedOperatorKind OOK = OO_None;230// Allow to use 'operator' keyword for C++ operators231bool WithOperator = false;232if (Tok.is(tok::kw_operator)) {233P.ConsumeToken();234Tok = P.getCurToken();235WithOperator = true;236}237switch (Tok.getKind()) {238case tok::plus: // '+'239OOK = OO_Plus;240break;241case tok::minus: // '-'242OOK = OO_Minus;243break;244case tok::star: // '*'245OOK = OO_Star;246break;247case tok::amp: // '&'248OOK = OO_Amp;249break;250case tok::pipe: // '|'251OOK = OO_Pipe;252break;253case tok::caret: // '^'254OOK = OO_Caret;255break;256case tok::ampamp: // '&&'257OOK = OO_AmpAmp;258break;259case tok::pipepipe: // '||'260OOK = OO_PipePipe;261break;262case tok::identifier: // identifier263if (!WithOperator)264break;265[[fallthrough]];266default:267P.Diag(Tok.getLocation(), diag::err_omp_expected_reduction_identifier);268P.SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,269Parser::StopBeforeMatch);270return DeclarationName();271}272P.ConsumeToken();273auto &DeclNames = Actions.getASTContext().DeclarationNames;274return OOK == OO_None ? DeclNames.getIdentifier(Tok.getIdentifierInfo())275: DeclNames.getCXXOperatorName(OOK);276}277278/// Parse 'omp declare reduction' construct.279///280/// declare-reduction-directive:281/// annot_pragma_openmp 'declare' 'reduction'282/// '(' <reduction_id> ':' <type> {',' <type>} ':' <expression> ')'283/// ['initializer' '(' ('omp_priv' '=' <expression>)|<function_call> ')']284/// annot_pragma_openmp_end285/// <reduction_id> is either a base language identifier or one of the following286/// operators: '+', '-', '*', '&', '|', '^', '&&' and '||'.287///288Parser::DeclGroupPtrTy289Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {290// Parse '('.291BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);292if (T.expectAndConsume(293diag::err_expected_lparen_after,294getOpenMPDirectiveName(OMPD_declare_reduction).data())) {295SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);296return DeclGroupPtrTy();297}298299DeclarationName Name = parseOpenMPReductionId(*this);300if (Name.isEmpty() && Tok.is(tok::annot_pragma_openmp_end))301return DeclGroupPtrTy();302303// Consume ':'.304bool IsCorrect = !ExpectAndConsume(tok::colon);305306if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))307return DeclGroupPtrTy();308309IsCorrect = IsCorrect && !Name.isEmpty();310311if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) {312Diag(Tok.getLocation(), diag::err_expected_type);313IsCorrect = false;314}315316if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))317return DeclGroupPtrTy();318319SmallVector<std::pair<QualType, SourceLocation>, 8> ReductionTypes;320// Parse list of types until ':' token.321do {322ColonProtectionRAIIObject ColonRAII(*this);323SourceRange Range;324TypeResult TR = ParseTypeName(&Range, DeclaratorContext::Prototype, AS);325if (TR.isUsable()) {326QualType ReductionType = Actions.OpenMP().ActOnOpenMPDeclareReductionType(327Range.getBegin(), TR);328if (!ReductionType.isNull()) {329ReductionTypes.push_back(330std::make_pair(ReductionType, Range.getBegin()));331}332} else {333SkipUntil(tok::comma, tok::colon, tok::annot_pragma_openmp_end,334StopBeforeMatch);335}336337if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end))338break;339340// Consume ','.341if (ExpectAndConsume(tok::comma)) {342IsCorrect = false;343if (Tok.is(tok::annot_pragma_openmp_end)) {344Diag(Tok.getLocation(), diag::err_expected_type);345return DeclGroupPtrTy();346}347}348} while (Tok.isNot(tok::annot_pragma_openmp_end));349350if (ReductionTypes.empty()) {351SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);352return DeclGroupPtrTy();353}354355if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))356return DeclGroupPtrTy();357358// Consume ':'.359if (ExpectAndConsume(tok::colon))360IsCorrect = false;361362if (Tok.is(tok::annot_pragma_openmp_end)) {363Diag(Tok.getLocation(), diag::err_expected_expression);364return DeclGroupPtrTy();365}366367DeclGroupPtrTy DRD =368Actions.OpenMP().ActOnOpenMPDeclareReductionDirectiveStart(369getCurScope(), Actions.getCurLexicalContext(), Name, ReductionTypes,370AS);371372// Parse <combiner> expression and then parse initializer if any for each373// correct type.374unsigned I = 0, E = ReductionTypes.size();375for (Decl *D : DRD.get()) {376TentativeParsingAction TPA(*this);377ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |378Scope::CompoundStmtScope |379Scope::OpenMPDirectiveScope);380// Parse <combiner> expression.381Actions.OpenMP().ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D);382ExprResult CombinerResult = Actions.ActOnFinishFullExpr(383ParseExpression().get(), D->getLocation(), /*DiscardedValue*/ false);384Actions.OpenMP().ActOnOpenMPDeclareReductionCombinerEnd(385D, CombinerResult.get());386387if (CombinerResult.isInvalid() && Tok.isNot(tok::r_paren) &&388Tok.isNot(tok::annot_pragma_openmp_end)) {389TPA.Commit();390IsCorrect = false;391break;392}393IsCorrect = !T.consumeClose() && IsCorrect && CombinerResult.isUsable();394ExprResult InitializerResult;395if (Tok.isNot(tok::annot_pragma_openmp_end)) {396// Parse <initializer> expression.397if (Tok.is(tok::identifier) &&398Tok.getIdentifierInfo()->isStr("initializer")) {399ConsumeToken();400} else {401Diag(Tok.getLocation(), diag::err_expected) << "'initializer'";402TPA.Commit();403IsCorrect = false;404break;405}406// Parse '('.407BalancedDelimiterTracker T(*this, tok::l_paren,408tok::annot_pragma_openmp_end);409IsCorrect =410!T.expectAndConsume(diag::err_expected_lparen_after, "initializer") &&411IsCorrect;412if (Tok.isNot(tok::annot_pragma_openmp_end)) {413ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |414Scope::CompoundStmtScope |415Scope::OpenMPDirectiveScope);416// Parse expression.417VarDecl *OmpPrivParm =418Actions.OpenMP().ActOnOpenMPDeclareReductionInitializerStart(419getCurScope(), D);420// Check if initializer is omp_priv <init_expr> or something else.421if (Tok.is(tok::identifier) &&422Tok.getIdentifierInfo()->isStr("omp_priv")) {423ConsumeToken();424ParseOpenMPReductionInitializerForDecl(OmpPrivParm);425} else {426InitializerResult = Actions.ActOnFinishFullExpr(427ParseAssignmentExpression().get(), D->getLocation(),428/*DiscardedValue*/ false);429}430Actions.OpenMP().ActOnOpenMPDeclareReductionInitializerEnd(431D, InitializerResult.get(), OmpPrivParm);432if (InitializerResult.isInvalid() && Tok.isNot(tok::r_paren) &&433Tok.isNot(tok::annot_pragma_openmp_end)) {434TPA.Commit();435IsCorrect = false;436break;437}438IsCorrect =439!T.consumeClose() && IsCorrect && !InitializerResult.isInvalid();440}441}442443++I;444// Revert parsing if not the last type, otherwise accept it, we're done with445// parsing.446if (I != E)447TPA.Revert();448else449TPA.Commit();450}451return Actions.OpenMP().ActOnOpenMPDeclareReductionDirectiveEnd(452getCurScope(), DRD, IsCorrect);453}454455void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {456// Parse declarator '=' initializer.457// If a '==' or '+=' is found, suggest a fixit to '='.458if (isTokenEqualOrEqualTypo()) {459ConsumeToken();460461if (Tok.is(tok::code_completion)) {462cutOffParsing();463Actions.CodeCompletion().CodeCompleteInitializer(getCurScope(),464OmpPrivParm);465Actions.FinalizeDeclaration(OmpPrivParm);466return;467}468469PreferredType.enterVariableInit(Tok.getLocation(), OmpPrivParm);470ExprResult Init = ParseInitializer();471472if (Init.isInvalid()) {473SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);474Actions.ActOnInitializerError(OmpPrivParm);475} else {476Actions.AddInitializerToDecl(OmpPrivParm, Init.get(),477/*DirectInit=*/false);478}479} else if (Tok.is(tok::l_paren)) {480// Parse C++ direct initializer: '(' expression-list ')'481BalancedDelimiterTracker T(*this, tok::l_paren);482T.consumeOpen();483484ExprVector Exprs;485486SourceLocation LParLoc = T.getOpenLocation();487auto RunSignatureHelp = [this, OmpPrivParm, LParLoc, &Exprs]() {488QualType PreferredType =489Actions.CodeCompletion().ProduceConstructorSignatureHelp(490OmpPrivParm->getType()->getCanonicalTypeInternal(),491OmpPrivParm->getLocation(), Exprs, LParLoc, /*Braced=*/false);492CalledSignatureHelp = true;493return PreferredType;494};495if (ParseExpressionList(Exprs, [&] {496PreferredType.enterFunctionArgument(Tok.getLocation(),497RunSignatureHelp);498})) {499if (PP.isCodeCompletionReached() && !CalledSignatureHelp)500RunSignatureHelp();501Actions.ActOnInitializerError(OmpPrivParm);502SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);503} else {504// Match the ')'.505SourceLocation RLoc = Tok.getLocation();506if (!T.consumeClose())507RLoc = T.getCloseLocation();508509ExprResult Initializer =510Actions.ActOnParenListExpr(T.getOpenLocation(), RLoc, Exprs);511Actions.AddInitializerToDecl(OmpPrivParm, Initializer.get(),512/*DirectInit=*/true);513}514} else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {515// Parse C++0x braced-init-list.516Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);517518ExprResult Init(ParseBraceInitializer());519520if (Init.isInvalid()) {521Actions.ActOnInitializerError(OmpPrivParm);522} else {523Actions.AddInitializerToDecl(OmpPrivParm, Init.get(),524/*DirectInit=*/true);525}526} else {527Actions.ActOnUninitializedDecl(OmpPrivParm);528}529}530531/// Parses 'omp declare mapper' directive.532///533/// declare-mapper-directive:534/// annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifier> ':']535/// <type> <var> ')' [<clause>[[,] <clause>] ... ]536/// annot_pragma_openmp_end537/// <mapper-identifier> and <var> are base language identifiers.538///539Parser::DeclGroupPtrTy540Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) {541bool IsCorrect = true;542// Parse '('543BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);544if (T.expectAndConsume(diag::err_expected_lparen_after,545getOpenMPDirectiveName(OMPD_declare_mapper).data())) {546SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);547return DeclGroupPtrTy();548}549550// Parse <mapper-identifier>551auto &DeclNames = Actions.getASTContext().DeclarationNames;552DeclarationName MapperId;553if (PP.LookAhead(0).is(tok::colon)) {554if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_default)) {555Diag(Tok.getLocation(), diag::err_omp_mapper_illegal_identifier);556IsCorrect = false;557} else {558MapperId = DeclNames.getIdentifier(Tok.getIdentifierInfo());559}560ConsumeToken();561// Consume ':'.562ExpectAndConsume(tok::colon);563} else {564// If no mapper identifier is provided, its name is "default" by default565MapperId =566DeclNames.getIdentifier(&Actions.getASTContext().Idents.get("default"));567}568569if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))570return DeclGroupPtrTy();571572// Parse <type> <var>573DeclarationName VName;574QualType MapperType;575SourceRange Range;576TypeResult ParsedType = parseOpenMPDeclareMapperVarDecl(Range, VName, AS);577if (ParsedType.isUsable())578MapperType = Actions.OpenMP().ActOnOpenMPDeclareMapperType(Range.getBegin(),579ParsedType);580if (MapperType.isNull())581IsCorrect = false;582if (!IsCorrect) {583SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch);584return DeclGroupPtrTy();585}586587// Consume ')'.588IsCorrect &= !T.consumeClose();589if (!IsCorrect) {590SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch);591return DeclGroupPtrTy();592}593594// Enter scope.595DeclarationNameInfo DirName;596SourceLocation Loc = Tok.getLocation();597unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |598Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;599ParseScope OMPDirectiveScope(this, ScopeFlags);600Actions.OpenMP().StartOpenMPDSABlock(OMPD_declare_mapper, DirName,601getCurScope(), Loc);602603// Add the mapper variable declaration.604ExprResult MapperVarRef =605Actions.OpenMP().ActOnOpenMPDeclareMapperDirectiveVarDecl(606getCurScope(), MapperType, Range.getBegin(), VName);607608// Parse map clauses.609SmallVector<OMPClause *, 6> Clauses;610while (Tok.isNot(tok::annot_pragma_openmp_end)) {611OpenMPClauseKind CKind = Tok.isAnnotation()612? OMPC_unknown613: getOpenMPClauseKind(PP.getSpelling(Tok));614Actions.OpenMP().StartOpenMPClause(CKind);615OMPClause *Clause =616ParseOpenMPClause(OMPD_declare_mapper, CKind, Clauses.empty());617if (Clause)618Clauses.push_back(Clause);619else620IsCorrect = false;621// Skip ',' if any.622if (Tok.is(tok::comma))623ConsumeToken();624Actions.OpenMP().EndOpenMPClause();625}626if (Clauses.empty()) {627Diag(Tok, diag::err_omp_expected_clause)628<< getOpenMPDirectiveName(OMPD_declare_mapper);629IsCorrect = false;630}631632// Exit scope.633Actions.OpenMP().EndOpenMPDSABlock(nullptr);634OMPDirectiveScope.Exit();635DeclGroupPtrTy DG = Actions.OpenMP().ActOnOpenMPDeclareMapperDirective(636getCurScope(), Actions.getCurLexicalContext(), MapperId, MapperType,637Range.getBegin(), VName, AS, MapperVarRef.get(), Clauses);638if (!IsCorrect)639return DeclGroupPtrTy();640641return DG;642}643644TypeResult Parser::parseOpenMPDeclareMapperVarDecl(SourceRange &Range,645DeclarationName &Name,646AccessSpecifier AS) {647// Parse the common declaration-specifiers piece.648Parser::DeclSpecContext DSC = Parser::DeclSpecContext::DSC_type_specifier;649DeclSpec DS(AttrFactory);650ParseSpecifierQualifierList(DS, AS, DSC);651652// Parse the declarator.653DeclaratorContext Context = DeclaratorContext::Prototype;654Declarator DeclaratorInfo(DS, ParsedAttributesView::none(), Context);655ParseDeclarator(DeclaratorInfo);656Range = DeclaratorInfo.getSourceRange();657if (DeclaratorInfo.getIdentifier() == nullptr) {658Diag(Tok.getLocation(), diag::err_omp_mapper_expected_declarator);659return true;660}661Name = Actions.GetNameForDeclarator(DeclaratorInfo).getName();662663return Actions.OpenMP().ActOnOpenMPDeclareMapperVarDecl(getCurScope(),664DeclaratorInfo);665}666667namespace {668/// RAII that recreates function context for correct parsing of clauses of669/// 'declare simd' construct.670/// OpenMP, 2.8.2 declare simd Construct671/// The expressions appearing in the clauses of this directive are evaluated in672/// the scope of the arguments of the function declaration or definition.673class FNContextRAII final {674Parser &P;675Sema::CXXThisScopeRAII *ThisScope;676Parser::MultiParseScope Scopes;677bool HasFunScope = false;678FNContextRAII() = delete;679FNContextRAII(const FNContextRAII &) = delete;680FNContextRAII &operator=(const FNContextRAII &) = delete;681682public:683FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr) : P(P), Scopes(P) {684Decl *D = *Ptr.get().begin();685NamedDecl *ND = dyn_cast<NamedDecl>(D);686RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());687Sema &Actions = P.getActions();688689// Allow 'this' within late-parsed attributes.690ThisScope = new Sema::CXXThisScopeRAII(Actions, RD, Qualifiers(),691ND && ND->isCXXInstanceMember());692693// If the Decl is templatized, add template parameters to scope.694// FIXME: Track CurTemplateDepth?695P.ReenterTemplateScopes(Scopes, D);696697// If the Decl is on a function, add function parameters to the scope.698if (D->isFunctionOrFunctionTemplate()) {699HasFunScope = true;700Scopes.Enter(Scope::FnScope | Scope::DeclScope |701Scope::CompoundStmtScope);702Actions.ActOnReenterFunctionContext(Actions.getCurScope(), D);703}704}705~FNContextRAII() {706if (HasFunScope)707P.getActions().ActOnExitFunctionContext();708delete ThisScope;709}710};711} // namespace712713/// Parses clauses for 'declare simd' directive.714/// clause:715/// 'inbranch' | 'notinbranch'716/// 'simdlen' '(' <expr> ')'717/// { 'uniform' '(' <argument_list> ')' }718/// { 'aligned '(' <argument_list> [ ':' <alignment> ] ')' }719/// { 'linear '(' <argument_list> [ ':' <step> ] ')' }720static bool parseDeclareSimdClauses(721Parser &P, OMPDeclareSimdDeclAttr::BranchStateTy &BS, ExprResult &SimdLen,722SmallVectorImpl<Expr *> &Uniforms, SmallVectorImpl<Expr *> &Aligneds,723SmallVectorImpl<Expr *> &Alignments, SmallVectorImpl<Expr *> &Linears,724SmallVectorImpl<unsigned> &LinModifiers, SmallVectorImpl<Expr *> &Steps) {725SourceRange BSRange;726const Token &Tok = P.getCurToken();727bool IsError = false;728while (Tok.isNot(tok::annot_pragma_openmp_end)) {729if (Tok.isNot(tok::identifier))730break;731OMPDeclareSimdDeclAttr::BranchStateTy Out;732IdentifierInfo *II = Tok.getIdentifierInfo();733StringRef ClauseName = II->getName();734// Parse 'inranch|notinbranch' clauses.735if (OMPDeclareSimdDeclAttr::ConvertStrToBranchStateTy(ClauseName, Out)) {736if (BS != OMPDeclareSimdDeclAttr::BS_Undefined && BS != Out) {737P.Diag(Tok, diag::err_omp_declare_simd_inbranch_notinbranch)738<< ClauseName739<< OMPDeclareSimdDeclAttr::ConvertBranchStateTyToStr(BS) << BSRange;740IsError = true;741}742BS = Out;743BSRange = SourceRange(Tok.getLocation(), Tok.getEndLoc());744P.ConsumeToken();745} else if (ClauseName == "simdlen") {746if (SimdLen.isUsable()) {747P.Diag(Tok, diag::err_omp_more_one_clause)748<< getOpenMPDirectiveName(OMPD_declare_simd) << ClauseName << 0;749IsError = true;750}751P.ConsumeToken();752SourceLocation RLoc;753SimdLen = P.ParseOpenMPParensExpr(ClauseName, RLoc);754if (SimdLen.isInvalid())755IsError = true;756} else {757OpenMPClauseKind CKind = getOpenMPClauseKind(ClauseName);758if (CKind == OMPC_uniform || CKind == OMPC_aligned ||759CKind == OMPC_linear) {760SemaOpenMP::OpenMPVarListDataTy Data;761SmallVectorImpl<Expr *> *Vars = &Uniforms;762if (CKind == OMPC_aligned) {763Vars = &Aligneds;764} else if (CKind == OMPC_linear) {765Data.ExtraModifier = OMPC_LINEAR_val;766Vars = &Linears;767}768769P.ConsumeToken();770if (P.ParseOpenMPVarList(OMPD_declare_simd,771getOpenMPClauseKind(ClauseName), *Vars, Data))772IsError = true;773if (CKind == OMPC_aligned) {774Alignments.append(Aligneds.size() - Alignments.size(),775Data.DepModOrTailExpr);776} else if (CKind == OMPC_linear) {777assert(0 <= Data.ExtraModifier &&778Data.ExtraModifier <= OMPC_LINEAR_unknown &&779"Unexpected linear modifier.");780if (P.getActions().OpenMP().CheckOpenMPLinearModifier(781static_cast<OpenMPLinearClauseKind>(Data.ExtraModifier),782Data.ExtraModifierLoc))783Data.ExtraModifier = OMPC_LINEAR_val;784LinModifiers.append(Linears.size() - LinModifiers.size(),785Data.ExtraModifier);786Steps.append(Linears.size() - Steps.size(), Data.DepModOrTailExpr);787}788} else789// TODO: add parsing of other clauses.790break;791}792// Skip ',' if any.793if (Tok.is(tok::comma))794P.ConsumeToken();795}796return IsError;797}798799/// Parse clauses for '#pragma omp declare simd'.800Parser::DeclGroupPtrTy801Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,802CachedTokens &Toks, SourceLocation Loc) {803PP.EnterToken(Tok, /*IsReinject*/ true);804PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,805/*IsReinject*/ true);806// Consume the previously pushed token.807ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);808ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);809810FNContextRAII FnContext(*this, Ptr);811OMPDeclareSimdDeclAttr::BranchStateTy BS =812OMPDeclareSimdDeclAttr::BS_Undefined;813ExprResult Simdlen;814SmallVector<Expr *, 4> Uniforms;815SmallVector<Expr *, 4> Aligneds;816SmallVector<Expr *, 4> Alignments;817SmallVector<Expr *, 4> Linears;818SmallVector<unsigned, 4> LinModifiers;819SmallVector<Expr *, 4> Steps;820bool IsError =821parseDeclareSimdClauses(*this, BS, Simdlen, Uniforms, Aligneds,822Alignments, Linears, LinModifiers, Steps);823skipUntilPragmaOpenMPEnd(OMPD_declare_simd);824// Skip the last annot_pragma_openmp_end.825SourceLocation EndLoc = ConsumeAnnotationToken();826if (IsError)827return Ptr;828return Actions.OpenMP().ActOnOpenMPDeclareSimdDirective(829Ptr, BS, Simdlen.get(), Uniforms, Aligneds, Alignments, Linears,830LinModifiers, Steps, SourceRange(Loc, EndLoc));831}832833namespace {834/// Constant used in the diagnostics to distinguish the levels in an OpenMP835/// contexts: selector-set={selector(trait, ...), ...}, ....836enum OMPContextLvl {837CONTEXT_SELECTOR_SET_LVL = 0,838CONTEXT_SELECTOR_LVL = 1,839CONTEXT_TRAIT_LVL = 2,840};841842static StringRef stringLiteralParser(Parser &P) {843ExprResult Res = P.ParseStringLiteralExpression(true);844return Res.isUsable() ? Res.getAs<StringLiteral>()->getString() : "";845}846847static StringRef getNameFromIdOrString(Parser &P, Token &Tok,848OMPContextLvl Lvl) {849if (Tok.is(tok::identifier) || Tok.is(tok::kw_for)) {850llvm::SmallString<16> Buffer;851StringRef Name = P.getPreprocessor().getSpelling(Tok, Buffer);852(void)P.ConsumeToken();853return Name;854}855856if (tok::isStringLiteral(Tok.getKind()))857return stringLiteralParser(P);858859P.Diag(Tok.getLocation(),860diag::warn_omp_declare_variant_string_literal_or_identifier)861<< Lvl;862return "";863}864865static bool checkForDuplicates(Parser &P, StringRef Name,866SourceLocation NameLoc,867llvm::StringMap<SourceLocation> &Seen,868OMPContextLvl Lvl) {869auto Res = Seen.try_emplace(Name, NameLoc);870if (Res.second)871return false;872873// Each trait-set-selector-name, trait-selector-name and trait-name can874// only be specified once.875P.Diag(NameLoc, diag::warn_omp_declare_variant_ctx_mutiple_use)876<< Lvl << Name;877P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here)878<< Lvl << Name;879return true;880}881} // namespace882883void Parser::parseOMPTraitPropertyKind(OMPTraitProperty &TIProperty,884llvm::omp::TraitSet Set,885llvm::omp::TraitSelector Selector,886llvm::StringMap<SourceLocation> &Seen) {887TIProperty.Kind = TraitProperty::invalid;888889SourceLocation NameLoc = Tok.getLocation();890StringRef Name = getNameFromIdOrString(*this, Tok, CONTEXT_TRAIT_LVL);891if (Name.empty()) {892Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options)893<< CONTEXT_TRAIT_LVL << listOpenMPContextTraitProperties(Set, Selector);894return;895}896897TIProperty.RawString = Name;898TIProperty.Kind = getOpenMPContextTraitPropertyKind(Set, Selector, Name);899if (TIProperty.Kind != TraitProperty::invalid) {900if (checkForDuplicates(*this, Name, NameLoc, Seen, CONTEXT_TRAIT_LVL))901TIProperty.Kind = TraitProperty::invalid;902return;903}904905// It follows diagnosis and helping notes.906// FIXME: We should move the diagnosis string generation into libFrontend.907Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_property)908<< Name << getOpenMPContextTraitSelectorName(Selector)909<< getOpenMPContextTraitSetName(Set);910911TraitSet SetForName = getOpenMPContextTraitSetKind(Name);912if (SetForName != TraitSet::invalid) {913Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)914<< Name << CONTEXT_SELECTOR_SET_LVL << CONTEXT_TRAIT_LVL;915Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)916<< Name << "<selector-name>"917<< "(<property-name>)";918return;919}920TraitSelector SelectorForName = getOpenMPContextTraitSelectorKind(Name);921if (SelectorForName != TraitSelector::invalid) {922Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)923<< Name << CONTEXT_SELECTOR_LVL << CONTEXT_TRAIT_LVL;924bool AllowsTraitScore = false;925bool RequiresProperty = false;926isValidTraitSelectorForTraitSet(927SelectorForName, getOpenMPContextTraitSetForSelector(SelectorForName),928AllowsTraitScore, RequiresProperty);929Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)930<< getOpenMPContextTraitSetName(931getOpenMPContextTraitSetForSelector(SelectorForName))932<< Name << (RequiresProperty ? "(<property-name>)" : "");933return;934}935for (const auto &PotentialSet :936{TraitSet::construct, TraitSet::user, TraitSet::implementation,937TraitSet::device}) {938TraitProperty PropertyForName =939getOpenMPContextTraitPropertyKind(PotentialSet, Selector, Name);940if (PropertyForName == TraitProperty::invalid)941continue;942Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)943<< getOpenMPContextTraitSetName(944getOpenMPContextTraitSetForProperty(PropertyForName))945<< getOpenMPContextTraitSelectorName(946getOpenMPContextTraitSelectorForProperty(PropertyForName))947<< ("(" + Name + ")").str();948return;949}950Diag(NameLoc, diag::note_omp_declare_variant_ctx_options)951<< CONTEXT_TRAIT_LVL << listOpenMPContextTraitProperties(Set, Selector);952}953954static bool checkExtensionProperty(Parser &P, SourceLocation Loc,955OMPTraitProperty &TIProperty,956OMPTraitSelector &TISelector,957llvm::StringMap<SourceLocation> &Seen) {958assert(TISelector.Kind ==959llvm::omp::TraitSelector::implementation_extension &&960"Only for extension properties, e.g., "961"`implementation={extension(PROPERTY)}`");962if (TIProperty.Kind == TraitProperty::invalid)963return false;964965if (TIProperty.Kind ==966TraitProperty::implementation_extension_disable_implicit_base)967return true;968969if (TIProperty.Kind ==970TraitProperty::implementation_extension_allow_templates)971return true;972973if (TIProperty.Kind ==974TraitProperty::implementation_extension_bind_to_declaration)975return true;976977auto IsMatchExtension = [](OMPTraitProperty &TP) {978return (TP.Kind ==979llvm::omp::TraitProperty::implementation_extension_match_all ||980TP.Kind ==981llvm::omp::TraitProperty::implementation_extension_match_any ||982TP.Kind ==983llvm::omp::TraitProperty::implementation_extension_match_none);984};985986if (IsMatchExtension(TIProperty)) {987for (OMPTraitProperty &SeenProp : TISelector.Properties)988if (IsMatchExtension(SeenProp)) {989P.Diag(Loc, diag::err_omp_variant_ctx_second_match_extension);990StringRef SeenName = llvm::omp::getOpenMPContextTraitPropertyName(991SeenProp.Kind, SeenProp.RawString);992SourceLocation SeenLoc = Seen[SeenName];993P.Diag(SeenLoc, diag::note_omp_declare_variant_ctx_used_here)994<< CONTEXT_TRAIT_LVL << SeenName;995return false;996}997return true;998}9991000llvm_unreachable("Unknown extension property!");1001}10021003void Parser::parseOMPContextProperty(OMPTraitSelector &TISelector,1004llvm::omp::TraitSet Set,1005llvm::StringMap<SourceLocation> &Seen) {1006assert(TISelector.Kind != TraitSelector::user_condition &&1007"User conditions are special properties not handled here!");10081009SourceLocation PropertyLoc = Tok.getLocation();1010OMPTraitProperty TIProperty;1011parseOMPTraitPropertyKind(TIProperty, Set, TISelector.Kind, Seen);10121013if (TISelector.Kind == llvm::omp::TraitSelector::implementation_extension)1014if (!checkExtensionProperty(*this, Tok.getLocation(), TIProperty,1015TISelector, Seen))1016TIProperty.Kind = TraitProperty::invalid;10171018// If we have an invalid property here we already issued a warning.1019if (TIProperty.Kind == TraitProperty::invalid) {1020if (PropertyLoc != Tok.getLocation())1021Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here)1022<< CONTEXT_TRAIT_LVL;1023return;1024}10251026if (isValidTraitPropertyForTraitSetAndSelector(TIProperty.Kind,1027TISelector.Kind, Set)) {10281029// If we make it here the property, selector, set, score, condition, ... are1030// all valid (or have been corrected). Thus we can record the property.1031TISelector.Properties.push_back(TIProperty);1032return;1033}10341035Diag(PropertyLoc, diag::warn_omp_ctx_incompatible_property_for_selector)1036<< getOpenMPContextTraitPropertyName(TIProperty.Kind,1037TIProperty.RawString)1038<< getOpenMPContextTraitSelectorName(TISelector.Kind)1039<< getOpenMPContextTraitSetName(Set);1040Diag(PropertyLoc, diag::note_omp_ctx_compatible_set_and_selector_for_property)1041<< getOpenMPContextTraitPropertyName(TIProperty.Kind,1042TIProperty.RawString)1043<< getOpenMPContextTraitSelectorName(1044getOpenMPContextTraitSelectorForProperty(TIProperty.Kind))1045<< getOpenMPContextTraitSetName(1046getOpenMPContextTraitSetForProperty(TIProperty.Kind));1047Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here)1048<< CONTEXT_TRAIT_LVL;1049}10501051void Parser::parseOMPTraitSelectorKind(OMPTraitSelector &TISelector,1052llvm::omp::TraitSet Set,1053llvm::StringMap<SourceLocation> &Seen) {1054TISelector.Kind = TraitSelector::invalid;10551056SourceLocation NameLoc = Tok.getLocation();1057StringRef Name = getNameFromIdOrString(*this, Tok, CONTEXT_SELECTOR_LVL);1058if (Name.empty()) {1059Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options)1060<< CONTEXT_SELECTOR_LVL << listOpenMPContextTraitSelectors(Set);1061return;1062}10631064TISelector.Kind = getOpenMPContextTraitSelectorKind(Name);1065if (TISelector.Kind != TraitSelector::invalid) {1066if (checkForDuplicates(*this, Name, NameLoc, Seen, CONTEXT_SELECTOR_LVL))1067TISelector.Kind = TraitSelector::invalid;1068return;1069}10701071// It follows diagnosis and helping notes.1072Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_selector)1073<< Name << getOpenMPContextTraitSetName(Set);10741075TraitSet SetForName = getOpenMPContextTraitSetKind(Name);1076if (SetForName != TraitSet::invalid) {1077Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)1078<< Name << CONTEXT_SELECTOR_SET_LVL << CONTEXT_SELECTOR_LVL;1079Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)1080<< Name << "<selector-name>"1081<< "<property-name>";1082return;1083}1084for (const auto &PotentialSet :1085{TraitSet::construct, TraitSet::user, TraitSet::implementation,1086TraitSet::device}) {1087TraitProperty PropertyForName = getOpenMPContextTraitPropertyKind(1088PotentialSet, TraitSelector::invalid, Name);1089if (PropertyForName == TraitProperty::invalid)1090continue;1091Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)1092<< Name << CONTEXT_TRAIT_LVL << CONTEXT_SELECTOR_LVL;1093Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)1094<< getOpenMPContextTraitSetName(1095getOpenMPContextTraitSetForProperty(PropertyForName))1096<< getOpenMPContextTraitSelectorName(1097getOpenMPContextTraitSelectorForProperty(PropertyForName))1098<< ("(" + Name + ")").str();1099return;1100}1101Diag(NameLoc, diag::note_omp_declare_variant_ctx_options)1102<< CONTEXT_SELECTOR_LVL << listOpenMPContextTraitSelectors(Set);1103}11041105/// Parse optional 'score' '(' <expr> ')' ':'.1106static ExprResult parseContextScore(Parser &P) {1107ExprResult ScoreExpr;1108llvm::SmallString<16> Buffer;1109StringRef SelectorName =1110P.getPreprocessor().getSpelling(P.getCurToken(), Buffer);1111if (SelectorName != "score")1112return ScoreExpr;1113(void)P.ConsumeToken();1114SourceLocation RLoc;1115ScoreExpr = P.ParseOpenMPParensExpr(SelectorName, RLoc);1116// Parse ':'1117if (P.getCurToken().is(tok::colon))1118(void)P.ConsumeAnyToken();1119else1120P.Diag(P.getCurToken(), diag::warn_omp_declare_variant_expected)1121<< "':'"1122<< "score expression";1123return ScoreExpr;1124}11251126/// Parses an OpenMP context selector.1127///1128/// <trait-selector-name> ['('[<trait-score>] <trait-property> [, <t-p>]* ')']1129void Parser::parseOMPContextSelector(1130OMPTraitSelector &TISelector, llvm::omp::TraitSet Set,1131llvm::StringMap<SourceLocation> &SeenSelectors) {1132unsigned short OuterPC = ParenCount;11331134// If anything went wrong we issue an error or warning and then skip the rest1135// of the selector. However, commas are ambiguous so we look for the nesting1136// of parentheses here as well.1137auto FinishSelector = [OuterPC, this]() -> void {1138bool Done = false;1139while (!Done) {1140while (!SkipUntil({tok::r_brace, tok::r_paren, tok::comma,1141tok::annot_pragma_openmp_end},1142StopBeforeMatch))1143;1144if (Tok.is(tok::r_paren) && OuterPC > ParenCount)1145(void)ConsumeParen();1146if (OuterPC <= ParenCount) {1147Done = true;1148break;1149}1150if (!Tok.is(tok::comma) && !Tok.is(tok::r_paren)) {1151Done = true;1152break;1153}1154(void)ConsumeAnyToken();1155}1156Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here)1157<< CONTEXT_SELECTOR_LVL;1158};11591160SourceLocation SelectorLoc = Tok.getLocation();1161parseOMPTraitSelectorKind(TISelector, Set, SeenSelectors);1162if (TISelector.Kind == TraitSelector::invalid)1163return FinishSelector();11641165bool AllowsTraitScore = false;1166bool RequiresProperty = false;1167if (!isValidTraitSelectorForTraitSet(TISelector.Kind, Set, AllowsTraitScore,1168RequiresProperty)) {1169Diag(SelectorLoc, diag::warn_omp_ctx_incompatible_selector_for_set)1170<< getOpenMPContextTraitSelectorName(TISelector.Kind)1171<< getOpenMPContextTraitSetName(Set);1172Diag(SelectorLoc, diag::note_omp_ctx_compatible_set_for_selector)1173<< getOpenMPContextTraitSelectorName(TISelector.Kind)1174<< getOpenMPContextTraitSetName(1175getOpenMPContextTraitSetForSelector(TISelector.Kind))1176<< RequiresProperty;1177return FinishSelector();1178}11791180if (!RequiresProperty) {1181TISelector.Properties.push_back(1182{getOpenMPContextTraitPropertyForSelector(TISelector.Kind),1183getOpenMPContextTraitSelectorName(TISelector.Kind)});1184return;1185}11861187if (!Tok.is(tok::l_paren)) {1188Diag(SelectorLoc, diag::warn_omp_ctx_selector_without_properties)1189<< getOpenMPContextTraitSelectorName(TISelector.Kind)1190<< getOpenMPContextTraitSetName(Set);1191return FinishSelector();1192}11931194if (TISelector.Kind == TraitSelector::user_condition) {1195SourceLocation RLoc;1196ExprResult Condition = ParseOpenMPParensExpr("user condition", RLoc);1197if (!Condition.isUsable())1198return FinishSelector();1199TISelector.ScoreOrCondition = Condition.get();1200TISelector.Properties.push_back(1201{TraitProperty::user_condition_unknown, "<condition>"});1202return;1203}12041205BalancedDelimiterTracker BDT(*this, tok::l_paren,1206tok::annot_pragma_openmp_end);1207// Parse '('.1208(void)BDT.consumeOpen();12091210SourceLocation ScoreLoc = Tok.getLocation();1211ExprResult Score = parseContextScore(*this);12121213if (!AllowsTraitScore && !Score.isUnset()) {1214if (Score.isUsable()) {1215Diag(ScoreLoc, diag::warn_omp_ctx_incompatible_score_for_property)1216<< getOpenMPContextTraitSelectorName(TISelector.Kind)1217<< getOpenMPContextTraitSetName(Set) << Score.get();1218} else {1219Diag(ScoreLoc, diag::warn_omp_ctx_incompatible_score_for_property)1220<< getOpenMPContextTraitSelectorName(TISelector.Kind)1221<< getOpenMPContextTraitSetName(Set) << "<invalid>";1222}1223Score = ExprResult();1224}12251226if (Score.isUsable())1227TISelector.ScoreOrCondition = Score.get();12281229llvm::StringMap<SourceLocation> SeenProperties;1230do {1231parseOMPContextProperty(TISelector, Set, SeenProperties);1232} while (TryConsumeToken(tok::comma));12331234// Parse ')'.1235BDT.consumeClose();1236}12371238void Parser::parseOMPTraitSetKind(OMPTraitSet &TISet,1239llvm::StringMap<SourceLocation> &Seen) {1240TISet.Kind = TraitSet::invalid;12411242SourceLocation NameLoc = Tok.getLocation();1243StringRef Name = getNameFromIdOrString(*this, Tok, CONTEXT_SELECTOR_SET_LVL);1244if (Name.empty()) {1245Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options)1246<< CONTEXT_SELECTOR_SET_LVL << listOpenMPContextTraitSets();1247return;1248}12491250TISet.Kind = getOpenMPContextTraitSetKind(Name);1251if (TISet.Kind != TraitSet::invalid) {1252if (checkForDuplicates(*this, Name, NameLoc, Seen,1253CONTEXT_SELECTOR_SET_LVL))1254TISet.Kind = TraitSet::invalid;1255return;1256}12571258// It follows diagnosis and helping notes.1259Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_set) << Name;12601261TraitSelector SelectorForName = getOpenMPContextTraitSelectorKind(Name);1262if (SelectorForName != TraitSelector::invalid) {1263Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)1264<< Name << CONTEXT_SELECTOR_LVL << CONTEXT_SELECTOR_SET_LVL;1265bool AllowsTraitScore = false;1266bool RequiresProperty = false;1267isValidTraitSelectorForTraitSet(1268SelectorForName, getOpenMPContextTraitSetForSelector(SelectorForName),1269AllowsTraitScore, RequiresProperty);1270Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)1271<< getOpenMPContextTraitSetName(1272getOpenMPContextTraitSetForSelector(SelectorForName))1273<< Name << (RequiresProperty ? "(<property-name>)" : "");1274return;1275}1276for (const auto &PotentialSet :1277{TraitSet::construct, TraitSet::user, TraitSet::implementation,1278TraitSet::device}) {1279TraitProperty PropertyForName = getOpenMPContextTraitPropertyKind(1280PotentialSet, TraitSelector::invalid, Name);1281if (PropertyForName == TraitProperty::invalid)1282continue;1283Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)1284<< Name << CONTEXT_TRAIT_LVL << CONTEXT_SELECTOR_SET_LVL;1285Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)1286<< getOpenMPContextTraitSetName(1287getOpenMPContextTraitSetForProperty(PropertyForName))1288<< getOpenMPContextTraitSelectorName(1289getOpenMPContextTraitSelectorForProperty(PropertyForName))1290<< ("(" + Name + ")").str();1291return;1292}1293Diag(NameLoc, diag::note_omp_declare_variant_ctx_options)1294<< CONTEXT_SELECTOR_SET_LVL << listOpenMPContextTraitSets();1295}12961297/// Parses an OpenMP context selector set.1298///1299/// <trait-set-selector-name> '=' '{' <trait-selector> [, <trait-selector>]* '}'1300void Parser::parseOMPContextSelectorSet(1301OMPTraitSet &TISet, llvm::StringMap<SourceLocation> &SeenSets) {1302auto OuterBC = BraceCount;13031304// If anything went wrong we issue an error or warning and then skip the rest1305// of the set. However, commas are ambiguous so we look for the nesting1306// of braces here as well.1307auto FinishSelectorSet = [this, OuterBC]() -> void {1308bool Done = false;1309while (!Done) {1310while (!SkipUntil({tok::comma, tok::r_brace, tok::r_paren,1311tok::annot_pragma_openmp_end},1312StopBeforeMatch))1313;1314if (Tok.is(tok::r_brace) && OuterBC > BraceCount)1315(void)ConsumeBrace();1316if (OuterBC <= BraceCount) {1317Done = true;1318break;1319}1320if (!Tok.is(tok::comma) && !Tok.is(tok::r_brace)) {1321Done = true;1322break;1323}1324(void)ConsumeAnyToken();1325}1326Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here)1327<< CONTEXT_SELECTOR_SET_LVL;1328};13291330parseOMPTraitSetKind(TISet, SeenSets);1331if (TISet.Kind == TraitSet::invalid)1332return FinishSelectorSet();13331334// Parse '='.1335if (!TryConsumeToken(tok::equal))1336Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected)1337<< "="1338<< ("context set name \"" + getOpenMPContextTraitSetName(TISet.Kind) +1339"\"")1340.str();13411342// Parse '{'.1343if (Tok.is(tok::l_brace)) {1344(void)ConsumeBrace();1345} else {1346Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected)1347<< "{"1348<< ("'=' that follows the context set name \"" +1349getOpenMPContextTraitSetName(TISet.Kind) + "\"")1350.str();1351}13521353llvm::StringMap<SourceLocation> SeenSelectors;1354do {1355OMPTraitSelector TISelector;1356parseOMPContextSelector(TISelector, TISet.Kind, SeenSelectors);1357if (TISelector.Kind != TraitSelector::invalid &&1358!TISelector.Properties.empty())1359TISet.Selectors.push_back(TISelector);1360} while (TryConsumeToken(tok::comma));13611362// Parse '}'.1363if (Tok.is(tok::r_brace)) {1364(void)ConsumeBrace();1365} else {1366Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected)1367<< "}"1368<< ("context selectors for the context set \"" +1369getOpenMPContextTraitSetName(TISet.Kind) + "\"")1370.str();1371}1372}13731374/// Parse OpenMP context selectors:1375///1376/// <trait-set-selector> [, <trait-set-selector>]*1377bool Parser::parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo &TI) {1378llvm::StringMap<SourceLocation> SeenSets;1379do {1380OMPTraitSet TISet;1381parseOMPContextSelectorSet(TISet, SeenSets);1382if (TISet.Kind != TraitSet::invalid && !TISet.Selectors.empty())1383TI.Sets.push_back(TISet);1384} while (TryConsumeToken(tok::comma));13851386return false;1387}13881389/// Parse clauses for '#pragma omp declare variant ( variant-func-id ) clause'.1390void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,1391CachedTokens &Toks,1392SourceLocation Loc) {1393PP.EnterToken(Tok, /*IsReinject*/ true);1394PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,1395/*IsReinject*/ true);1396// Consume the previously pushed token.1397ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);1398ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);13991400FNContextRAII FnContext(*this, Ptr);1401// Parse function declaration id.1402SourceLocation RLoc;1403// Parse with IsAddressOfOperand set to true to parse methods as DeclRefExprs1404// instead of MemberExprs.1405ExprResult AssociatedFunction;1406{1407// Do not mark function as is used to prevent its emission if this is the1408// only place where it is used.1409EnterExpressionEvaluationContext Unevaluated(1410Actions, Sema::ExpressionEvaluationContext::Unevaluated);1411AssociatedFunction = ParseOpenMPParensExpr(1412getOpenMPDirectiveName(OMPD_declare_variant), RLoc,1413/*IsAddressOfOperand=*/true);1414}1415if (!AssociatedFunction.isUsable()) {1416if (!Tok.is(tok::annot_pragma_openmp_end))1417while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch))1418;1419// Skip the last annot_pragma_openmp_end.1420(void)ConsumeAnnotationToken();1421return;1422}14231424OMPTraitInfo *ParentTI =1425Actions.OpenMP().getOMPTraitInfoForSurroundingScope();1426ASTContext &ASTCtx = Actions.getASTContext();1427OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo();1428SmallVector<Expr *, 6> AdjustNothing;1429SmallVector<Expr *, 6> AdjustNeedDevicePtr;1430SmallVector<OMPInteropInfo, 3> AppendArgs;1431SourceLocation AdjustArgsLoc, AppendArgsLoc;14321433// At least one clause is required.1434if (Tok.is(tok::annot_pragma_openmp_end)) {1435Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause)1436<< (getLangOpts().OpenMP < 51 ? 0 : 1);1437}14381439bool IsError = false;1440while (Tok.isNot(tok::annot_pragma_openmp_end)) {1441OpenMPClauseKind CKind = Tok.isAnnotation()1442? OMPC_unknown1443: getOpenMPClauseKind(PP.getSpelling(Tok));1444if (!isAllowedClauseForDirective(OMPD_declare_variant, CKind,1445getLangOpts().OpenMP)) {1446Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause)1447<< (getLangOpts().OpenMP < 51 ? 0 : 1);1448IsError = true;1449}1450if (!IsError) {1451switch (CKind) {1452case OMPC_match:1453IsError = parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI);1454break;1455case OMPC_adjust_args: {1456AdjustArgsLoc = Tok.getLocation();1457ConsumeToken();1458SemaOpenMP::OpenMPVarListDataTy Data;1459SmallVector<Expr *> Vars;1460IsError = ParseOpenMPVarList(OMPD_declare_variant, OMPC_adjust_args,1461Vars, Data);1462if (!IsError)1463llvm::append_range(Data.ExtraModifier == OMPC_ADJUST_ARGS_nothing1464? AdjustNothing1465: AdjustNeedDevicePtr,1466Vars);1467break;1468}1469case OMPC_append_args:1470if (!AppendArgs.empty()) {1471Diag(AppendArgsLoc, diag::err_omp_more_one_clause)1472<< getOpenMPDirectiveName(OMPD_declare_variant)1473<< getOpenMPClauseName(CKind) << 0;1474IsError = true;1475}1476if (!IsError) {1477AppendArgsLoc = Tok.getLocation();1478ConsumeToken();1479IsError = parseOpenMPAppendArgs(AppendArgs);1480}1481break;1482default:1483llvm_unreachable("Unexpected clause for declare variant.");1484}1485}1486if (IsError) {1487while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch))1488;1489// Skip the last annot_pragma_openmp_end.1490(void)ConsumeAnnotationToken();1491return;1492}1493// Skip ',' if any.1494if (Tok.is(tok::comma))1495ConsumeToken();1496}14971498std::optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =1499Actions.OpenMP().checkOpenMPDeclareVariantFunction(1500Ptr, AssociatedFunction.get(), TI, AppendArgs.size(),1501SourceRange(Loc, Tok.getLocation()));15021503if (DeclVarData && !TI.Sets.empty())1504Actions.OpenMP().ActOnOpenMPDeclareVariantDirective(1505DeclVarData->first, DeclVarData->second, TI, AdjustNothing,1506AdjustNeedDevicePtr, AppendArgs, AdjustArgsLoc, AppendArgsLoc,1507SourceRange(Loc, Tok.getLocation()));15081509// Skip the last annot_pragma_openmp_end.1510(void)ConsumeAnnotationToken();1511}15121513bool Parser::parseOpenMPAppendArgs(1514SmallVectorImpl<OMPInteropInfo> &InteropInfos) {1515bool HasError = false;1516// Parse '('.1517BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);1518if (T.expectAndConsume(diag::err_expected_lparen_after,1519getOpenMPClauseName(OMPC_append_args).data()))1520return true;15211522// Parse the list of append-ops, each is;1523// interop(interop-type[,interop-type]...)1524while (Tok.is(tok::identifier) && Tok.getIdentifierInfo()->isStr("interop")) {1525ConsumeToken();1526BalancedDelimiterTracker IT(*this, tok::l_paren,1527tok::annot_pragma_openmp_end);1528if (IT.expectAndConsume(diag::err_expected_lparen_after, "interop"))1529return true;15301531OMPInteropInfo InteropInfo;1532if (ParseOMPInteropInfo(InteropInfo, OMPC_append_args))1533HasError = true;1534else1535InteropInfos.push_back(InteropInfo);15361537IT.consumeClose();1538if (Tok.is(tok::comma))1539ConsumeToken();1540}1541if (!HasError && InteropInfos.empty()) {1542HasError = true;1543Diag(Tok.getLocation(), diag::err_omp_unexpected_append_op);1544SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,1545StopBeforeMatch);1546}1547HasError = T.consumeClose() || HasError;1548return HasError;1549}15501551bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc,1552OMPTraitInfo &TI,1553OMPTraitInfo *ParentTI) {1554// Parse 'match'.1555OpenMPClauseKind CKind = Tok.isAnnotation()1556? OMPC_unknown1557: getOpenMPClauseKind(PP.getSpelling(Tok));1558if (CKind != OMPC_match) {1559Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause)1560<< (getLangOpts().OpenMP < 51 ? 0 : 1);1561return true;1562}1563(void)ConsumeToken();1564// Parse '('.1565BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);1566if (T.expectAndConsume(diag::err_expected_lparen_after,1567getOpenMPClauseName(OMPC_match).data()))1568return true;15691570// Parse inner context selectors.1571parseOMPContextSelectors(Loc, TI);15721573// Parse ')'1574(void)T.consumeClose();15751576if (!ParentTI)1577return false;15781579// Merge the parent/outer trait info into the one we just parsed and diagnose1580// problems.1581// TODO: Keep some source location in the TI to provide better diagnostics.1582// TODO: Perform some kind of equivalence check on the condition and score1583// expressions.1584for (const OMPTraitSet &ParentSet : ParentTI->Sets) {1585bool MergedSet = false;1586for (OMPTraitSet &Set : TI.Sets) {1587if (Set.Kind != ParentSet.Kind)1588continue;1589MergedSet = true;1590for (const OMPTraitSelector &ParentSelector : ParentSet.Selectors) {1591bool MergedSelector = false;1592for (OMPTraitSelector &Selector : Set.Selectors) {1593if (Selector.Kind != ParentSelector.Kind)1594continue;1595MergedSelector = true;1596for (const OMPTraitProperty &ParentProperty :1597ParentSelector.Properties) {1598bool MergedProperty = false;1599for (OMPTraitProperty &Property : Selector.Properties) {1600// Ignore "equivalent" properties.1601if (Property.Kind != ParentProperty.Kind)1602continue;16031604// If the kind is the same but the raw string not, we don't want1605// to skip out on the property.1606MergedProperty |= Property.RawString == ParentProperty.RawString;16071608if (Property.RawString == ParentProperty.RawString &&1609Selector.ScoreOrCondition == ParentSelector.ScoreOrCondition)1610continue;16111612if (Selector.Kind == llvm::omp::TraitSelector::user_condition) {1613Diag(Loc, diag::err_omp_declare_variant_nested_user_condition);1614} else if (Selector.ScoreOrCondition !=1615ParentSelector.ScoreOrCondition) {1616Diag(Loc, diag::err_omp_declare_variant_duplicate_nested_trait)1617<< getOpenMPContextTraitPropertyName(1618ParentProperty.Kind, ParentProperty.RawString)1619<< getOpenMPContextTraitSelectorName(ParentSelector.Kind)1620<< getOpenMPContextTraitSetName(ParentSet.Kind);1621}1622}1623if (!MergedProperty)1624Selector.Properties.push_back(ParentProperty);1625}1626}1627if (!MergedSelector)1628Set.Selectors.push_back(ParentSelector);1629}1630}1631if (!MergedSet)1632TI.Sets.push_back(ParentSet);1633}16341635return false;1636}16371638/// <clause> [clause[ [,] clause] ... ]1639///1640/// clauses: for error directive1641/// 'at' '(' compilation | execution ')'1642/// 'severity' '(' fatal | warning ')'1643/// 'message' '(' msg-string ')'1644/// ....1645void Parser::ParseOpenMPClauses(OpenMPDirectiveKind DKind,1646SmallVectorImpl<OMPClause *> &Clauses,1647SourceLocation Loc) {1648std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses;1649while (Tok.isNot(tok::annot_pragma_openmp_end)) {1650OpenMPClauseKind CKind = Tok.isAnnotation()1651? OMPC_unknown1652: getOpenMPClauseKind(PP.getSpelling(Tok));1653Actions.OpenMP().StartOpenMPClause(CKind);1654OMPClause *Clause =1655ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]);1656SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,1657StopBeforeMatch);1658SeenClauses[unsigned(CKind)] = true;1659if (Clause != nullptr)1660Clauses.push_back(Clause);1661if (Tok.is(tok::annot_pragma_openmp_end)) {1662Actions.OpenMP().EndOpenMPClause();1663break;1664}1665// Skip ',' if any.1666if (Tok.is(tok::comma))1667ConsumeToken();1668Actions.OpenMP().EndOpenMPClause();1669}1670}16711672/// `omp assumes` or `omp begin/end assumes` <clause> [[,]<clause>]...1673/// where1674///1675/// clause:1676/// 'ext_IMPL_DEFINED'1677/// 'absent' '(' directive-name [, directive-name]* ')'1678/// 'contains' '(' directive-name [, directive-name]* ')'1679/// 'holds' '(' scalar-expression ')'1680/// 'no_openmp'1681/// 'no_openmp_routines'1682/// 'no_parallelism'1683///1684void Parser::ParseOpenMPAssumesDirective(OpenMPDirectiveKind DKind,1685SourceLocation Loc) {1686SmallVector<std::string, 4> Assumptions;1687bool SkippedClauses = false;16881689auto SkipBraces = [&](llvm::StringRef Spelling, bool IssueNote) {1690BalancedDelimiterTracker T(*this, tok::l_paren,1691tok::annot_pragma_openmp_end);1692if (T.expectAndConsume(diag::err_expected_lparen_after, Spelling.data()))1693return;1694T.skipToEnd();1695if (IssueNote && T.getCloseLocation().isValid())1696Diag(T.getCloseLocation(),1697diag::note_omp_assumption_clause_continue_here);1698};16991700/// Helper to determine which AssumptionClauseMapping (ACM) in the1701/// AssumptionClauseMappings table matches \p RawString. The return value is1702/// the index of the matching ACM into the table or -1 if there was no match.1703auto MatchACMClause = [&](StringRef RawString) {1704llvm::StringSwitch<int> SS(RawString);1705unsigned ACMIdx = 0;1706for (const AssumptionClauseMappingInfo &ACMI : AssumptionClauseMappings) {1707if (ACMI.StartsWith)1708SS.StartsWith(ACMI.Identifier, ACMIdx++);1709else1710SS.Case(ACMI.Identifier, ACMIdx++);1711}1712return SS.Default(-1);1713};17141715while (Tok.isNot(tok::annot_pragma_openmp_end)) {1716IdentifierInfo *II = nullptr;1717SourceLocation StartLoc = Tok.getLocation();1718int Idx = -1;1719if (Tok.isAnyIdentifier()) {1720II = Tok.getIdentifierInfo();1721Idx = MatchACMClause(II->getName());1722}1723ConsumeAnyToken();17241725bool NextIsLPar = Tok.is(tok::l_paren);1726// Handle unknown clauses by skipping them.1727if (Idx == -1) {1728Diag(StartLoc, diag::warn_omp_unknown_assumption_clause_missing_id)1729<< llvm::omp::getOpenMPDirectiveName(DKind)1730<< llvm::omp::getAllAssumeClauseOptions() << NextIsLPar;1731if (NextIsLPar)1732SkipBraces(II ? II->getName() : "", /* IssueNote */ true);1733SkippedClauses = true;1734continue;1735}1736const AssumptionClauseMappingInfo &ACMI = AssumptionClauseMappings[Idx];1737if (ACMI.HasDirectiveList || ACMI.HasExpression) {1738// TODO: We ignore absent, contains, and holds assumptions for now. We1739// also do not verify the content in the parenthesis at all.1740SkippedClauses = true;1741SkipBraces(II->getName(), /* IssueNote */ false);1742continue;1743}17441745if (NextIsLPar) {1746Diag(Tok.getLocation(),1747diag::warn_omp_unknown_assumption_clause_without_args)1748<< II;1749SkipBraces(II->getName(), /* IssueNote */ true);1750}17511752assert(II && "Expected an identifier clause!");1753std::string Assumption = II->getName().str();1754if (ACMI.StartsWith)1755Assumption = "ompx_" + Assumption.substr(ACMI.Identifier.size());1756else1757Assumption = "omp_" + Assumption;1758Assumptions.push_back(Assumption);1759}17601761Actions.OpenMP().ActOnOpenMPAssumesDirective(Loc, DKind, Assumptions,1762SkippedClauses);1763}17641765void Parser::ParseOpenMPEndAssumesDirective(SourceLocation Loc) {1766if (Actions.OpenMP().isInOpenMPAssumeScope())1767Actions.OpenMP().ActOnOpenMPEndAssumesDirective();1768else1769Diag(Loc, diag::err_expected_begin_assumes);1770}17711772/// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.1773///1774/// default-clause:1775/// 'default' '(' 'none' | 'shared' | 'private' | 'firstprivate' ')1776///1777/// proc_bind-clause:1778/// 'proc_bind' '(' 'master' | 'close' | 'spread' ')1779///1780/// device_type-clause:1781/// 'device_type' '(' 'host' | 'nohost' | 'any' )'1782namespace {1783struct SimpleClauseData {1784unsigned Type;1785SourceLocation Loc;1786SourceLocation LOpen;1787SourceLocation TypeLoc;1788SourceLocation RLoc;1789SimpleClauseData(unsigned Type, SourceLocation Loc, SourceLocation LOpen,1790SourceLocation TypeLoc, SourceLocation RLoc)1791: Type(Type), Loc(Loc), LOpen(LOpen), TypeLoc(TypeLoc), RLoc(RLoc) {}1792};1793} // anonymous namespace17941795static std::optional<SimpleClauseData>1796parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) {1797const Token &Tok = P.getCurToken();1798SourceLocation Loc = Tok.getLocation();1799SourceLocation LOpen = P.ConsumeToken();1800// Parse '('.1801BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end);1802if (T.expectAndConsume(diag::err_expected_lparen_after,1803getOpenMPClauseName(Kind).data()))1804return std::nullopt;18051806unsigned Type = getOpenMPSimpleClauseType(1807Kind, Tok.isAnnotation() ? "" : P.getPreprocessor().getSpelling(Tok),1808P.getLangOpts());1809SourceLocation TypeLoc = Tok.getLocation();1810if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&1811Tok.isNot(tok::annot_pragma_openmp_end))1812P.ConsumeAnyToken();18131814// Parse ')'.1815SourceLocation RLoc = Tok.getLocation();1816if (!T.consumeClose())1817RLoc = T.getCloseLocation();18181819return SimpleClauseData(Type, Loc, LOpen, TypeLoc, RLoc);1820}18211822void Parser::ParseOMPDeclareTargetClauses(1823SemaOpenMP::DeclareTargetContextInfo &DTCI) {1824SourceLocation DeviceTypeLoc;1825bool RequiresToOrLinkOrIndirectClause = false;1826bool HasToOrLinkOrIndirectClause = false;1827while (Tok.isNot(tok::annot_pragma_openmp_end)) {1828OMPDeclareTargetDeclAttr::MapTypeTy MT = OMPDeclareTargetDeclAttr::MT_To;1829bool HasIdentifier = Tok.is(tok::identifier);1830if (HasIdentifier) {1831// If we see any clause we need a to or link clause.1832RequiresToOrLinkOrIndirectClause = true;1833IdentifierInfo *II = Tok.getIdentifierInfo();1834StringRef ClauseName = II->getName();1835bool IsDeviceTypeClause =1836getLangOpts().OpenMP >= 50 &&1837getOpenMPClauseKind(ClauseName) == OMPC_device_type;18381839bool IsIndirectClause = getLangOpts().OpenMP >= 51 &&1840getOpenMPClauseKind(ClauseName) == OMPC_indirect;1841if (DTCI.Indirect && IsIndirectClause) {1842Diag(Tok, diag::err_omp_more_one_clause)1843<< getOpenMPDirectiveName(OMPD_declare_target)1844<< getOpenMPClauseName(OMPC_indirect) << 0;1845break;1846}1847bool IsToEnterOrLinkClause =1848OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT);1849assert((!IsDeviceTypeClause || !IsToEnterOrLinkClause) &&1850"Cannot be both!");18511852// Starting with OpenMP 5.2 the `to` clause has been replaced by the1853// `enter` clause.1854if (getLangOpts().OpenMP >= 52 && ClauseName == "to") {1855Diag(Tok, diag::err_omp_declare_target_unexpected_to_clause);1856break;1857}1858if (getLangOpts().OpenMP <= 51 && ClauseName == "enter") {1859Diag(Tok, diag::err_omp_declare_target_unexpected_enter_clause);1860break;1861}18621863if (!IsDeviceTypeClause && !IsIndirectClause &&1864DTCI.Kind == OMPD_begin_declare_target) {1865Diag(Tok, diag::err_omp_declare_target_unexpected_clause)1866<< ClauseName << (getLangOpts().OpenMP >= 51 ? 3 : 0);1867break;1868}1869if (!IsDeviceTypeClause && !IsToEnterOrLinkClause && !IsIndirectClause) {1870Diag(Tok, getLangOpts().OpenMP >= 521871? diag::err_omp_declare_target_unexpected_clause_521872: diag::err_omp_declare_target_unexpected_clause)1873<< ClauseName1874<< (getLangOpts().OpenMP >= 511875? 41876: getLangOpts().OpenMP >= 50 ? 2 : 1);1877break;1878}18791880if (IsToEnterOrLinkClause || IsIndirectClause)1881HasToOrLinkOrIndirectClause = true;18821883if (IsIndirectClause) {1884if (!ParseOpenMPIndirectClause(DTCI, /*ParseOnly*/ false))1885break;1886continue;1887}1888// Parse 'device_type' clause and go to next clause if any.1889if (IsDeviceTypeClause) {1890std::optional<SimpleClauseData> DevTypeData =1891parseOpenMPSimpleClause(*this, OMPC_device_type);1892if (DevTypeData) {1893if (DeviceTypeLoc.isValid()) {1894// We already saw another device_type clause, diagnose it.1895Diag(DevTypeData->Loc,1896diag::warn_omp_more_one_device_type_clause);1897break;1898}1899switch (static_cast<OpenMPDeviceType>(DevTypeData->Type)) {1900case OMPC_DEVICE_TYPE_any:1901DTCI.DT = OMPDeclareTargetDeclAttr::DT_Any;1902break;1903case OMPC_DEVICE_TYPE_host:1904DTCI.DT = OMPDeclareTargetDeclAttr::DT_Host;1905break;1906case OMPC_DEVICE_TYPE_nohost:1907DTCI.DT = OMPDeclareTargetDeclAttr::DT_NoHost;1908break;1909case OMPC_DEVICE_TYPE_unknown:1910llvm_unreachable("Unexpected device_type");1911}1912DeviceTypeLoc = DevTypeData->Loc;1913}1914continue;1915}1916ConsumeToken();1917}19181919if (DTCI.Kind == OMPD_declare_target || HasIdentifier) {1920auto &&Callback = [this, MT, &DTCI](CXXScopeSpec &SS,1921DeclarationNameInfo NameInfo) {1922NamedDecl *ND = Actions.OpenMP().lookupOpenMPDeclareTargetName(1923getCurScope(), SS, NameInfo);1924if (!ND)1925return;1926SemaOpenMP::DeclareTargetContextInfo::MapInfo MI{MT, NameInfo.getLoc()};1927bool FirstMapping = DTCI.ExplicitlyMapped.try_emplace(ND, MI).second;1928if (!FirstMapping)1929Diag(NameInfo.getLoc(), diag::err_omp_declare_target_multiple)1930<< NameInfo.getName();1931};1932if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback,1933/*AllowScopeSpecifier=*/true))1934break;1935}19361937if (Tok.is(tok::l_paren)) {1938Diag(Tok,1939diag::err_omp_begin_declare_target_unexpected_implicit_to_clause);1940break;1941}1942if (!HasIdentifier && Tok.isNot(tok::annot_pragma_openmp_end)) {1943Diag(Tok,1944getLangOpts().OpenMP >= 521945? diag::err_omp_declare_target_wrong_clause_after_implicit_enter1946: diag::err_omp_declare_target_wrong_clause_after_implicit_to);1947break;1948}19491950// Consume optional ','.1951if (Tok.is(tok::comma))1952ConsumeToken();1953}19541955if (DTCI.Indirect && DTCI.DT != OMPDeclareTargetDeclAttr::DT_Any)1956Diag(DeviceTypeLoc, diag::err_omp_declare_target_indirect_device_type);19571958// For declare target require at least 'to' or 'link' to be present.1959if (DTCI.Kind == OMPD_declare_target && RequiresToOrLinkOrIndirectClause &&1960!HasToOrLinkOrIndirectClause)1961Diag(DTCI.Loc,1962getLangOpts().OpenMP >= 521963? diag::err_omp_declare_target_missing_enter_or_link_clause1964: diag::err_omp_declare_target_missing_to_or_link_clause)1965<< (getLangOpts().OpenMP >= 51 ? 1 : 0);19661967SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);1968}19691970void Parser::skipUntilPragmaOpenMPEnd(OpenMPDirectiveKind DKind) {1971// The last seen token is annot_pragma_openmp_end - need to check for1972// extra tokens.1973if (Tok.is(tok::annot_pragma_openmp_end))1974return;19751976Diag(Tok, diag::warn_omp_extra_tokens_at_eol)1977<< getOpenMPDirectiveName(DKind);1978while (Tok.isNot(tok::annot_pragma_openmp_end))1979ConsumeAnyToken();1980}19811982void Parser::parseOMPEndDirective(OpenMPDirectiveKind BeginKind,1983OpenMPDirectiveKind ExpectedKind,1984OpenMPDirectiveKind FoundKind,1985SourceLocation BeginLoc,1986SourceLocation FoundLoc,1987bool SkipUntilOpenMPEnd) {1988int DiagSelection = ExpectedKind == OMPD_end_declare_target ? 0 : 1;19891990if (FoundKind == ExpectedKind) {1991ConsumeAnyToken();1992skipUntilPragmaOpenMPEnd(ExpectedKind);1993return;1994}19951996Diag(FoundLoc, diag::err_expected_end_declare_target_or_variant)1997<< DiagSelection;1998Diag(BeginLoc, diag::note_matching)1999<< ("'#pragma omp " + getOpenMPDirectiveName(BeginKind) + "'").str();2000if (SkipUntilOpenMPEnd)2001SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);2002}20032004void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind BeginDKind,2005OpenMPDirectiveKind EndDKind,2006SourceLocation DKLoc) {2007parseOMPEndDirective(BeginDKind, OMPD_end_declare_target, EndDKind, DKLoc,2008Tok.getLocation(),2009/* SkipUntilOpenMPEnd */ false);2010// Skip the last annot_pragma_openmp_end.2011if (Tok.is(tok::annot_pragma_openmp_end))2012ConsumeAnnotationToken();2013}20142015/// Parsing of declarative OpenMP directives.2016///2017/// threadprivate-directive:2018/// annot_pragma_openmp 'threadprivate' simple-variable-list2019/// annot_pragma_openmp_end2020///2021/// allocate-directive:2022/// annot_pragma_openmp 'allocate' simple-variable-list [<clause>]2023/// annot_pragma_openmp_end2024///2025/// declare-reduction-directive:2026/// annot_pragma_openmp 'declare' 'reduction' [...]2027/// annot_pragma_openmp_end2028///2029/// declare-mapper-directive:2030/// annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifer> ':']2031/// <type> <var> ')' [<clause>[[,] <clause>] ... ]2032/// annot_pragma_openmp_end2033///2034/// declare-simd-directive:2035/// annot_pragma_openmp 'declare simd' {<clause> [,]}2036/// annot_pragma_openmp_end2037/// <function declaration/definition>2038///2039/// requires directive:2040/// annot_pragma_openmp 'requires' <clause> [[[,] <clause>] ... ]2041/// annot_pragma_openmp_end2042///2043/// assumes directive:2044/// annot_pragma_openmp 'assumes' <clause> [[[,] <clause>] ... ]2045/// annot_pragma_openmp_end2046/// or2047/// annot_pragma_openmp 'begin assumes' <clause> [[[,] <clause>] ... ]2048/// annot_pragma_openmp 'end assumes'2049/// annot_pragma_openmp_end2050///2051Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(2052AccessSpecifier &AS, ParsedAttributes &Attrs, bool Delayed,2053DeclSpec::TST TagType, Decl *Tag) {2054assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) &&2055"Not an OpenMP directive!");2056ParsingOpenMPDirectiveRAII DirScope(*this);2057ParenBraceBracketBalancer BalancerRAIIObj(*this);20582059SourceLocation Loc;2060OpenMPDirectiveKind DKind;2061if (Delayed) {2062TentativeParsingAction TPA(*this);2063Loc = ConsumeAnnotationToken();2064DKind = parseOpenMPDirectiveKind(*this);2065if (DKind == OMPD_declare_reduction || DKind == OMPD_declare_mapper) {2066// Need to delay parsing until completion of the parent class.2067TPA.Revert();2068CachedTokens Toks;2069unsigned Cnt = 1;2070Toks.push_back(Tok);2071while (Cnt && Tok.isNot(tok::eof)) {2072(void)ConsumeAnyToken();2073if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp))2074++Cnt;2075else if (Tok.is(tok::annot_pragma_openmp_end))2076--Cnt;2077Toks.push_back(Tok);2078}2079// Skip last annot_pragma_openmp_end.2080if (Cnt == 0)2081(void)ConsumeAnyToken();2082auto *LP = new LateParsedPragma(this, AS);2083LP->takeToks(Toks);2084getCurrentClass().LateParsedDeclarations.push_back(LP);2085return nullptr;2086}2087TPA.Commit();2088} else {2089Loc = ConsumeAnnotationToken();2090DKind = parseOpenMPDirectiveKind(*this);2091}20922093switch (DKind) {2094case OMPD_threadprivate: {2095ConsumeToken();2096DeclDirectiveListParserHelper Helper(this, DKind);2097if (!ParseOpenMPSimpleVarList(DKind, Helper,2098/*AllowScopeSpecifier=*/true)) {2099skipUntilPragmaOpenMPEnd(DKind);2100// Skip the last annot_pragma_openmp_end.2101ConsumeAnnotationToken();2102return Actions.OpenMP().ActOnOpenMPThreadprivateDirective(2103Loc, Helper.getIdentifiers());2104}2105break;2106}2107case OMPD_allocate: {2108ConsumeToken();2109DeclDirectiveListParserHelper Helper(this, DKind);2110if (!ParseOpenMPSimpleVarList(DKind, Helper,2111/*AllowScopeSpecifier=*/true)) {2112SmallVector<OMPClause *, 1> Clauses;2113if (Tok.isNot(tok::annot_pragma_openmp_end)) {2114std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses;2115while (Tok.isNot(tok::annot_pragma_openmp_end)) {2116OpenMPClauseKind CKind =2117Tok.isAnnotation() ? OMPC_unknown2118: getOpenMPClauseKind(PP.getSpelling(Tok));2119Actions.OpenMP().StartOpenMPClause(CKind);2120OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind,2121!SeenClauses[unsigned(CKind)]);2122SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,2123StopBeforeMatch);2124SeenClauses[unsigned(CKind)] = true;2125if (Clause != nullptr)2126Clauses.push_back(Clause);2127if (Tok.is(tok::annot_pragma_openmp_end)) {2128Actions.OpenMP().EndOpenMPClause();2129break;2130}2131// Skip ',' if any.2132if (Tok.is(tok::comma))2133ConsumeToken();2134Actions.OpenMP().EndOpenMPClause();2135}2136skipUntilPragmaOpenMPEnd(DKind);2137}2138// Skip the last annot_pragma_openmp_end.2139ConsumeAnnotationToken();2140return Actions.OpenMP().ActOnOpenMPAllocateDirective(2141Loc, Helper.getIdentifiers(), Clauses);2142}2143break;2144}2145case OMPD_requires: {2146SourceLocation StartLoc = ConsumeToken();2147SmallVector<OMPClause *, 5> Clauses;2148llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1);2149if (Tok.is(tok::annot_pragma_openmp_end)) {2150Diag(Tok, diag::err_omp_expected_clause)2151<< getOpenMPDirectiveName(OMPD_requires);2152break;2153}2154while (Tok.isNot(tok::annot_pragma_openmp_end)) {2155OpenMPClauseKind CKind = Tok.isAnnotation()2156? OMPC_unknown2157: getOpenMPClauseKind(PP.getSpelling(Tok));2158Actions.OpenMP().StartOpenMPClause(CKind);2159OMPClause *Clause = ParseOpenMPClause(OMPD_requires, CKind,2160!SeenClauses[unsigned(CKind)]);2161SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,2162StopBeforeMatch);2163SeenClauses[unsigned(CKind)] = true;2164if (Clause != nullptr)2165Clauses.push_back(Clause);2166if (Tok.is(tok::annot_pragma_openmp_end)) {2167Actions.OpenMP().EndOpenMPClause();2168break;2169}2170// Skip ',' if any.2171if (Tok.is(tok::comma))2172ConsumeToken();2173Actions.OpenMP().EndOpenMPClause();2174}2175// Consume final annot_pragma_openmp_end2176if (Clauses.empty()) {2177Diag(Tok, diag::err_omp_expected_clause)2178<< getOpenMPDirectiveName(OMPD_requires);2179ConsumeAnnotationToken();2180return nullptr;2181}2182ConsumeAnnotationToken();2183return Actions.OpenMP().ActOnOpenMPRequiresDirective(StartLoc, Clauses);2184}2185case OMPD_error: {2186SmallVector<OMPClause *, 1> Clauses;2187SourceLocation StartLoc = ConsumeToken();2188ParseOpenMPClauses(DKind, Clauses, StartLoc);2189Actions.OpenMP().ActOnOpenMPErrorDirective(Clauses, StartLoc,2190SourceLocation(),2191/*InExContext = */ false);2192break;2193}2194case OMPD_assumes:2195case OMPD_begin_assumes:2196ParseOpenMPAssumesDirective(DKind, ConsumeToken());2197break;2198case OMPD_end_assumes:2199ParseOpenMPEndAssumesDirective(ConsumeToken());2200break;2201case OMPD_declare_reduction:2202ConsumeToken();2203if (DeclGroupPtrTy Res = ParseOpenMPDeclareReductionDirective(AS)) {2204skipUntilPragmaOpenMPEnd(OMPD_declare_reduction);2205// Skip the last annot_pragma_openmp_end.2206ConsumeAnnotationToken();2207return Res;2208}2209break;2210case OMPD_declare_mapper: {2211ConsumeToken();2212if (DeclGroupPtrTy Res = ParseOpenMPDeclareMapperDirective(AS)) {2213// Skip the last annot_pragma_openmp_end.2214ConsumeAnnotationToken();2215return Res;2216}2217break;2218}2219case OMPD_begin_declare_variant: {2220// The syntax is:2221// { #pragma omp begin declare variant clause }2222// <function-declaration-or-definition-sequence>2223// { #pragma omp end declare variant }2224//2225ConsumeToken();2226OMPTraitInfo *ParentTI =2227Actions.OpenMP().getOMPTraitInfoForSurroundingScope();2228ASTContext &ASTCtx = Actions.getASTContext();2229OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo();2230if (parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI)) {2231while (!SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch))2232;2233// Skip the last annot_pragma_openmp_end.2234(void)ConsumeAnnotationToken();2235break;2236}22372238// Skip last tokens.2239skipUntilPragmaOpenMPEnd(OMPD_begin_declare_variant);22402241ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);22422243VariantMatchInfo VMI;2244TI.getAsVariantMatchInfo(ASTCtx, VMI);22452246std::function<void(StringRef)> DiagUnknownTrait =2247[this, Loc](StringRef ISATrait) {2248// TODO Track the selector locations in a way that is accessible here2249// to improve the diagnostic location.2250Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) << ISATrait;2251};2252TargetOMPContext OMPCtx(2253ASTCtx, std::move(DiagUnknownTrait),2254/* CurrentFunctionDecl */ nullptr,2255/* ConstructTraits */ ArrayRef<llvm::omp::TraitProperty>());22562257if (isVariantApplicableInContext(VMI, OMPCtx, /* DeviceSetOnly */ true)) {2258Actions.OpenMP().ActOnOpenMPBeginDeclareVariant(Loc, TI);2259break;2260}22612262// Elide all the code till the matching end declare variant was found.2263unsigned Nesting = 1;2264SourceLocation DKLoc;2265OpenMPDirectiveKind DK = OMPD_unknown;2266do {2267DKLoc = Tok.getLocation();2268DK = parseOpenMPDirectiveKind(*this);2269if (DK == OMPD_end_declare_variant)2270--Nesting;2271else if (DK == OMPD_begin_declare_variant)2272++Nesting;2273if (!Nesting || isEofOrEom())2274break;2275ConsumeAnyToken();2276} while (true);22772278parseOMPEndDirective(OMPD_begin_declare_variant, OMPD_end_declare_variant,2279DK, Loc, DKLoc, /* SkipUntilOpenMPEnd */ true);2280if (isEofOrEom())2281return nullptr;2282break;2283}2284case OMPD_end_declare_variant: {2285if (Actions.OpenMP().isInOpenMPDeclareVariantScope())2286Actions.OpenMP().ActOnOpenMPEndDeclareVariant();2287else2288Diag(Loc, diag::err_expected_begin_declare_variant);2289ConsumeToken();2290break;2291}2292case OMPD_declare_variant:2293case OMPD_declare_simd: {2294// The syntax is:2295// { #pragma omp declare {simd|variant} }2296// <function-declaration-or-definition>2297//2298CachedTokens Toks;2299Toks.push_back(Tok);2300ConsumeToken();2301while (Tok.isNot(tok::annot_pragma_openmp_end)) {2302Toks.push_back(Tok);2303ConsumeAnyToken();2304}2305Toks.push_back(Tok);2306ConsumeAnyToken();23072308DeclGroupPtrTy Ptr;2309if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp)) {2310Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, Delayed,2311TagType, Tag);2312} else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) {2313// Here we expect to see some function declaration.2314if (AS == AS_none) {2315assert(TagType == DeclSpec::TST_unspecified);2316ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);2317MaybeParseCXX11Attributes(Attrs);2318ParsingDeclSpec PDS(*this);2319Ptr = ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs, &PDS);2320} else {2321Ptr =2322ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag);2323}2324}2325if (!Ptr) {2326Diag(Loc, diag::err_omp_decl_in_declare_simd_variant)2327<< (DKind == OMPD_declare_simd ? 0 : 1);2328return DeclGroupPtrTy();2329}2330if (DKind == OMPD_declare_simd)2331return ParseOMPDeclareSimdClauses(Ptr, Toks, Loc);2332assert(DKind == OMPD_declare_variant &&2333"Expected declare variant directive only");2334ParseOMPDeclareVariantClauses(Ptr, Toks, Loc);2335return Ptr;2336}2337case OMPD_begin_declare_target:2338case OMPD_declare_target: {2339SourceLocation DTLoc = ConsumeAnyToken();2340bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end);2341SemaOpenMP::DeclareTargetContextInfo DTCI(DKind, DTLoc);2342if (HasClauses)2343ParseOMPDeclareTargetClauses(DTCI);2344bool HasImplicitMappings = DKind == OMPD_begin_declare_target ||2345!HasClauses ||2346(DTCI.ExplicitlyMapped.empty() && DTCI.Indirect);23472348// Skip the last annot_pragma_openmp_end.2349ConsumeAnyToken();23502351if (HasImplicitMappings) {2352Actions.OpenMP().ActOnStartOpenMPDeclareTargetContext(DTCI);2353return nullptr;2354}23552356Actions.OpenMP().ActOnFinishedOpenMPDeclareTargetContext(DTCI);2357llvm::SmallVector<Decl *, 4> Decls;2358for (auto &It : DTCI.ExplicitlyMapped)2359Decls.push_back(It.first);2360return Actions.BuildDeclaratorGroup(Decls);2361}2362case OMPD_end_declare_target: {2363if (!Actions.OpenMP().isInOpenMPDeclareTargetContext()) {2364Diag(Tok, diag::err_omp_unexpected_directive)2365<< 1 << getOpenMPDirectiveName(DKind);2366break;2367}2368const SemaOpenMP::DeclareTargetContextInfo &DTCI =2369Actions.OpenMP().ActOnOpenMPEndDeclareTargetDirective();2370ParseOMPEndDeclareTargetDirective(DTCI.Kind, DKind, DTCI.Loc);2371return nullptr;2372}2373case OMPD_unknown:2374Diag(Tok, diag::err_omp_unknown_directive);2375break;2376default:2377switch (getDirectiveCategory(DKind)) {2378case Category::Executable:2379case Category::Meta:2380case Category::Subsidiary:2381case Category::Utility:2382Diag(Tok, diag::err_omp_unexpected_directive)2383<< 1 << getOpenMPDirectiveName(DKind);2384break;2385case Category::Declarative:2386case Category::Informational:2387break;2388}2389}2390while (Tok.isNot(tok::annot_pragma_openmp_end))2391ConsumeAnyToken();2392ConsumeAnyToken();2393return nullptr;2394}23952396StmtResult Parser::ParseOpenMPExecutableDirective(2397ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc,2398bool ReadDirectiveWithinMetadirective) {2399assert(isOpenMPExecutableDirective(DKind) && "Unexpected directive category");24002401bool HasAssociatedStatement = true;2402Association Assoc = getDirectiveAssociation(DKind);24032404// OMPD_ordered has None as association, but it comes in two variants,2405// the second of which is associated with a block.2406// OMPD_scan and OMPD_section are both "separating", but section is treated2407// as if it was associated with a statement, while scan is not.2408if (DKind != OMPD_ordered && DKind != OMPD_section &&2409(Assoc == Association::None || Assoc == Association::Separating)) {2410if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==2411ParsedStmtContext()) {2412Diag(Tok, diag::err_omp_immediate_directive)2413<< getOpenMPDirectiveName(DKind) << 0;2414if (DKind == OMPD_error) {2415SkipUntil(tok::annot_pragma_openmp_end);2416return StmtError();2417}2418}2419HasAssociatedStatement = false;2420}24212422SourceLocation EndLoc;2423SmallVector<OMPClause *, 5> Clauses;2424llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1);2425DeclarationNameInfo DirName;2426OpenMPDirectiveKind CancelRegion = OMPD_unknown;2427unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |2428Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;24292430// Special processing for flush and depobj clauses.2431Token ImplicitTok;2432bool ImplicitClauseAllowed = false;2433if (DKind == OMPD_flush || DKind == OMPD_depobj) {2434ImplicitTok = Tok;2435ImplicitClauseAllowed = true;2436}2437ConsumeToken();2438// Parse directive name of the 'critical' directive if any.2439if (DKind == OMPD_critical) {2440BalancedDelimiterTracker T(*this, tok::l_paren,2441tok::annot_pragma_openmp_end);2442if (!T.consumeOpen()) {2443if (Tok.isAnyIdentifier()) {2444DirName =2445DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation());2446ConsumeAnyToken();2447} else {2448Diag(Tok, diag::err_omp_expected_identifier_for_critical);2449}2450T.consumeClose();2451}2452} else if (DKind == OMPD_cancellation_point || DKind == OMPD_cancel) {2453CancelRegion = parseOpenMPDirectiveKind(*this);2454if (Tok.isNot(tok::annot_pragma_openmp_end))2455ConsumeToken();2456}24572458if (isOpenMPLoopDirective(DKind))2459ScopeFlags |= Scope::OpenMPLoopDirectiveScope;2460if (isOpenMPSimdDirective(DKind))2461ScopeFlags |= Scope::OpenMPSimdDirectiveScope;2462ParseScope OMPDirectiveScope(this, ScopeFlags);2463Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(),2464Loc);24652466while (Tok.isNot(tok::annot_pragma_openmp_end)) {2467// If we are parsing for a directive within a metadirective, the directive2468// ends with a ')'.2469if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) {2470while (Tok.isNot(tok::annot_pragma_openmp_end))2471ConsumeAnyToken();2472break;2473}2474bool HasImplicitClause = false;2475if (ImplicitClauseAllowed && Tok.is(tok::l_paren)) {2476HasImplicitClause = true;2477// Push copy of the current token back to stream to properly parse2478// pseudo-clause OMPFlushClause or OMPDepobjClause.2479PP.EnterToken(Tok, /*IsReinject*/ true);2480PP.EnterToken(ImplicitTok, /*IsReinject*/ true);2481ConsumeAnyToken();2482}2483OpenMPClauseKind CKind = Tok.isAnnotation()2484? OMPC_unknown2485: getOpenMPClauseKind(PP.getSpelling(Tok));2486if (HasImplicitClause) {2487assert(CKind == OMPC_unknown && "Must be unknown implicit clause.");2488if (DKind == OMPD_flush) {2489CKind = OMPC_flush;2490} else {2491assert(DKind == OMPD_depobj && "Expected flush or depobj directives.");2492CKind = OMPC_depobj;2493}2494}2495// No more implicit clauses allowed.2496ImplicitClauseAllowed = false;2497Actions.OpenMP().StartOpenMPClause(CKind);2498HasImplicitClause = false;2499OMPClause *Clause =2500ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]);2501SeenClauses[unsigned(CKind)] = true;2502if (Clause)2503Clauses.push_back(Clause);25042505// Skip ',' if any.2506if (Tok.is(tok::comma))2507ConsumeToken();2508Actions.OpenMP().EndOpenMPClause();2509}2510// End location of the directive.2511EndLoc = Tok.getLocation();2512// Consume final annot_pragma_openmp_end.2513ConsumeAnnotationToken();25142515if (DKind == OMPD_ordered) {2516// If the depend or doacross clause is specified, the ordered construct2517// is a stand-alone directive.2518for (auto CK : {OMPC_depend, OMPC_doacross}) {2519if (SeenClauses[unsigned(CK)]) {2520if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==2521ParsedStmtContext()) {2522Diag(Loc, diag::err_omp_immediate_directive)2523<< getOpenMPDirectiveName(DKind) << 1 << getOpenMPClauseName(CK);2524}2525HasAssociatedStatement = false;2526}2527}2528}25292530if (DKind == OMPD_tile && !SeenClauses[unsigned(OMPC_sizes)]) {2531Diag(Loc, diag::err_omp_required_clause)2532<< getOpenMPDirectiveName(OMPD_tile) << "sizes";2533}25342535StmtResult AssociatedStmt;2536if (HasAssociatedStatement) {2537// The body is a block scope like in Lambdas and Blocks.2538Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope());2539// FIXME: We create a bogus CompoundStmt scope to hold the contents of2540// the captured region. Code elsewhere assumes that any FunctionScopeInfo2541// should have at least one compound statement scope within it.2542ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);2543{2544Sema::CompoundScopeRAII Scope(Actions);2545AssociatedStmt = ParseStatement();25462547if (AssociatedStmt.isUsable() && isOpenMPLoopDirective(DKind) &&2548getLangOpts().OpenMPIRBuilder)2549AssociatedStmt =2550Actions.OpenMP().ActOnOpenMPLoopnest(AssociatedStmt.get());2551}2552AssociatedStmt =2553Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);2554} else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data ||2555DKind == OMPD_target_exit_data) {2556Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope());2557AssociatedStmt = (Sema::CompoundScopeRAII(Actions),2558Actions.ActOnCompoundStmt(Loc, Loc, std::nullopt,2559/*isStmtExpr=*/false));2560AssociatedStmt =2561Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);2562}25632564StmtResult Directive = Actions.OpenMP().ActOnOpenMPExecutableDirective(2565DKind, DirName, CancelRegion, Clauses, AssociatedStmt.get(), Loc, EndLoc);25662567// Exit scope.2568Actions.OpenMP().EndOpenMPDSABlock(Directive.get());2569OMPDirectiveScope.Exit();25702571return Directive;2572}25732574/// Parsing of declarative or executable OpenMP directives.2575///2576/// threadprivate-directive:2577/// annot_pragma_openmp 'threadprivate' simple-variable-list2578/// annot_pragma_openmp_end2579///2580/// allocate-directive:2581/// annot_pragma_openmp 'allocate' simple-variable-list2582/// annot_pragma_openmp_end2583///2584/// declare-reduction-directive:2585/// annot_pragma_openmp 'declare' 'reduction' '(' <reduction_id> ':'2586/// <type> {',' <type>} ':' <expression> ')' ['initializer' '('2587/// ('omp_priv' '=' <expression>|<function_call>) ')']2588/// annot_pragma_openmp_end2589///2590/// declare-mapper-directive:2591/// annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifer> ':']2592/// <type> <var> ')' [<clause>[[,] <clause>] ... ]2593/// annot_pragma_openmp_end2594///2595/// executable-directive:2596/// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |2597/// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] |2598/// 'parallel for' | 'parallel sections' | 'parallel master' | 'task' |2599/// 'taskyield' | 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'error'2600/// | 'atomic' | 'for simd' | 'parallel for simd' | 'target' | 'target2601/// data' | 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' |2602/// 'master taskloop' | 'master taskloop simd' | 'parallel master2603/// taskloop' | 'parallel master taskloop simd' | 'distribute' | 'target2604/// enter data' | 'target exit data' | 'target parallel' | 'target2605/// parallel for' | 'target update' | 'distribute parallel for' |2606/// 'distribute paralle for simd' | 'distribute simd' | 'target parallel2607/// for simd' | 'target simd' | 'teams distribute' | 'teams distribute2608/// simd' | 'teams distribute parallel for simd' | 'teams distribute2609/// parallel for' | 'target teams' | 'target teams distribute' | 'target2610/// teams distribute parallel for' | 'target teams distribute parallel2611/// for simd' | 'target teams distribute simd' | 'masked' |2612/// 'parallel masked' {clause} annot_pragma_openmp_end2613///2614StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(2615ParsedStmtContext StmtCtx, bool ReadDirectiveWithinMetadirective) {2616if (!ReadDirectiveWithinMetadirective)2617assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) &&2618"Not an OpenMP directive!");2619ParsingOpenMPDirectiveRAII DirScope(*this);2620ParenBraceBracketBalancer BalancerRAIIObj(*this);2621SourceLocation Loc = ReadDirectiveWithinMetadirective2622? Tok.getLocation()2623: ConsumeAnnotationToken();2624OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this);2625if (ReadDirectiveWithinMetadirective && DKind == OMPD_unknown) {2626Diag(Tok, diag::err_omp_unknown_directive);2627return StmtError();2628}26292630StmtResult Directive = StmtError();26312632bool IsExecutable = [&]() {2633if (DKind == OMPD_error) // OMPD_error is handled as executable2634return true;2635auto Res = getDirectiveCategory(DKind);2636return Res == Category::Executable || Res == Category::Subsidiary;2637}();26382639if (IsExecutable) {2640Directive = ParseOpenMPExecutableDirective(2641StmtCtx, DKind, Loc, ReadDirectiveWithinMetadirective);2642assert(!Directive.isUnset() && "Executable directive remained unprocessed");2643return Directive;2644}26452646switch (DKind) {2647case OMPD_nothing:2648ConsumeToken();2649// If we are parsing the directive within a metadirective, the directive2650// ends with a ')'.2651if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren))2652while (Tok.isNot(tok::annot_pragma_openmp_end))2653ConsumeAnyToken();2654else2655skipUntilPragmaOpenMPEnd(DKind);2656if (Tok.is(tok::annot_pragma_openmp_end))2657ConsumeAnnotationToken();2658// return an empty statement2659return StmtEmpty();2660case OMPD_metadirective: {2661ConsumeToken();2662SmallVector<VariantMatchInfo, 4> VMIs;26632664// First iteration of parsing all clauses of metadirective.2665// This iteration only parses and collects all context selector ignoring the2666// associated directives.2667TentativeParsingAction TPA(*this);2668ASTContext &ASTContext = Actions.getASTContext();26692670BalancedDelimiterTracker T(*this, tok::l_paren,2671tok::annot_pragma_openmp_end);2672while (Tok.isNot(tok::annot_pragma_openmp_end)) {2673OpenMPClauseKind CKind = Tok.isAnnotation()2674? OMPC_unknown2675: getOpenMPClauseKind(PP.getSpelling(Tok));2676SourceLocation Loc = ConsumeToken();26772678// Parse '('.2679if (T.expectAndConsume(diag::err_expected_lparen_after,2680getOpenMPClauseName(CKind).data()))2681return Directive;26822683OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo();2684if (CKind == OMPC_when) {2685// parse and get OMPTraitInfo to pass to the When clause2686parseOMPContextSelectors(Loc, TI);2687if (TI.Sets.size() == 0) {2688Diag(Tok, diag::err_omp_expected_context_selector) << "when clause";2689TPA.Commit();2690return Directive;2691}26922693// Parse ':'2694if (Tok.is(tok::colon))2695ConsumeAnyToken();2696else {2697Diag(Tok, diag::err_omp_expected_colon) << "when clause";2698TPA.Commit();2699return Directive;2700}2701}2702// Skip Directive for now. We will parse directive in the second iteration2703int paren = 0;2704while (Tok.isNot(tok::r_paren) || paren != 0) {2705if (Tok.is(tok::l_paren))2706paren++;2707if (Tok.is(tok::r_paren))2708paren--;2709if (Tok.is(tok::annot_pragma_openmp_end)) {2710Diag(Tok, diag::err_omp_expected_punc)2711<< getOpenMPClauseName(CKind) << 0;2712TPA.Commit();2713return Directive;2714}2715ConsumeAnyToken();2716}2717// Parse ')'2718if (Tok.is(tok::r_paren))2719T.consumeClose();27202721VariantMatchInfo VMI;2722TI.getAsVariantMatchInfo(ASTContext, VMI);27232724VMIs.push_back(VMI);2725}27262727TPA.Revert();2728// End of the first iteration. Parser is reset to the start of metadirective27292730std::function<void(StringRef)> DiagUnknownTrait =2731[this, Loc](StringRef ISATrait) {2732// TODO Track the selector locations in a way that is accessible here2733// to improve the diagnostic location.2734Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) << ISATrait;2735};2736TargetOMPContext OMPCtx(ASTContext, std::move(DiagUnknownTrait),2737/* CurrentFunctionDecl */ nullptr,2738ArrayRef<llvm::omp::TraitProperty>());27392740// A single match is returned for OpenMP 5.02741int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx);27422743int Idx = 0;2744// In OpenMP 5.0 metadirective is either replaced by another directive or2745// ignored.2746// TODO: In OpenMP 5.1 generate multiple directives based upon the matches2747// found by getBestWhenMatchForContext.2748while (Tok.isNot(tok::annot_pragma_openmp_end)) {2749// OpenMP 5.0 implementation - Skip to the best index found.2750if (Idx++ != BestIdx) {2751ConsumeToken(); // Consume clause name2752T.consumeOpen(); // Consume '('2753int paren = 0;2754// Skip everything inside the clause2755while (Tok.isNot(tok::r_paren) || paren != 0) {2756if (Tok.is(tok::l_paren))2757paren++;2758if (Tok.is(tok::r_paren))2759paren--;2760ConsumeAnyToken();2761}2762// Parse ')'2763if (Tok.is(tok::r_paren))2764T.consumeClose();2765continue;2766}27672768OpenMPClauseKind CKind = Tok.isAnnotation()2769? OMPC_unknown2770: getOpenMPClauseKind(PP.getSpelling(Tok));2771SourceLocation Loc = ConsumeToken();27722773// Parse '('.2774T.consumeOpen();27752776// Skip ContextSelectors for when clause2777if (CKind == OMPC_when) {2778OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo();2779// parse and skip the ContextSelectors2780parseOMPContextSelectors(Loc, TI);27812782// Parse ':'2783ConsumeAnyToken();2784}27852786// If no directive is passed, skip in OpenMP 5.0.2787// TODO: Generate nothing directive from OpenMP 5.1.2788if (Tok.is(tok::r_paren)) {2789SkipUntil(tok::annot_pragma_openmp_end);2790break;2791}27922793// Parse Directive2794Directive = ParseOpenMPDeclarativeOrExecutableDirective(2795StmtCtx,2796/*ReadDirectiveWithinMetadirective=*/true);2797break;2798}2799break;2800}2801case OMPD_threadprivate: {2802// FIXME: Should this be permitted in C++?2803if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==2804ParsedStmtContext()) {2805Diag(Tok, diag::err_omp_immediate_directive)2806<< getOpenMPDirectiveName(DKind) << 0;2807}2808ConsumeToken();2809DeclDirectiveListParserHelper Helper(this, DKind);2810if (!ParseOpenMPSimpleVarList(DKind, Helper,2811/*AllowScopeSpecifier=*/false)) {2812skipUntilPragmaOpenMPEnd(DKind);2813DeclGroupPtrTy Res = Actions.OpenMP().ActOnOpenMPThreadprivateDirective(2814Loc, Helper.getIdentifiers());2815Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());2816}2817SkipUntil(tok::annot_pragma_openmp_end);2818break;2819}2820case OMPD_allocate: {2821// FIXME: Should this be permitted in C++?2822if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==2823ParsedStmtContext()) {2824Diag(Tok, diag::err_omp_immediate_directive)2825<< getOpenMPDirectiveName(DKind) << 0;2826}2827ConsumeToken();2828DeclDirectiveListParserHelper Helper(this, DKind);2829if (!ParseOpenMPSimpleVarList(DKind, Helper,2830/*AllowScopeSpecifier=*/false)) {2831SmallVector<OMPClause *, 1> Clauses;2832if (Tok.isNot(tok::annot_pragma_openmp_end)) {2833llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1);2834while (Tok.isNot(tok::annot_pragma_openmp_end)) {2835OpenMPClauseKind CKind =2836Tok.isAnnotation() ? OMPC_unknown2837: getOpenMPClauseKind(PP.getSpelling(Tok));2838Actions.OpenMP().StartOpenMPClause(CKind);2839OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind,2840!SeenClauses[unsigned(CKind)]);2841SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,2842StopBeforeMatch);2843SeenClauses[unsigned(CKind)] = true;2844if (Clause != nullptr)2845Clauses.push_back(Clause);2846if (Tok.is(tok::annot_pragma_openmp_end)) {2847Actions.OpenMP().EndOpenMPClause();2848break;2849}2850// Skip ',' if any.2851if (Tok.is(tok::comma))2852ConsumeToken();2853Actions.OpenMP().EndOpenMPClause();2854}2855skipUntilPragmaOpenMPEnd(DKind);2856}2857DeclGroupPtrTy Res = Actions.OpenMP().ActOnOpenMPAllocateDirective(2858Loc, Helper.getIdentifiers(), Clauses);2859Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());2860}2861SkipUntil(tok::annot_pragma_openmp_end);2862break;2863}2864case OMPD_declare_reduction:2865ConsumeToken();2866if (DeclGroupPtrTy Res =2867ParseOpenMPDeclareReductionDirective(/*AS=*/AS_none)) {2868skipUntilPragmaOpenMPEnd(OMPD_declare_reduction);2869ConsumeAnyToken();2870Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());2871} else {2872SkipUntil(tok::annot_pragma_openmp_end);2873}2874break;2875case OMPD_declare_mapper: {2876ConsumeToken();2877if (DeclGroupPtrTy Res =2878ParseOpenMPDeclareMapperDirective(/*AS=*/AS_none)) {2879// Skip the last annot_pragma_openmp_end.2880ConsumeAnnotationToken();2881Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());2882} else {2883SkipUntil(tok::annot_pragma_openmp_end);2884}2885break;2886}2887case OMPD_reverse:2888case OMPD_interchange:2889case OMPD_declare_target: {2890SourceLocation DTLoc = ConsumeAnyToken();2891bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end);2892SemaOpenMP::DeclareTargetContextInfo DTCI(DKind, DTLoc);2893if (HasClauses)2894ParseOMPDeclareTargetClauses(DTCI);2895bool HasImplicitMappings =2896!HasClauses || (DTCI.ExplicitlyMapped.empty() && DTCI.Indirect);28972898if (HasImplicitMappings) {2899Diag(Tok, diag::err_omp_unexpected_directive)2900<< 1 << getOpenMPDirectiveName(DKind);2901SkipUntil(tok::annot_pragma_openmp_end);2902break;2903}29042905// Skip the last annot_pragma_openmp_end.2906ConsumeAnyToken();29072908Actions.OpenMP().ActOnFinishedOpenMPDeclareTargetContext(DTCI);2909break;2910}2911case OMPD_declare_simd:2912case OMPD_begin_declare_target:2913case OMPD_end_declare_target:2914case OMPD_requires:2915case OMPD_begin_declare_variant:2916case OMPD_end_declare_variant:2917case OMPD_declare_variant:2918Diag(Tok, diag::err_omp_unexpected_directive)2919<< 1 << getOpenMPDirectiveName(DKind);2920SkipUntil(tok::annot_pragma_openmp_end);2921break;2922case OMPD_unknown:2923default:2924Diag(Tok, diag::err_omp_unknown_directive);2925SkipUntil(tok::annot_pragma_openmp_end);2926break;2927}2928return Directive;2929}29302931// Parses simple list:2932// simple-variable-list:2933// '(' id-expression {, id-expression} ')'2934//2935bool Parser::ParseOpenMPSimpleVarList(2936OpenMPDirectiveKind Kind,2937const llvm::function_ref<void(CXXScopeSpec &, DeclarationNameInfo)>2938&Callback,2939bool AllowScopeSpecifier) {2940// Parse '('.2941BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);2942if (T.expectAndConsume(diag::err_expected_lparen_after,2943getOpenMPDirectiveName(Kind).data()))2944return true;2945bool IsCorrect = true;2946bool NoIdentIsFound = true;29472948// Read tokens while ')' or annot_pragma_openmp_end is not found.2949while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {2950CXXScopeSpec SS;2951UnqualifiedId Name;2952// Read var name.2953Token PrevTok = Tok;2954NoIdentIsFound = false;29552956if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&2957ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,2958/*ObjectHasErrors=*/false, false)) {2959IsCorrect = false;2960SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,2961StopBeforeMatch);2962} else if (ParseUnqualifiedId(SS, /*ObjectType=*/nullptr,2963/*ObjectHadErrors=*/false, false, false,2964false, false, nullptr, Name)) {2965IsCorrect = false;2966SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,2967StopBeforeMatch);2968} else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&2969Tok.isNot(tok::annot_pragma_openmp_end)) {2970IsCorrect = false;2971SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,2972StopBeforeMatch);2973Diag(PrevTok.getLocation(), diag::err_expected)2974<< tok::identifier2975<< SourceRange(PrevTok.getLocation(), PrevTokLocation);2976} else {2977Callback(SS, Actions.GetNameFromUnqualifiedId(Name));2978}2979// Consume ','.2980if (Tok.is(tok::comma)) {2981ConsumeToken();2982}2983}29842985if (NoIdentIsFound) {2986Diag(Tok, diag::err_expected) << tok::identifier;2987IsCorrect = false;2988}29892990// Parse ')'.2991IsCorrect = !T.consumeClose() && IsCorrect;29922993return !IsCorrect;2994}29952996OMPClause *Parser::ParseOpenMPSizesClause() {2997SourceLocation ClauseNameLoc, OpenLoc, CloseLoc;2998SmallVector<Expr *, 4> ValExprs;2999if (ParseOpenMPExprListClause(OMPC_sizes, ClauseNameLoc, OpenLoc, CloseLoc,3000ValExprs))3001return nullptr;30023003return Actions.OpenMP().ActOnOpenMPSizesClause(ValExprs, ClauseNameLoc,3004OpenLoc, CloseLoc);3005}30063007OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) {3008SourceLocation Loc = Tok.getLocation();3009ConsumeAnyToken();30103011// Parse '('.3012BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);3013if (T.expectAndConsume(diag::err_expected_lparen_after, "uses_allocator"))3014return nullptr;3015SmallVector<SemaOpenMP::UsesAllocatorsData, 4> Data;3016do {3017CXXScopeSpec SS;3018Token Replacement;3019ExprResult Allocator =3020getLangOpts().CPlusPlus3021? ParseCXXIdExpression()3022: tryParseCXXIdExpression(SS, /*isAddressOfOperand=*/false,3023Replacement);3024if (Allocator.isInvalid()) {3025SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,3026StopBeforeMatch);3027break;3028}3029SemaOpenMP::UsesAllocatorsData &D = Data.emplace_back();3030D.Allocator = Allocator.get();3031if (Tok.is(tok::l_paren)) {3032BalancedDelimiterTracker T(*this, tok::l_paren,3033tok::annot_pragma_openmp_end);3034T.consumeOpen();3035ExprResult AllocatorTraits =3036getLangOpts().CPlusPlus ? ParseCXXIdExpression() : ParseExpression();3037T.consumeClose();3038if (AllocatorTraits.isInvalid()) {3039SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,3040StopBeforeMatch);3041break;3042}3043D.AllocatorTraits = AllocatorTraits.get();3044D.LParenLoc = T.getOpenLocation();3045D.RParenLoc = T.getCloseLocation();3046}3047if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren))3048Diag(Tok, diag::err_omp_expected_punc) << "uses_allocators" << 0;3049// Parse ','3050if (Tok.is(tok::comma))3051ConsumeAnyToken();3052} while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end));3053T.consumeClose();3054return Actions.OpenMP().ActOnOpenMPUsesAllocatorClause(3055Loc, T.getOpenLocation(), T.getCloseLocation(), Data);3056}30573058/// Parsing of OpenMP clauses.3059///3060/// clause:3061/// if-clause | final-clause | num_threads-clause | safelen-clause |3062/// default-clause | private-clause | firstprivate-clause | shared-clause3063/// | linear-clause | aligned-clause | collapse-clause | bind-clause |3064/// lastprivate-clause | reduction-clause | proc_bind-clause |3065/// schedule-clause | copyin-clause | copyprivate-clause | untied-clause |3066/// mergeable-clause | flush-clause | read-clause | write-clause |3067/// update-clause | capture-clause | seq_cst-clause | device-clause |3068/// simdlen-clause | threads-clause | simd-clause | num_teams-clause |3069/// thread_limit-clause | priority-clause | grainsize-clause |3070/// nogroup-clause | num_tasks-clause | hint-clause | to-clause |3071/// from-clause | is_device_ptr-clause | task_reduction-clause |3072/// in_reduction-clause | allocator-clause | allocate-clause |3073/// acq_rel-clause | acquire-clause | release-clause | relaxed-clause |3074/// depobj-clause | destroy-clause | detach-clause | inclusive-clause |3075/// exclusive-clause | uses_allocators-clause | use_device_addr-clause |3076/// has_device_addr3077///3078OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,3079OpenMPClauseKind CKind, bool FirstClause) {3080OMPClauseKind = CKind;3081OMPClause *Clause = nullptr;3082bool ErrorFound = false;3083bool WrongDirective = false;3084// Check if clause is allowed for the given directive.3085if (CKind != OMPC_unknown &&3086!isAllowedClauseForDirective(DKind, CKind, getLangOpts().OpenMP)) {3087Diag(Tok, diag::err_omp_unexpected_clause)3088<< getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);3089ErrorFound = true;3090WrongDirective = true;3091}30923093switch (CKind) {3094case OMPC_final:3095case OMPC_num_threads:3096case OMPC_safelen:3097case OMPC_simdlen:3098case OMPC_collapse:3099case OMPC_ordered:3100case OMPC_num_teams:3101case OMPC_thread_limit:3102case OMPC_priority:3103case OMPC_grainsize:3104case OMPC_num_tasks:3105case OMPC_hint:3106case OMPC_allocator:3107case OMPC_depobj:3108case OMPC_detach:3109case OMPC_novariants:3110case OMPC_nocontext:3111case OMPC_filter:3112case OMPC_partial:3113case OMPC_align:3114case OMPC_message:3115case OMPC_ompx_dyn_cgroup_mem:3116// OpenMP [2.5, Restrictions]3117// At most one num_threads clause can appear on the directive.3118// OpenMP [2.8.1, simd construct, Restrictions]3119// Only one safelen clause can appear on a simd directive.3120// Only one simdlen clause can appear on a simd directive.3121// Only one collapse clause can appear on a simd directive.3122// OpenMP [2.11.1, task Construct, Restrictions]3123// At most one if clause can appear on the directive.3124// At most one final clause can appear on the directive.3125// OpenMP [teams Construct, Restrictions]3126// At most one num_teams clause can appear on the directive.3127// At most one thread_limit clause can appear on the directive.3128// OpenMP [2.9.1, task Construct, Restrictions]3129// At most one priority clause can appear on the directive.3130// OpenMP [2.9.2, taskloop Construct, Restrictions]3131// At most one grainsize clause can appear on the directive.3132// OpenMP [2.9.2, taskloop Construct, Restrictions]3133// At most one num_tasks clause can appear on the directive.3134// OpenMP [2.11.3, allocate Directive, Restrictions]3135// At most one allocator clause can appear on the directive.3136// OpenMP 5.0, 2.10.1 task Construct, Restrictions.3137// At most one detach clause can appear on the directive.3138// OpenMP 5.1, 2.3.6 dispatch Construct, Restrictions.3139// At most one novariants clause can appear on a dispatch directive.3140// At most one nocontext clause can appear on a dispatch directive.3141// OpenMP [5.1, error directive, Restrictions]3142// At most one message clause can appear on the directive3143if (!FirstClause) {3144Diag(Tok, diag::err_omp_more_one_clause)3145<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3146ErrorFound = true;3147}31483149if ((CKind == OMPC_ordered || CKind == OMPC_partial) &&3150PP.LookAhead(/*N=*/0).isNot(tok::l_paren))3151Clause = ParseOpenMPClause(CKind, WrongDirective);3152else if (CKind == OMPC_grainsize || CKind == OMPC_num_tasks)3153Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective);3154else3155Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective);3156break;3157case OMPC_fail:3158case OMPC_default:3159case OMPC_proc_bind:3160case OMPC_atomic_default_mem_order:3161case OMPC_at:3162case OMPC_severity:3163case OMPC_bind:3164// OpenMP [2.14.3.1, Restrictions]3165// Only a single default clause may be specified on a parallel, task or3166// teams directive.3167// OpenMP [2.5, parallel Construct, Restrictions]3168// At most one proc_bind clause can appear on the directive.3169// OpenMP [5.0, Requires directive, Restrictions]3170// At most one atomic_default_mem_order clause can appear3171// on the directive3172// OpenMP [5.1, error directive, Restrictions]3173// At most one at clause can appear on the directive3174// At most one severity clause can appear on the directive3175// OpenMP 5.1, 2.11.7 loop Construct, Restrictions.3176// At most one bind clause can appear on a loop directive.3177if (!FirstClause) {3178Diag(Tok, diag::err_omp_more_one_clause)3179<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3180ErrorFound = true;3181}31823183Clause = ParseOpenMPSimpleClause(CKind, WrongDirective);3184break;3185case OMPC_device:3186case OMPC_schedule:3187case OMPC_dist_schedule:3188case OMPC_defaultmap:3189case OMPC_order:3190// OpenMP [2.7.1, Restrictions, p. 3]3191// Only one schedule clause can appear on a loop directive.3192// OpenMP 4.5 [2.10.4, Restrictions, p. 106]3193// At most one defaultmap clause can appear on the directive.3194// OpenMP 5.0 [2.12.5, target construct, Restrictions]3195// At most one device clause can appear on the directive.3196// OpenMP 5.1 [2.11.3, order clause, Restrictions]3197// At most one order clause may appear on a construct.3198if ((getLangOpts().OpenMP < 50 || CKind != OMPC_defaultmap) &&3199(CKind != OMPC_order || getLangOpts().OpenMP >= 51) && !FirstClause) {3200Diag(Tok, diag::err_omp_more_one_clause)3201<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3202ErrorFound = true;3203}3204[[fallthrough]];3205case OMPC_if:3206Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective);3207break;3208case OMPC_nowait:3209case OMPC_untied:3210case OMPC_mergeable:3211case OMPC_read:3212case OMPC_write:3213case OMPC_capture:3214case OMPC_compare:3215case OMPC_seq_cst:3216case OMPC_acq_rel:3217case OMPC_acquire:3218case OMPC_release:3219case OMPC_relaxed:3220case OMPC_weak:3221case OMPC_threads:3222case OMPC_simd:3223case OMPC_nogroup:3224case OMPC_unified_address:3225case OMPC_unified_shared_memory:3226case OMPC_reverse_offload:3227case OMPC_dynamic_allocators:3228case OMPC_full:3229// OpenMP [2.7.1, Restrictions, p. 9]3230// Only one ordered clause can appear on a loop directive.3231// OpenMP [2.7.1, Restrictions, C/C++, p. 4]3232// Only one nowait clause can appear on a for directive.3233// OpenMP [5.0, Requires directive, Restrictions]3234// Each of the requires clauses can appear at most once on the directive.3235if (!FirstClause) {3236Diag(Tok, diag::err_omp_more_one_clause)3237<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3238ErrorFound = true;3239}32403241Clause = ParseOpenMPClause(CKind, WrongDirective);3242break;3243case OMPC_update:3244if (!FirstClause) {3245Diag(Tok, diag::err_omp_more_one_clause)3246<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3247ErrorFound = true;3248}32493250Clause = (DKind == OMPD_depobj)3251? ParseOpenMPSimpleClause(CKind, WrongDirective)3252: ParseOpenMPClause(CKind, WrongDirective);3253break;3254case OMPC_private:3255case OMPC_firstprivate:3256case OMPC_lastprivate:3257case OMPC_shared:3258case OMPC_reduction:3259case OMPC_task_reduction:3260case OMPC_in_reduction:3261case OMPC_linear:3262case OMPC_aligned:3263case OMPC_copyin:3264case OMPC_copyprivate:3265case OMPC_flush:3266case OMPC_depend:3267case OMPC_map:3268case OMPC_to:3269case OMPC_from:3270case OMPC_use_device_ptr:3271case OMPC_use_device_addr:3272case OMPC_is_device_ptr:3273case OMPC_has_device_addr:3274case OMPC_allocate:3275case OMPC_nontemporal:3276case OMPC_inclusive:3277case OMPC_exclusive:3278case OMPC_affinity:3279case OMPC_doacross:3280case OMPC_enter:3281if (getLangOpts().OpenMP >= 52 && DKind == OMPD_ordered &&3282CKind == OMPC_depend)3283Diag(Tok, diag::warn_omp_depend_in_ordered_deprecated);3284Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective);3285break;3286case OMPC_sizes:3287if (!FirstClause) {3288Diag(Tok, diag::err_omp_more_one_clause)3289<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3290ErrorFound = true;3291}32923293Clause = ParseOpenMPSizesClause();3294break;3295case OMPC_uses_allocators:3296Clause = ParseOpenMPUsesAllocatorClause(DKind);3297break;3298case OMPC_destroy:3299if (DKind != OMPD_interop) {3300if (!FirstClause) {3301Diag(Tok, diag::err_omp_more_one_clause)3302<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3303ErrorFound = true;3304}3305Clause = ParseOpenMPClause(CKind, WrongDirective);3306break;3307}3308[[fallthrough]];3309case OMPC_init:3310case OMPC_use:3311Clause = ParseOpenMPInteropClause(CKind, WrongDirective);3312break;3313case OMPC_device_type:3314case OMPC_unknown:3315skipUntilPragmaOpenMPEnd(DKind);3316break;3317case OMPC_threadprivate:3318case OMPC_uniform:3319case OMPC_match:3320if (!WrongDirective)3321Diag(Tok, diag::err_omp_unexpected_clause)3322<< getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);3323SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);3324break;3325case OMPC_ompx_attribute:3326Clause = ParseOpenMPOMPXAttributesClause(WrongDirective);3327break;3328case OMPC_ompx_bare:3329if (WrongDirective)3330Diag(Tok, diag::note_ompx_bare_clause)3331<< getOpenMPClauseName(CKind) << "target teams";3332if (!ErrorFound && !getLangOpts().OpenMPExtensions) {3333Diag(Tok, diag::err_omp_unexpected_clause_extension_only)3334<< getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);3335ErrorFound = true;3336}3337Clause = ParseOpenMPClause(CKind, WrongDirective);3338break;3339default:3340break;3341}3342return ErrorFound ? nullptr : Clause;3343}33443345/// Parses simple expression in parens for single-expression clauses of OpenMP3346/// constructs.3347/// \param RLoc Returned location of right paren.3348ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName,3349SourceLocation &RLoc,3350bool IsAddressOfOperand) {3351BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);3352if (T.expectAndConsume(diag::err_expected_lparen_after, ClauseName.data()))3353return ExprError();33543355SourceLocation ELoc = Tok.getLocation();3356ExprResult LHS(3357ParseCastExpression(AnyCastExpr, IsAddressOfOperand, NotTypeCast));3358ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));3359Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false);33603361// Parse ')'.3362RLoc = Tok.getLocation();3363if (!T.consumeClose())3364RLoc = T.getCloseLocation();33653366return Val;3367}33683369/// Parsing of OpenMP clauses with single expressions like 'final',3370/// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams',3371/// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks', 'hint' or3372/// 'detach'.3373///3374/// final-clause:3375/// 'final' '(' expression ')'3376///3377/// num_threads-clause:3378/// 'num_threads' '(' expression ')'3379///3380/// safelen-clause:3381/// 'safelen' '(' expression ')'3382///3383/// simdlen-clause:3384/// 'simdlen' '(' expression ')'3385///3386/// collapse-clause:3387/// 'collapse' '(' expression ')'3388///3389/// priority-clause:3390/// 'priority' '(' expression ')'3391///3392/// grainsize-clause:3393/// 'grainsize' '(' expression ')'3394///3395/// num_tasks-clause:3396/// 'num_tasks' '(' expression ')'3397///3398/// hint-clause:3399/// 'hint' '(' expression ')'3400///3401/// allocator-clause:3402/// 'allocator' '(' expression ')'3403///3404/// detach-clause:3405/// 'detach' '(' event-handler-expression ')'3406///3407/// align-clause3408/// 'align' '(' positive-integer-constant ')'3409///3410OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind,3411bool ParseOnly) {3412SourceLocation Loc = ConsumeToken();3413SourceLocation LLoc = Tok.getLocation();3414SourceLocation RLoc;34153416ExprResult Val = ParseOpenMPParensExpr(getOpenMPClauseName(Kind), RLoc);34173418if (Val.isInvalid())3419return nullptr;34203421if (ParseOnly)3422return nullptr;3423return Actions.OpenMP().ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc,3424LLoc, RLoc);3425}34263427/// Parse indirect clause for '#pragma omp declare target' directive.3428/// 'indirect' '[' '(' invoked-by-fptr ')' ']'3429/// where invoked-by-fptr is a constant boolean expression that evaluates to3430/// true or false at compile time.3431bool Parser::ParseOpenMPIndirectClause(3432SemaOpenMP::DeclareTargetContextInfo &DTCI, bool ParseOnly) {3433SourceLocation Loc = ConsumeToken();3434SourceLocation RLoc;34353436if (Tok.isNot(tok::l_paren)) {3437if (ParseOnly)3438return false;3439DTCI.Indirect = nullptr;3440return true;3441}34423443ExprResult Val =3444ParseOpenMPParensExpr(getOpenMPClauseName(OMPC_indirect), RLoc);3445if (Val.isInvalid())3446return false;34473448if (ParseOnly)3449return false;34503451if (!Val.get()->isValueDependent() && !Val.get()->isTypeDependent() &&3452!Val.get()->isInstantiationDependent() &&3453!Val.get()->containsUnexpandedParameterPack()) {3454ExprResult Ret = Actions.CheckBooleanCondition(Loc, Val.get());3455if (Ret.isInvalid())3456return false;3457llvm::APSInt Result;3458Ret = Actions.VerifyIntegerConstantExpression(Val.get(), &Result,3459Sema::AllowFold);3460if (Ret.isInvalid())3461return false;3462DTCI.Indirect = Val.get();3463return true;3464}3465return false;3466}34673468/// Parses a comma-separated list of interop-types and a prefer_type list.3469///3470bool Parser::ParseOMPInteropInfo(OMPInteropInfo &InteropInfo,3471OpenMPClauseKind Kind) {3472const Token &Tok = getCurToken();3473bool HasError = false;3474bool IsTarget = false;3475bool IsTargetSync = false;34763477while (Tok.is(tok::identifier)) {3478// Currently prefer_type is only allowed with 'init' and it must be first.3479bool PreferTypeAllowed = Kind == OMPC_init &&3480InteropInfo.PreferTypes.empty() && !IsTarget &&3481!IsTargetSync;3482if (Tok.getIdentifierInfo()->isStr("target")) {3483// OpenMP 5.1 [2.15.1, interop Construct, Restrictions]3484// Each interop-type may be specified on an action-clause at most3485// once.3486if (IsTarget)3487Diag(Tok, diag::warn_omp_more_one_interop_type) << "target";3488IsTarget = true;3489ConsumeToken();3490} else if (Tok.getIdentifierInfo()->isStr("targetsync")) {3491if (IsTargetSync)3492Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync";3493IsTargetSync = true;3494ConsumeToken();3495} else if (Tok.getIdentifierInfo()->isStr("prefer_type") &&3496PreferTypeAllowed) {3497ConsumeToken();3498BalancedDelimiterTracker PT(*this, tok::l_paren,3499tok::annot_pragma_openmp_end);3500if (PT.expectAndConsume(diag::err_expected_lparen_after, "prefer_type"))3501HasError = true;35023503while (Tok.isNot(tok::r_paren)) {3504SourceLocation Loc = Tok.getLocation();3505ExprResult LHS = ParseCastExpression(AnyCastExpr);3506ExprResult PTExpr = Actions.CorrectDelayedTyposInExpr(3507ParseRHSOfBinaryExpression(LHS, prec::Conditional));3508PTExpr = Actions.ActOnFinishFullExpr(PTExpr.get(), Loc,3509/*DiscardedValue=*/false);3510if (PTExpr.isUsable()) {3511InteropInfo.PreferTypes.push_back(PTExpr.get());3512} else {3513HasError = true;3514SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,3515StopBeforeMatch);3516}35173518if (Tok.is(tok::comma))3519ConsumeToken();3520}3521PT.consumeClose();3522} else {3523HasError = true;3524Diag(Tok, diag::err_omp_expected_interop_type);3525ConsumeToken();3526}3527if (!Tok.is(tok::comma))3528break;3529ConsumeToken();3530}35313532if (!HasError && !IsTarget && !IsTargetSync) {3533Diag(Tok, diag::err_omp_expected_interop_type);3534HasError = true;3535}35363537if (Kind == OMPC_init) {3538if (Tok.isNot(tok::colon) && (IsTarget || IsTargetSync))3539Diag(Tok, diag::warn_pragma_expected_colon) << "interop types";3540if (Tok.is(tok::colon))3541ConsumeToken();3542}35433544// As of OpenMP 5.1,there are two interop-types, "target" and3545// "targetsync". Either or both are allowed for a single interop.3546InteropInfo.IsTarget = IsTarget;3547InteropInfo.IsTargetSync = IsTargetSync;35483549return HasError;3550}35513552/// Parsing of OpenMP clauses that use an interop-var.3553///3554/// init-clause:3555/// init([interop-modifier, ]interop-type[[, interop-type] ... ]:interop-var)3556///3557/// destroy-clause:3558/// destroy(interop-var)3559///3560/// use-clause:3561/// use(interop-var)3562///3563/// interop-modifier:3564/// prefer_type(preference-list)3565///3566/// preference-list:3567/// foreign-runtime-id [, foreign-runtime-id]...3568///3569/// foreign-runtime-id:3570/// <string-literal> | <constant-integral-expression>3571///3572/// interop-type:3573/// target | targetsync3574///3575OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind,3576bool ParseOnly) {3577SourceLocation Loc = ConsumeToken();3578// Parse '('.3579BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);3580if (T.expectAndConsume(diag::err_expected_lparen_after,3581getOpenMPClauseName(Kind).data()))3582return nullptr;35833584bool InteropError = false;3585OMPInteropInfo InteropInfo;3586if (Kind == OMPC_init)3587InteropError = ParseOMPInteropInfo(InteropInfo, OMPC_init);35883589// Parse the variable.3590SourceLocation VarLoc = Tok.getLocation();3591ExprResult InteropVarExpr =3592Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());3593if (!InteropVarExpr.isUsable()) {3594SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,3595StopBeforeMatch);3596}35973598// Parse ')'.3599SourceLocation RLoc = Tok.getLocation();3600if (!T.consumeClose())3601RLoc = T.getCloseLocation();36023603if (ParseOnly || !InteropVarExpr.isUsable() || InteropError)3604return nullptr;36053606if (Kind == OMPC_init)3607return Actions.OpenMP().ActOnOpenMPInitClause(3608InteropVarExpr.get(), InteropInfo, Loc, T.getOpenLocation(), VarLoc,3609RLoc);3610if (Kind == OMPC_use)3611return Actions.OpenMP().ActOnOpenMPUseClause(3612InteropVarExpr.get(), Loc, T.getOpenLocation(), VarLoc, RLoc);36133614if (Kind == OMPC_destroy)3615return Actions.OpenMP().ActOnOpenMPDestroyClause(3616InteropVarExpr.get(), Loc, T.getOpenLocation(), VarLoc, RLoc);36173618llvm_unreachable("Unexpected interop variable clause.");3619}36203621OMPClause *Parser::ParseOpenMPOMPXAttributesClause(bool ParseOnly) {3622SourceLocation Loc = ConsumeToken();3623// Parse '('.3624BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);3625if (T.expectAndConsume(diag::err_expected_lparen_after,3626getOpenMPClauseName(OMPC_ompx_attribute).data()))3627return nullptr;36283629ParsedAttributes ParsedAttrs(AttrFactory);3630ParseAttributes(PAKM_GNU | PAKM_CXX11, ParsedAttrs);36313632// Parse ')'.3633if (T.consumeClose())3634return nullptr;36353636if (ParseOnly)3637return nullptr;36383639SmallVector<Attr *> Attrs;3640for (const ParsedAttr &PA : ParsedAttrs) {3641switch (PA.getKind()) {3642case ParsedAttr::AT_AMDGPUFlatWorkGroupSize:3643if (!PA.checkExactlyNumArgs(Actions, 2))3644continue;3645if (auto *A = Actions.AMDGPU().CreateAMDGPUFlatWorkGroupSizeAttr(3646PA, PA.getArgAsExpr(0), PA.getArgAsExpr(1)))3647Attrs.push_back(A);3648continue;3649case ParsedAttr::AT_AMDGPUWavesPerEU:3650if (!PA.checkAtLeastNumArgs(Actions, 1) ||3651!PA.checkAtMostNumArgs(Actions, 2))3652continue;3653if (auto *A = Actions.AMDGPU().CreateAMDGPUWavesPerEUAttr(3654PA, PA.getArgAsExpr(0),3655PA.getNumArgs() > 1 ? PA.getArgAsExpr(1) : nullptr))3656Attrs.push_back(A);3657continue;3658case ParsedAttr::AT_CUDALaunchBounds:3659if (!PA.checkAtLeastNumArgs(Actions, 1) ||3660!PA.checkAtMostNumArgs(Actions, 2))3661continue;3662if (auto *A = Actions.CreateLaunchBoundsAttr(3663PA, PA.getArgAsExpr(0),3664PA.getNumArgs() > 1 ? PA.getArgAsExpr(1) : nullptr,3665PA.getNumArgs() > 2 ? PA.getArgAsExpr(2) : nullptr))3666Attrs.push_back(A);3667continue;3668default:3669Diag(Loc, diag::warn_omp_invalid_attribute_for_ompx_attributes) << PA;3670continue;3671};3672}36733674return Actions.OpenMP().ActOnOpenMPXAttributeClause(3675Attrs, Loc, T.getOpenLocation(), T.getCloseLocation());3676}36773678/// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.3679///3680/// default-clause:3681/// 'default' '(' 'none' | 'shared' | 'private' | 'firstprivate' ')'3682///3683/// proc_bind-clause:3684/// 'proc_bind' '(' 'master' | 'close' | 'spread' ')'3685///3686/// bind-clause:3687/// 'bind' '(' 'teams' | 'parallel' | 'thread' ')'3688///3689/// update-clause:3690/// 'update' '(' 'in' | 'out' | 'inout' | 'mutexinoutset' |3691/// 'inoutset' ')'3692///3693OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind,3694bool ParseOnly) {3695std::optional<SimpleClauseData> Val = parseOpenMPSimpleClause(*this, Kind);3696if (!Val || ParseOnly)3697return nullptr;3698if (getLangOpts().OpenMP < 51 && Kind == OMPC_default &&3699(static_cast<DefaultKind>(Val->Type) == OMP_DEFAULT_private ||3700static_cast<DefaultKind>(Val->Type) ==3701OMP_DEFAULT_firstprivate)) {3702Diag(Val->LOpen, diag::err_omp_invalid_dsa)3703<< getOpenMPClauseName(static_cast<DefaultKind>(Val->Type) ==3704OMP_DEFAULT_private3705? OMPC_private3706: OMPC_firstprivate)3707<< getOpenMPClauseName(OMPC_default) << "5.1";3708return nullptr;3709}3710return Actions.OpenMP().ActOnOpenMPSimpleClause(3711Kind, Val->Type, Val->TypeLoc, Val->LOpen, Val->Loc, Val->RLoc);3712}37133714/// Parsing of OpenMP clauses like 'ordered'.3715///3716/// ordered-clause:3717/// 'ordered'3718///3719/// nowait-clause:3720/// 'nowait'3721///3722/// untied-clause:3723/// 'untied'3724///3725/// mergeable-clause:3726/// 'mergeable'3727///3728/// read-clause:3729/// 'read'3730///3731/// threads-clause:3732/// 'threads'3733///3734/// simd-clause:3735/// 'simd'3736///3737/// nogroup-clause:3738/// 'nogroup'3739///3740OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind, bool ParseOnly) {3741SourceLocation Loc = Tok.getLocation();3742ConsumeAnyToken();37433744if (ParseOnly)3745return nullptr;3746return Actions.OpenMP().ActOnOpenMPClause(Kind, Loc, Tok.getLocation());3747}37483749/// Parsing of OpenMP clauses with single expressions and some additional3750/// argument like 'schedule' or 'dist_schedule'.3751///3752/// schedule-clause:3753/// 'schedule' '(' [ modifier [ ',' modifier ] ':' ] kind [',' expression ]3754/// ')'3755///3756/// if-clause:3757/// 'if' '(' [ directive-name-modifier ':' ] expression ')'3758///3759/// defaultmap:3760/// 'defaultmap' '(' modifier [ ':' kind ] ')'3761///3762/// device-clause:3763/// 'device' '(' [ device-modifier ':' ] expression ')'3764///3765OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind,3766OpenMPClauseKind Kind,3767bool ParseOnly) {3768SourceLocation Loc = ConsumeToken();3769SourceLocation DelimLoc;3770// Parse '('.3771BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);3772if (T.expectAndConsume(diag::err_expected_lparen_after,3773getOpenMPClauseName(Kind).data()))3774return nullptr;37753776ExprResult Val;3777SmallVector<unsigned, 4> Arg;3778SmallVector<SourceLocation, 4> KLoc;3779if (Kind == OMPC_schedule) {3780enum { Modifier1, Modifier2, ScheduleKind, NumberOfElements };3781Arg.resize(NumberOfElements);3782KLoc.resize(NumberOfElements);3783Arg[Modifier1] = OMPC_SCHEDULE_MODIFIER_unknown;3784Arg[Modifier2] = OMPC_SCHEDULE_MODIFIER_unknown;3785Arg[ScheduleKind] = OMPC_SCHEDULE_unknown;3786unsigned KindModifier = getOpenMPSimpleClauseType(3787Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());3788if (KindModifier > OMPC_SCHEDULE_unknown) {3789// Parse 'modifier'3790Arg[Modifier1] = KindModifier;3791KLoc[Modifier1] = Tok.getLocation();3792if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3793Tok.isNot(tok::annot_pragma_openmp_end))3794ConsumeAnyToken();3795if (Tok.is(tok::comma)) {3796// Parse ',' 'modifier'3797ConsumeAnyToken();3798KindModifier = getOpenMPSimpleClauseType(3799Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());3800Arg[Modifier2] = KindModifier > OMPC_SCHEDULE_unknown3801? KindModifier3802: (unsigned)OMPC_SCHEDULE_unknown;3803KLoc[Modifier2] = Tok.getLocation();3804if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3805Tok.isNot(tok::annot_pragma_openmp_end))3806ConsumeAnyToken();3807}3808// Parse ':'3809if (Tok.is(tok::colon))3810ConsumeAnyToken();3811else3812Diag(Tok, diag::warn_pragma_expected_colon) << "schedule modifier";3813KindModifier = getOpenMPSimpleClauseType(3814Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());3815}3816Arg[ScheduleKind] = KindModifier;3817KLoc[ScheduleKind] = Tok.getLocation();3818if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3819Tok.isNot(tok::annot_pragma_openmp_end))3820ConsumeAnyToken();3821if ((Arg[ScheduleKind] == OMPC_SCHEDULE_static ||3822Arg[ScheduleKind] == OMPC_SCHEDULE_dynamic ||3823Arg[ScheduleKind] == OMPC_SCHEDULE_guided) &&3824Tok.is(tok::comma))3825DelimLoc = ConsumeAnyToken();3826} else if (Kind == OMPC_dist_schedule) {3827Arg.push_back(getOpenMPSimpleClauseType(3828Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()));3829KLoc.push_back(Tok.getLocation());3830if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3831Tok.isNot(tok::annot_pragma_openmp_end))3832ConsumeAnyToken();3833if (Arg.back() == OMPC_DIST_SCHEDULE_static && Tok.is(tok::comma))3834DelimLoc = ConsumeAnyToken();3835} else if (Kind == OMPC_defaultmap) {3836// Get a defaultmap modifier3837unsigned Modifier = getOpenMPSimpleClauseType(3838Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());3839// Set defaultmap modifier to unknown if it is either scalar, aggregate, or3840// pointer3841if (Modifier < OMPC_DEFAULTMAP_MODIFIER_unknown)3842Modifier = OMPC_DEFAULTMAP_MODIFIER_unknown;3843Arg.push_back(Modifier);3844KLoc.push_back(Tok.getLocation());3845if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3846Tok.isNot(tok::annot_pragma_openmp_end))3847ConsumeAnyToken();3848// Parse ':'3849if (Tok.is(tok::colon) || getLangOpts().OpenMP < 50) {3850if (Tok.is(tok::colon))3851ConsumeAnyToken();3852else if (Arg.back() != OMPC_DEFAULTMAP_MODIFIER_unknown)3853Diag(Tok, diag::warn_pragma_expected_colon) << "defaultmap modifier";3854// Get a defaultmap kind3855Arg.push_back(getOpenMPSimpleClauseType(3856Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()));3857KLoc.push_back(Tok.getLocation());3858if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3859Tok.isNot(tok::annot_pragma_openmp_end))3860ConsumeAnyToken();3861} else {3862Arg.push_back(OMPC_DEFAULTMAP_unknown);3863KLoc.push_back(SourceLocation());3864}3865} else if (Kind == OMPC_order) {3866enum { Modifier, OrderKind, NumberOfElements };3867Arg.resize(NumberOfElements);3868KLoc.resize(NumberOfElements);3869Arg[Modifier] = OMPC_ORDER_MODIFIER_unknown;3870Arg[OrderKind] = OMPC_ORDER_unknown;3871unsigned KindModifier = getOpenMPSimpleClauseType(3872Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());3873if (KindModifier > OMPC_ORDER_unknown) {3874// Parse 'modifier'3875Arg[Modifier] = KindModifier;3876KLoc[Modifier] = Tok.getLocation();3877if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3878Tok.isNot(tok::annot_pragma_openmp_end))3879ConsumeAnyToken();3880// Parse ':'3881if (Tok.is(tok::colon))3882ConsumeAnyToken();3883else3884Diag(Tok, diag::warn_pragma_expected_colon) << "order modifier";3885KindModifier = getOpenMPSimpleClauseType(3886Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());3887}3888Arg[OrderKind] = KindModifier;3889KLoc[OrderKind] = Tok.getLocation();3890if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3891Tok.isNot(tok::annot_pragma_openmp_end))3892ConsumeAnyToken();3893} else if (Kind == OMPC_device) {3894// Only target executable directives support extended device construct.3895if (isOpenMPTargetExecutionDirective(DKind) && getLangOpts().OpenMP >= 50 &&3896NextToken().is(tok::colon)) {3897// Parse optional <device modifier> ':'3898Arg.push_back(getOpenMPSimpleClauseType(3899Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()));3900KLoc.push_back(Tok.getLocation());3901ConsumeAnyToken();3902// Parse ':'3903ConsumeAnyToken();3904} else {3905Arg.push_back(OMPC_DEVICE_unknown);3906KLoc.emplace_back();3907}3908} else if (Kind == OMPC_grainsize) {3909// Parse optional <grainsize modifier> ':'3910OpenMPGrainsizeClauseModifier Modifier =3911static_cast<OpenMPGrainsizeClauseModifier>(getOpenMPSimpleClauseType(3912Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok),3913getLangOpts()));3914if (getLangOpts().OpenMP >= 51) {3915if (NextToken().is(tok::colon)) {3916Arg.push_back(Modifier);3917KLoc.push_back(Tok.getLocation());3918// Parse modifier3919ConsumeAnyToken();3920// Parse ':'3921ConsumeAnyToken();3922} else {3923if (Modifier == OMPC_GRAINSIZE_strict) {3924Diag(Tok, diag::err_modifier_expected_colon) << "strict";3925// Parse modifier3926ConsumeAnyToken();3927}3928Arg.push_back(OMPC_GRAINSIZE_unknown);3929KLoc.emplace_back();3930}3931} else {3932Arg.push_back(OMPC_GRAINSIZE_unknown);3933KLoc.emplace_back();3934}3935} else if (Kind == OMPC_num_tasks) {3936// Parse optional <num_tasks modifier> ':'3937OpenMPNumTasksClauseModifier Modifier =3938static_cast<OpenMPNumTasksClauseModifier>(getOpenMPSimpleClauseType(3939Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok),3940getLangOpts()));3941if (getLangOpts().OpenMP >= 51) {3942if (NextToken().is(tok::colon)) {3943Arg.push_back(Modifier);3944KLoc.push_back(Tok.getLocation());3945// Parse modifier3946ConsumeAnyToken();3947// Parse ':'3948ConsumeAnyToken();3949} else {3950if (Modifier == OMPC_NUMTASKS_strict) {3951Diag(Tok, diag::err_modifier_expected_colon) << "strict";3952// Parse modifier3953ConsumeAnyToken();3954}3955Arg.push_back(OMPC_NUMTASKS_unknown);3956KLoc.emplace_back();3957}3958} else {3959Arg.push_back(OMPC_NUMTASKS_unknown);3960KLoc.emplace_back();3961}3962} else {3963assert(Kind == OMPC_if);3964KLoc.push_back(Tok.getLocation());3965TentativeParsingAction TPA(*this);3966auto DK = parseOpenMPDirectiveKind(*this);3967Arg.push_back(DK);3968if (DK != OMPD_unknown) {3969ConsumeToken();3970if (Tok.is(tok::colon) && getLangOpts().OpenMP > 40) {3971TPA.Commit();3972DelimLoc = ConsumeToken();3973} else {3974TPA.Revert();3975Arg.back() = unsigned(OMPD_unknown);3976}3977} else {3978TPA.Revert();3979}3980}39813982bool NeedAnExpression = (Kind == OMPC_schedule && DelimLoc.isValid()) ||3983(Kind == OMPC_dist_schedule && DelimLoc.isValid()) ||3984Kind == OMPC_if || Kind == OMPC_device ||3985Kind == OMPC_grainsize || Kind == OMPC_num_tasks;3986if (NeedAnExpression) {3987SourceLocation ELoc = Tok.getLocation();3988ExprResult LHS(ParseCastExpression(AnyCastExpr, false, NotTypeCast));3989Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional);3990Val =3991Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false);3992}39933994// Parse ')'.3995SourceLocation RLoc = Tok.getLocation();3996if (!T.consumeClose())3997RLoc = T.getCloseLocation();39983999if (NeedAnExpression && Val.isInvalid())4000return nullptr;40014002if (ParseOnly)4003return nullptr;4004return Actions.OpenMP().ActOnOpenMPSingleExprWithArgClause(4005Kind, Arg, Val.get(), Loc, T.getOpenLocation(), KLoc, DelimLoc, RLoc);4006}40074008static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,4009UnqualifiedId &ReductionId) {4010if (ReductionIdScopeSpec.isEmpty()) {4011auto OOK = OO_None;4012switch (P.getCurToken().getKind()) {4013case tok::plus:4014OOK = OO_Plus;4015break;4016case tok::minus:4017OOK = OO_Minus;4018break;4019case tok::star:4020OOK = OO_Star;4021break;4022case tok::amp:4023OOK = OO_Amp;4024break;4025case tok::pipe:4026OOK = OO_Pipe;4027break;4028case tok::caret:4029OOK = OO_Caret;4030break;4031case tok::ampamp:4032OOK = OO_AmpAmp;4033break;4034case tok::pipepipe:4035OOK = OO_PipePipe;4036break;4037default:4038break;4039}4040if (OOK != OO_None) {4041SourceLocation OpLoc = P.ConsumeToken();4042SourceLocation SymbolLocations[] = {OpLoc, OpLoc, SourceLocation()};4043ReductionId.setOperatorFunctionId(OpLoc, OOK, SymbolLocations);4044return false;4045}4046}4047return P.ParseUnqualifiedId(4048ReductionIdScopeSpec, /*ObjectType=*/nullptr,4049/*ObjectHadErrors=*/false, /*EnteringContext*/ false,4050/*AllowDestructorName*/ false,4051/*AllowConstructorName*/ false,4052/*AllowDeductionGuide*/ false, nullptr, ReductionId);4053}40544055/// Checks if the token is a valid map-type-modifier.4056/// FIXME: It will return an OpenMPMapClauseKind if that's what it parses.4057static OpenMPMapModifierKind isMapModifier(Parser &P) {4058Token Tok = P.getCurToken();4059if (!Tok.is(tok::identifier))4060return OMPC_MAP_MODIFIER_unknown;40614062Preprocessor &PP = P.getPreprocessor();4063OpenMPMapModifierKind TypeModifier =4064static_cast<OpenMPMapModifierKind>(getOpenMPSimpleClauseType(4065OMPC_map, PP.getSpelling(Tok), P.getLangOpts()));4066return TypeModifier;4067}40684069/// Parse the mapper modifier in map, to, and from clauses.4070bool Parser::parseMapperModifier(SemaOpenMP::OpenMPVarListDataTy &Data) {4071// Parse '('.4072BalancedDelimiterTracker T(*this, tok::l_paren, tok::colon);4073if (T.expectAndConsume(diag::err_expected_lparen_after, "mapper")) {4074SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,4075StopBeforeMatch);4076return true;4077}4078// Parse mapper-identifier4079if (getLangOpts().CPlusPlus)4080ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec,4081/*ObjectType=*/nullptr,4082/*ObjectHasErrors=*/false,4083/*EnteringContext=*/false);4084if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_default)) {4085Diag(Tok.getLocation(), diag::err_omp_mapper_illegal_identifier);4086SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,4087StopBeforeMatch);4088return true;4089}4090auto &DeclNames = Actions.getASTContext().DeclarationNames;4091Data.ReductionOrMapperId = DeclarationNameInfo(4092DeclNames.getIdentifier(Tok.getIdentifierInfo()), Tok.getLocation());4093ConsumeToken();4094// Parse ')'.4095return T.consumeClose();4096}40974098static OpenMPMapClauseKind isMapType(Parser &P);40994100/// Parse map-type-modifiers in map clause.4101/// map([ [map-type-modifier[,] [map-type-modifier[,] ...] [map-type] : ] list)4102/// where, map-type-modifier ::= always | close | mapper(mapper-identifier) |4103/// present4104/// where, map-type ::= alloc | delete | from | release | to | tofrom4105bool Parser::parseMapTypeModifiers(SemaOpenMP::OpenMPVarListDataTy &Data) {4106bool HasMapType = false;4107SourceLocation PreMapLoc = Tok.getLocation();4108StringRef PreMapName = "";4109while (getCurToken().isNot(tok::colon)) {4110OpenMPMapModifierKind TypeModifier = isMapModifier(*this);4111OpenMPMapClauseKind MapKind = isMapType(*this);4112if (TypeModifier == OMPC_MAP_MODIFIER_always ||4113TypeModifier == OMPC_MAP_MODIFIER_close ||4114TypeModifier == OMPC_MAP_MODIFIER_present ||4115TypeModifier == OMPC_MAP_MODIFIER_ompx_hold) {4116Data.MapTypeModifiers.push_back(TypeModifier);4117Data.MapTypeModifiersLoc.push_back(Tok.getLocation());4118if (PP.LookAhead(0).isNot(tok::comma) &&4119PP.LookAhead(0).isNot(tok::colon) && getLangOpts().OpenMP >= 52)4120Diag(Tok.getLocation(), diag::err_omp_missing_comma)4121<< "map type modifier";4122ConsumeToken();4123} else if (TypeModifier == OMPC_MAP_MODIFIER_mapper) {4124Data.MapTypeModifiers.push_back(TypeModifier);4125Data.MapTypeModifiersLoc.push_back(Tok.getLocation());4126ConsumeToken();4127if (parseMapperModifier(Data))4128return true;4129if (Tok.isNot(tok::comma) && Tok.isNot(tok::colon) &&4130getLangOpts().OpenMP >= 52)4131Diag(Data.MapTypeModifiersLoc.back(), diag::err_omp_missing_comma)4132<< "map type modifier";41334134} else if (getLangOpts().OpenMP >= 60 && MapKind != OMPC_MAP_unknown) {4135if (!HasMapType) {4136HasMapType = true;4137Data.ExtraModifier = MapKind;4138MapKind = OMPC_MAP_unknown;4139PreMapLoc = Tok.getLocation();4140PreMapName = Tok.getIdentifierInfo()->getName();4141} else {4142Diag(Tok, diag::err_omp_more_one_map_type);4143Diag(PreMapLoc, diag::note_previous_map_type_specified_here)4144<< PreMapName;4145}4146ConsumeToken();4147} else {4148// For the case of unknown map-type-modifier or a map-type.4149// Map-type is followed by a colon; the function returns when it4150// encounters a token followed by a colon.4151if (Tok.is(tok::comma)) {4152Diag(Tok, diag::err_omp_map_type_modifier_missing);4153ConsumeToken();4154continue;4155}4156// Potential map-type token as it is followed by a colon.4157if (PP.LookAhead(0).is(tok::colon)) {4158if (getLangOpts().OpenMP >= 60) {4159break;4160} else {4161return false;4162}4163}41644165Diag(Tok, diag::err_omp_unknown_map_type_modifier)4166<< (getLangOpts().OpenMP >= 51 ? (getLangOpts().OpenMP >= 52 ? 2 : 1)4167: 0)4168<< getLangOpts().OpenMPExtensions;4169ConsumeToken();4170}4171if (getCurToken().is(tok::comma))4172ConsumeToken();4173}4174if (getLangOpts().OpenMP >= 60 && !HasMapType) {4175if (!Tok.is(tok::colon)) {4176Diag(Tok, diag::err_omp_unknown_map_type);4177ConsumeToken();4178} else {4179Data.ExtraModifier = OMPC_MAP_unknown;4180}4181}4182return false;4183}41844185/// Checks if the token is a valid map-type.4186/// If it is not MapType kind, OMPC_MAP_unknown is returned.4187static OpenMPMapClauseKind isMapType(Parser &P) {4188Token Tok = P.getCurToken();4189// The map-type token can be either an identifier or the C++ delete keyword.4190if (!Tok.isOneOf(tok::identifier, tok::kw_delete))4191return OMPC_MAP_unknown;4192Preprocessor &PP = P.getPreprocessor();4193unsigned MapType =4194getOpenMPSimpleClauseType(OMPC_map, PP.getSpelling(Tok), P.getLangOpts());4195if (MapType == OMPC_MAP_to || MapType == OMPC_MAP_from ||4196MapType == OMPC_MAP_tofrom || MapType == OMPC_MAP_alloc ||4197MapType == OMPC_MAP_delete || MapType == OMPC_MAP_release)4198return static_cast<OpenMPMapClauseKind>(MapType);4199return OMPC_MAP_unknown;4200}42014202/// Parse map-type in map clause.4203/// map([ [map-type-modifier[,] [map-type-modifier[,] ...] map-type : ] list)4204/// where, map-type ::= to | from | tofrom | alloc | release | delete4205static void parseMapType(Parser &P, SemaOpenMP::OpenMPVarListDataTy &Data) {4206Token Tok = P.getCurToken();4207if (Tok.is(tok::colon)) {4208P.Diag(Tok, diag::err_omp_map_type_missing);4209return;4210}4211Data.ExtraModifier = isMapType(P);4212if (Data.ExtraModifier == OMPC_MAP_unknown)4213P.Diag(Tok, diag::err_omp_unknown_map_type);4214P.ConsumeToken();4215}42164217/// Parses simple expression in parens for single-expression clauses of OpenMP4218/// constructs.4219ExprResult Parser::ParseOpenMPIteratorsExpr() {4220assert(Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator" &&4221"Expected 'iterator' token.");4222SourceLocation IteratorKwLoc = ConsumeToken();42234224BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);4225if (T.expectAndConsume(diag::err_expected_lparen_after, "iterator"))4226return ExprError();42274228SourceLocation LLoc = T.getOpenLocation();4229SmallVector<SemaOpenMP::OMPIteratorData, 4> Data;4230while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {4231// Check if the type parsing is required.4232ParsedType IteratorType;4233if (Tok.isNot(tok::identifier) || NextToken().isNot(tok::equal)) {4234// identifier '=' is not found - parse type.4235TypeResult TR = ParseTypeName();4236if (TR.isInvalid()) {4237T.skipToEnd();4238return ExprError();4239}4240IteratorType = TR.get();4241}42424243// Parse identifier.4244IdentifierInfo *II = nullptr;4245SourceLocation IdLoc;4246if (Tok.is(tok::identifier)) {4247II = Tok.getIdentifierInfo();4248IdLoc = ConsumeToken();4249} else {4250Diag(Tok, diag::err_expected_unqualified_id) << 0;4251}42524253// Parse '='.4254SourceLocation AssignLoc;4255if (Tok.is(tok::equal))4256AssignLoc = ConsumeToken();4257else4258Diag(Tok, diag::err_omp_expected_equal_in_iterator);42594260// Parse range-specification - <begin> ':' <end> [ ':' <step> ]4261ColonProtectionRAIIObject ColonRAII(*this);4262// Parse <begin>4263SourceLocation Loc = Tok.getLocation();4264ExprResult LHS = ParseCastExpression(AnyCastExpr);4265ExprResult Begin = Actions.CorrectDelayedTyposInExpr(4266ParseRHSOfBinaryExpression(LHS, prec::Conditional));4267Begin = Actions.ActOnFinishFullExpr(Begin.get(), Loc,4268/*DiscardedValue=*/false);4269// Parse ':'.4270SourceLocation ColonLoc;4271if (Tok.is(tok::colon))4272ColonLoc = ConsumeToken();42734274// Parse <end>4275Loc = Tok.getLocation();4276LHS = ParseCastExpression(AnyCastExpr);4277ExprResult End = Actions.CorrectDelayedTyposInExpr(4278ParseRHSOfBinaryExpression(LHS, prec::Conditional));4279End = Actions.ActOnFinishFullExpr(End.get(), Loc,4280/*DiscardedValue=*/false);42814282SourceLocation SecColonLoc;4283ExprResult Step;4284// Parse optional step.4285if (Tok.is(tok::colon)) {4286// Parse ':'4287SecColonLoc = ConsumeToken();4288// Parse <step>4289Loc = Tok.getLocation();4290LHS = ParseCastExpression(AnyCastExpr);4291Step = Actions.CorrectDelayedTyposInExpr(4292ParseRHSOfBinaryExpression(LHS, prec::Conditional));4293Step = Actions.ActOnFinishFullExpr(Step.get(), Loc,4294/*DiscardedValue=*/false);4295}42964297// Parse ',' or ')'4298if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren))4299Diag(Tok, diag::err_omp_expected_punc_after_iterator);4300if (Tok.is(tok::comma))4301ConsumeToken();43024303SemaOpenMP::OMPIteratorData &D = Data.emplace_back();4304D.DeclIdent = II;4305D.DeclIdentLoc = IdLoc;4306D.Type = IteratorType;4307D.AssignLoc = AssignLoc;4308D.ColonLoc = ColonLoc;4309D.SecColonLoc = SecColonLoc;4310D.Range.Begin = Begin.get();4311D.Range.End = End.get();4312D.Range.Step = Step.get();4313}43144315// Parse ')'.4316SourceLocation RLoc = Tok.getLocation();4317if (!T.consumeClose())4318RLoc = T.getCloseLocation();43194320return Actions.OpenMP().ActOnOMPIteratorExpr(getCurScope(), IteratorKwLoc,4321LLoc, RLoc, Data);4322}43234324bool Parser::ParseOpenMPReservedLocator(OpenMPClauseKind Kind,4325SemaOpenMP::OpenMPVarListDataTy &Data,4326const LangOptions &LangOpts) {4327// Currently the only reserved locator is 'omp_all_memory' which is only4328// allowed on a depend clause.4329if (Kind != OMPC_depend || LangOpts.OpenMP < 51)4330return false;43314332if (Tok.is(tok::identifier) &&4333Tok.getIdentifierInfo()->isStr("omp_all_memory")) {43344335if (Data.ExtraModifier == OMPC_DEPEND_outallmemory ||4336Data.ExtraModifier == OMPC_DEPEND_inoutallmemory)4337Diag(Tok, diag::warn_omp_more_one_omp_all_memory);4338else if (Data.ExtraModifier != OMPC_DEPEND_out &&4339Data.ExtraModifier != OMPC_DEPEND_inout)4340Diag(Tok, diag::err_omp_requires_out_inout_depend_type);4341else4342Data.ExtraModifier = Data.ExtraModifier == OMPC_DEPEND_out4343? OMPC_DEPEND_outallmemory4344: OMPC_DEPEND_inoutallmemory;4345ConsumeToken();4346return true;4347}4348return false;4349}43504351/// Parse step size expression. Returns true if parsing is successfull,4352/// otherwise returns false.4353static bool parseStepSize(Parser &P, SemaOpenMP::OpenMPVarListDataTy &Data,4354OpenMPClauseKind CKind, SourceLocation ELoc) {4355ExprResult Tail = P.ParseAssignmentExpression();4356Sema &Actions = P.getActions();4357Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc,4358/*DiscardedValue*/ false);4359if (Tail.isUsable()) {4360Data.DepModOrTailExpr = Tail.get();4361Token CurTok = P.getCurToken();4362if (CurTok.isNot(tok::r_paren) && CurTok.isNot(tok::comma)) {4363P.Diag(CurTok, diag::err_expected_punc) << "step expression";4364}4365return true;4366}4367return false;4368}43694370/// Parses clauses with list.4371bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,4372OpenMPClauseKind Kind,4373SmallVectorImpl<Expr *> &Vars,4374SemaOpenMP::OpenMPVarListDataTy &Data) {4375UnqualifiedId UnqualifiedReductionId;4376bool InvalidReductionId = false;4377bool IsInvalidMapperModifier = false;43784379// Parse '('.4380BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);4381if (T.expectAndConsume(diag::err_expected_lparen_after,4382getOpenMPClauseName(Kind).data()))4383return true;43844385bool HasIterator = false;4386bool InvalidIterator = false;4387bool NeedRParenForLinear = false;4388BalancedDelimiterTracker LinearT(*this, tok::l_paren,4389tok::annot_pragma_openmp_end);4390// Handle reduction-identifier for reduction clause.4391if (Kind == OMPC_reduction || Kind == OMPC_task_reduction ||4392Kind == OMPC_in_reduction) {4393Data.ExtraModifier = OMPC_REDUCTION_unknown;4394if (Kind == OMPC_reduction && getLangOpts().OpenMP >= 50 &&4395(Tok.is(tok::identifier) || Tok.is(tok::kw_default)) &&4396NextToken().is(tok::comma)) {4397// Parse optional reduction modifier.4398Data.ExtraModifier =4399getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts());4400Data.ExtraModifierLoc = Tok.getLocation();4401ConsumeToken();4402assert(Tok.is(tok::comma) && "Expected comma.");4403(void)ConsumeToken();4404}4405ColonProtectionRAIIObject ColonRAII(*this);4406if (getLangOpts().CPlusPlus)4407ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec,4408/*ObjectType=*/nullptr,4409/*ObjectHasErrors=*/false,4410/*EnteringContext=*/false);4411InvalidReductionId = ParseReductionId(4412*this, Data.ReductionOrMapperIdScopeSpec, UnqualifiedReductionId);4413if (InvalidReductionId) {4414SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,4415StopBeforeMatch);4416}4417if (Tok.is(tok::colon))4418Data.ColonLoc = ConsumeToken();4419else4420Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier";4421if (!InvalidReductionId)4422Data.ReductionOrMapperId =4423Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId);4424} else if (Kind == OMPC_depend || Kind == OMPC_doacross) {4425if (getLangOpts().OpenMP >= 50) {4426if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") {4427// Handle optional dependence modifier.4428// iterator(iterators-definition)4429// where iterators-definition is iterator-specifier [,4430// iterators-definition ]4431// where iterator-specifier is [ iterator-type ] identifier =4432// range-specification4433HasIterator = true;4434EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);4435ExprResult IteratorRes = ParseOpenMPIteratorsExpr();4436Data.DepModOrTailExpr = IteratorRes.get();4437// Parse ','4438ExpectAndConsume(tok::comma);4439}4440}4441// Handle dependency type for depend clause.4442ColonProtectionRAIIObject ColonRAII(*this);4443Data.ExtraModifier = getOpenMPSimpleClauseType(4444Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "",4445getLangOpts());4446Data.ExtraModifierLoc = Tok.getLocation();4447if ((Kind == OMPC_depend && Data.ExtraModifier == OMPC_DEPEND_unknown) ||4448(Kind == OMPC_doacross &&4449Data.ExtraModifier == OMPC_DOACROSS_unknown)) {4450SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,4451StopBeforeMatch);4452} else {4453ConsumeToken();4454// Special processing for depend(source) clause.4455if (DKind == OMPD_ordered && Kind == OMPC_depend &&4456Data.ExtraModifier == OMPC_DEPEND_source) {4457// Parse ')'.4458T.consumeClose();4459return false;4460}4461}4462if (Tok.is(tok::colon)) {4463Data.ColonLoc = ConsumeToken();4464} else if (Kind != OMPC_doacross || Tok.isNot(tok::r_paren)) {4465Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren4466: diag::warn_pragma_expected_colon)4467<< (Kind == OMPC_depend ? "dependency type" : "dependence-type");4468}4469if (Kind == OMPC_doacross) {4470if (Tok.is(tok::identifier) &&4471Tok.getIdentifierInfo()->isStr("omp_cur_iteration")) {4472Data.ExtraModifier = Data.ExtraModifier == OMPC_DOACROSS_source4473? OMPC_DOACROSS_source_omp_cur_iteration4474: OMPC_DOACROSS_sink_omp_cur_iteration;4475ConsumeToken();4476}4477if (Data.ExtraModifier == OMPC_DOACROSS_sink_omp_cur_iteration) {4478if (Tok.isNot(tok::minus)) {4479Diag(Tok, diag::err_omp_sink_and_source_iteration_not_allowd)4480<< getOpenMPClauseName(Kind) << 0 << 0;4481SkipUntil(tok::r_paren);4482return false;4483} else {4484ConsumeToken();4485SourceLocation Loc = Tok.getLocation();4486uint64_t Value = 0;4487if (Tok.isNot(tok::numeric_constant) ||4488(PP.parseSimpleIntegerLiteral(Tok, Value) && Value != 1)) {4489Diag(Loc, diag::err_omp_sink_and_source_iteration_not_allowd)4490<< getOpenMPClauseName(Kind) << 0 << 0;4491SkipUntil(tok::r_paren);4492return false;4493}4494}4495}4496if (Data.ExtraModifier == OMPC_DOACROSS_source_omp_cur_iteration) {4497if (Tok.isNot(tok::r_paren)) {4498Diag(Tok, diag::err_omp_sink_and_source_iteration_not_allowd)4499<< getOpenMPClauseName(Kind) << 1 << 1;4500SkipUntil(tok::r_paren);4501return false;4502}4503}4504// Only the 'sink' case has the expression list.4505if (Kind == OMPC_doacross &&4506(Data.ExtraModifier == OMPC_DOACROSS_source ||4507Data.ExtraModifier == OMPC_DOACROSS_source_omp_cur_iteration ||4508Data.ExtraModifier == OMPC_DOACROSS_sink_omp_cur_iteration)) {4509// Parse ')'.4510T.consumeClose();4511return false;4512}4513}4514} else if (Kind == OMPC_linear) {4515// Try to parse modifier if any.4516Data.ExtraModifier = OMPC_LINEAR_val;4517if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) {4518Data.ExtraModifier =4519getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts());4520Data.ExtraModifierLoc = ConsumeToken();4521LinearT.consumeOpen();4522NeedRParenForLinear = true;4523if (getLangOpts().OpenMP >= 52)4524Diag(Data.ExtraModifierLoc, diag::err_omp_deprecate_old_syntax)4525<< "linear-modifier(list)" << getOpenMPClauseName(Kind)4526<< "linear(list: [linear-modifier,] step(step-size))";4527}4528} else if (Kind == OMPC_lastprivate) {4529// Try to parse modifier if any.4530Data.ExtraModifier = OMPC_LASTPRIVATE_unknown;4531// Conditional modifier allowed only in OpenMP 5.0 and not supported in4532// distribute and taskloop based directives.4533if ((getLangOpts().OpenMP >= 50 && !isOpenMPDistributeDirective(DKind) &&4534!isOpenMPTaskLoopDirective(DKind)) &&4535Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::colon)) {4536Data.ExtraModifier =4537getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts());4538Data.ExtraModifierLoc = Tok.getLocation();4539ConsumeToken();4540assert(Tok.is(tok::colon) && "Expected colon.");4541Data.ColonLoc = ConsumeToken();4542}4543} else if (Kind == OMPC_map) {4544// Handle optional iterator map modifier.4545if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") {4546HasIterator = true;4547EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);4548Data.MapTypeModifiers.push_back(OMPC_MAP_MODIFIER_iterator);4549Data.MapTypeModifiersLoc.push_back(Tok.getLocation());4550ExprResult IteratorRes = ParseOpenMPIteratorsExpr();4551Data.IteratorExpr = IteratorRes.get();4552// Parse ','4553ExpectAndConsume(tok::comma);4554if (getLangOpts().OpenMP < 52) {4555Diag(Tok, diag::err_omp_unknown_map_type_modifier)4556<< (getLangOpts().OpenMP >= 51 ? 1 : 0)4557<< getLangOpts().OpenMPExtensions;4558InvalidIterator = true;4559}4560}4561// Handle map type for map clause.4562ColonProtectionRAIIObject ColonRAII(*this);45634564// The first identifier may be a list item, a map-type or a4565// map-type-modifier. The map-type can also be delete which has the same4566// spelling of the C++ delete keyword.4567Data.ExtraModifier = OMPC_MAP_unknown;4568Data.ExtraModifierLoc = Tok.getLocation();45694570// Check for presence of a colon in the map clause.4571TentativeParsingAction TPA(*this);4572bool ColonPresent = false;4573if (SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,4574StopBeforeMatch)) {4575if (Tok.is(tok::colon))4576ColonPresent = true;4577}4578TPA.Revert();4579// Only parse map-type-modifier[s] and map-type if a colon is present in4580// the map clause.4581if (ColonPresent) {4582if (getLangOpts().OpenMP >= 60 && getCurToken().is(tok::colon))4583Diag(Tok, diag::err_omp_map_modifier_specification_list);4584IsInvalidMapperModifier = parseMapTypeModifiers(Data);4585if (getLangOpts().OpenMP < 60 && !IsInvalidMapperModifier)4586parseMapType(*this, Data);4587else4588SkipUntil(tok::colon, tok::annot_pragma_openmp_end, StopBeforeMatch);4589}4590if (Data.ExtraModifier == OMPC_MAP_unknown) {4591Data.ExtraModifier = OMPC_MAP_tofrom;4592if (getLangOpts().OpenMP >= 52) {4593if (DKind == OMPD_target_enter_data)4594Data.ExtraModifier = OMPC_MAP_to;4595else if (DKind == OMPD_target_exit_data)4596Data.ExtraModifier = OMPC_MAP_from;4597}4598Data.IsMapTypeImplicit = true;4599}46004601if (Tok.is(tok::colon))4602Data.ColonLoc = ConsumeToken();4603} else if (Kind == OMPC_to || Kind == OMPC_from) {4604while (Tok.is(tok::identifier)) {4605auto Modifier = static_cast<OpenMPMotionModifierKind>(4606getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts()));4607if (Modifier == OMPC_MOTION_MODIFIER_unknown)4608break;4609Data.MotionModifiers.push_back(Modifier);4610Data.MotionModifiersLoc.push_back(Tok.getLocation());4611ConsumeToken();4612if (Modifier == OMPC_MOTION_MODIFIER_mapper) {4613IsInvalidMapperModifier = parseMapperModifier(Data);4614if (IsInvalidMapperModifier)4615break;4616}4617// OpenMP < 5.1 doesn't permit a ',' or additional modifiers.4618if (getLangOpts().OpenMP < 51)4619break;4620// OpenMP 5.1 accepts an optional ',' even if the next character is ':'.4621// TODO: Is that intentional?4622if (Tok.is(tok::comma))4623ConsumeToken();4624}4625if (!Data.MotionModifiers.empty() && Tok.isNot(tok::colon)) {4626if (!IsInvalidMapperModifier) {4627if (getLangOpts().OpenMP < 51)4628Diag(Tok, diag::warn_pragma_expected_colon) << ")";4629else4630Diag(Tok, diag::warn_pragma_expected_colon) << "motion modifier";4631}4632SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,4633StopBeforeMatch);4634}4635// OpenMP 5.1 permits a ':' even without a preceding modifier. TODO: Is4636// that intentional?4637if ((!Data.MotionModifiers.empty() || getLangOpts().OpenMP >= 51) &&4638Tok.is(tok::colon))4639Data.ColonLoc = ConsumeToken();4640} else if (Kind == OMPC_allocate ||4641(Kind == OMPC_affinity && Tok.is(tok::identifier) &&4642PP.getSpelling(Tok) == "iterator")) {4643// Handle optional allocator expression followed by colon delimiter.4644ColonProtectionRAIIObject ColonRAII(*this);4645TentativeParsingAction TPA(*this);4646// OpenMP 5.0, 2.10.1, task Construct.4647// where aff-modifier is one of the following:4648// iterator(iterators-definition)4649ExprResult Tail;4650if (Kind == OMPC_allocate) {4651Tail = ParseAssignmentExpression();4652} else {4653HasIterator = true;4654EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);4655Tail = ParseOpenMPIteratorsExpr();4656}4657Tail = Actions.CorrectDelayedTyposInExpr(Tail);4658Tail = Actions.ActOnFinishFullExpr(Tail.get(), T.getOpenLocation(),4659/*DiscardedValue=*/false);4660if (Tail.isUsable()) {4661if (Tok.is(tok::colon)) {4662Data.DepModOrTailExpr = Tail.get();4663Data.ColonLoc = ConsumeToken();4664TPA.Commit();4665} else {4666// Colon not found, parse only list of variables.4667TPA.Revert();4668}4669} else {4670// Parsing was unsuccessfull, revert and skip to the end of clause or4671// directive.4672TPA.Revert();4673SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,4674StopBeforeMatch);4675}4676} else if (Kind == OMPC_adjust_args) {4677// Handle adjust-op for adjust_args clause.4678ColonProtectionRAIIObject ColonRAII(*this);4679Data.ExtraModifier = getOpenMPSimpleClauseType(4680Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "",4681getLangOpts());4682Data.ExtraModifierLoc = Tok.getLocation();4683if (Data.ExtraModifier == OMPC_ADJUST_ARGS_unknown) {4684Diag(Tok, diag::err_omp_unknown_adjust_args_op);4685SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);4686} else {4687ConsumeToken();4688if (Tok.is(tok::colon))4689Data.ColonLoc = Tok.getLocation();4690ExpectAndConsume(tok::colon, diag::warn_pragma_expected_colon,4691"adjust-op");4692}4693}46944695bool IsComma =4696(Kind != OMPC_reduction && Kind != OMPC_task_reduction &&4697Kind != OMPC_in_reduction && Kind != OMPC_depend &&4698Kind != OMPC_doacross && Kind != OMPC_map && Kind != OMPC_adjust_args) ||4699(Kind == OMPC_reduction && !InvalidReductionId) ||4700(Kind == OMPC_map && Data.ExtraModifier != OMPC_MAP_unknown) ||4701(Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown) ||4702(Kind == OMPC_doacross && Data.ExtraModifier != OMPC_DOACROSS_unknown) ||4703(Kind == OMPC_adjust_args &&4704Data.ExtraModifier != OMPC_ADJUST_ARGS_unknown);4705const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);4706while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&4707Tok.isNot(tok::annot_pragma_openmp_end))) {4708ParseScope OMPListScope(this, Scope::OpenMPDirectiveScope);4709ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);4710if (!ParseOpenMPReservedLocator(Kind, Data, getLangOpts())) {4711// Parse variable4712ExprResult VarExpr =4713Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());4714if (VarExpr.isUsable()) {4715Vars.push_back(VarExpr.get());4716} else {4717SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,4718StopBeforeMatch);4719}4720}4721// Skip ',' if any4722IsComma = Tok.is(tok::comma);4723if (IsComma)4724ConsumeToken();4725else if (Tok.isNot(tok::r_paren) &&4726Tok.isNot(tok::annot_pragma_openmp_end) &&4727(!MayHaveTail || Tok.isNot(tok::colon)))4728Diag(Tok, diag::err_omp_expected_punc)4729<< ((Kind == OMPC_flush) ? getOpenMPDirectiveName(OMPD_flush)4730: getOpenMPClauseName(Kind))4731<< (Kind == OMPC_flush);4732}47334734// Parse ')' for linear clause with modifier.4735if (NeedRParenForLinear)4736LinearT.consumeClose();47374738// Parse ':' linear modifiers (val, uval, ref or step(step-size))4739// or parse ':' alignment.4740const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);4741bool StepFound = false;4742bool ModifierFound = false;4743if (MustHaveTail) {4744Data.ColonLoc = Tok.getLocation();4745SourceLocation ELoc = ConsumeToken();47464747if (getLangOpts().OpenMP >= 52 && Kind == OMPC_linear) {4748while (Tok.isNot(tok::r_paren)) {4749if (Tok.is(tok::identifier)) {4750// identifier could be a linear kind (val, uval, ref) or step4751// modifier or step size4752OpenMPLinearClauseKind LinKind =4753static_cast<OpenMPLinearClauseKind>(getOpenMPSimpleClauseType(4754Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok),4755getLangOpts()));47564757if (LinKind == OMPC_LINEAR_step) {4758if (StepFound)4759Diag(Tok, diag::err_omp_multiple_step_or_linear_modifier) << 0;47604761BalancedDelimiterTracker StepT(*this, tok::l_paren,4762tok::annot_pragma_openmp_end);4763SourceLocation StepModifierLoc = ConsumeToken();4764// parse '('4765if (StepT.consumeOpen())4766Diag(StepModifierLoc, diag::err_expected_lparen_after) << "step";47674768// parse step size expression4769StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation());4770if (StepFound)4771Data.StepModifierLoc = StepModifierLoc;47724773// parse ')'4774StepT.consumeClose();4775} else if (LinKind >= 0 && LinKind < OMPC_LINEAR_step) {4776if (ModifierFound)4777Diag(Tok, diag::err_omp_multiple_step_or_linear_modifier) << 1;47784779Data.ExtraModifier = LinKind;4780Data.ExtraModifierLoc = ConsumeToken();4781ModifierFound = true;4782} else {4783StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation());4784}4785} else {4786// parse an integer expression as step size4787StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation());4788}47894790if (Tok.is(tok::comma))4791ConsumeToken();4792if (Tok.is(tok::r_paren) || Tok.is(tok::annot_pragma_openmp_end))4793break;4794}4795if (!StepFound && !ModifierFound)4796Diag(ELoc, diag::err_expected_expression);4797} else {4798// for OMPC_aligned and OMPC_linear (with OpenMP <= 5.1)4799ExprResult Tail = ParseAssignmentExpression();4800Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc,4801/*DiscardedValue*/ false);4802if (Tail.isUsable())4803Data.DepModOrTailExpr = Tail.get();4804else4805SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,4806StopBeforeMatch);4807}4808}48094810// Parse ')'.4811Data.RLoc = Tok.getLocation();4812if (!T.consumeClose())4813Data.RLoc = T.getCloseLocation();4814// Exit from scope when the iterator is used in depend clause.4815if (HasIterator)4816ExitScope();4817return (Kind != OMPC_depend && Kind != OMPC_doacross && Kind != OMPC_map &&4818Vars.empty()) ||4819(MustHaveTail && !Data.DepModOrTailExpr && StepFound) ||4820InvalidReductionId || IsInvalidMapperModifier || InvalidIterator;4821}48224823/// Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',4824/// 'shared', 'copyin', 'copyprivate', 'flush', 'reduction', 'task_reduction',4825/// 'in_reduction', 'nontemporal', 'exclusive' or 'inclusive'.4826///4827/// private-clause:4828/// 'private' '(' list ')'4829/// firstprivate-clause:4830/// 'firstprivate' '(' list ')'4831/// lastprivate-clause:4832/// 'lastprivate' '(' list ')'4833/// shared-clause:4834/// 'shared' '(' list ')'4835/// linear-clause:4836/// 'linear' '(' linear-list [ ':' linear-step ] ')'4837/// aligned-clause:4838/// 'aligned' '(' list [ ':' alignment ] ')'4839/// reduction-clause:4840/// 'reduction' '(' [ modifier ',' ] reduction-identifier ':' list ')'4841/// task_reduction-clause:4842/// 'task_reduction' '(' reduction-identifier ':' list ')'4843/// in_reduction-clause:4844/// 'in_reduction' '(' reduction-identifier ':' list ')'4845/// copyprivate-clause:4846/// 'copyprivate' '(' list ')'4847/// flush-clause:4848/// 'flush' '(' list ')'4849/// depend-clause:4850/// 'depend' '(' in | out | inout : list | source ')'4851/// map-clause:4852/// 'map' '(' [ [ always [,] ] [ close [,] ]4853/// [ mapper '(' mapper-identifier ')' [,] ]4854/// to | from | tofrom | alloc | release | delete ':' ] list ')';4855/// to-clause:4856/// 'to' '(' [ mapper '(' mapper-identifier ')' ':' ] list ')'4857/// from-clause:4858/// 'from' '(' [ mapper '(' mapper-identifier ')' ':' ] list ')'4859/// use_device_ptr-clause:4860/// 'use_device_ptr' '(' list ')'4861/// use_device_addr-clause:4862/// 'use_device_addr' '(' list ')'4863/// is_device_ptr-clause:4864/// 'is_device_ptr' '(' list ')'4865/// has_device_addr-clause:4866/// 'has_device_addr' '(' list ')'4867/// allocate-clause:4868/// 'allocate' '(' [ allocator ':' ] list ')'4869/// nontemporal-clause:4870/// 'nontemporal' '(' list ')'4871/// inclusive-clause:4872/// 'inclusive' '(' list ')'4873/// exclusive-clause:4874/// 'exclusive' '(' list ')'4875///4876/// For 'linear' clause linear-list may have the following forms:4877/// list4878/// modifier(list)4879/// where modifier is 'val' (C) or 'ref', 'val' or 'uval'(C++).4880OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,4881OpenMPClauseKind Kind,4882bool ParseOnly) {4883SourceLocation Loc = Tok.getLocation();4884SourceLocation LOpen = ConsumeToken();4885SmallVector<Expr *, 4> Vars;4886SemaOpenMP::OpenMPVarListDataTy Data;48874888if (ParseOpenMPVarList(DKind, Kind, Vars, Data))4889return nullptr;48904891if (ParseOnly)4892return nullptr;4893OMPVarListLocTy Locs(Loc, LOpen, Data.RLoc);4894return Actions.OpenMP().ActOnOpenMPVarListClause(Kind, Vars, Locs, Data);4895}48964897bool Parser::ParseOpenMPExprListClause(OpenMPClauseKind Kind,4898SourceLocation &ClauseNameLoc,4899SourceLocation &OpenLoc,4900SourceLocation &CloseLoc,4901SmallVectorImpl<Expr *> &Exprs,4902bool ReqIntConst) {4903assert(getOpenMPClauseName(Kind) == PP.getSpelling(Tok) &&4904"Expected parsing to start at clause name");4905ClauseNameLoc = ConsumeToken();49064907// Parse inside of '(' and ')'.4908BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);4909if (T.consumeOpen()) {4910Diag(Tok, diag::err_expected) << tok::l_paren;4911return true;4912}49134914// Parse the list with interleaved commas.4915do {4916ExprResult Val =4917ReqIntConst ? ParseConstantExpression() : ParseAssignmentExpression();4918if (!Val.isUsable()) {4919// Encountered something other than an expression; abort to ')'.4920T.skipToEnd();4921return true;4922}4923Exprs.push_back(Val.get());4924} while (TryConsumeToken(tok::comma));49254926bool Result = T.consumeClose();4927OpenLoc = T.getOpenLocation();4928CloseLoc = T.getCloseLocation();4929return Result;4930}493149324933