llvm-project
4929 строк · 180.3 Кб
1//===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8/// \file
9/// This file implements parsing of all OpenMP directives and clauses.
10///
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/ASTContext.h"14#include "clang/AST/OpenMPClause.h"15#include "clang/AST/StmtOpenMP.h"16#include "clang/Basic/OpenMPKinds.h"17#include "clang/Basic/TargetInfo.h"18#include "clang/Basic/TokenKinds.h"19#include "clang/Parse/ParseDiagnostic.h"20#include "clang/Parse/Parser.h"21#include "clang/Parse/RAIIObjectsForParser.h"22#include "clang/Sema/EnterExpressionEvaluationContext.h"23#include "clang/Sema/Scope.h"24#include "clang/Sema/SemaAMDGPU.h"25#include "clang/Sema/SemaCodeCompletion.h"26#include "clang/Sema/SemaOpenMP.h"27#include "llvm/ADT/SmallBitVector.h"28#include "llvm/ADT/StringSwitch.h"29#include "llvm/Frontend/OpenMP/OMPAssume.h"30#include "llvm/Frontend/OpenMP/OMPContext.h"31#include <optional>32
33using namespace clang;34using namespace llvm::omp;35
36//===----------------------------------------------------------------------===//
37// OpenMP declarative directives.
38//===----------------------------------------------------------------------===//
39
40namespace {41enum OpenMPDirectiveKindEx {42OMPD_cancellation = llvm::omp::Directive_enumSize + 1,43OMPD_data,44OMPD_declare,45OMPD_end,46OMPD_end_declare,47OMPD_enter,48OMPD_exit,49OMPD_point,50OMPD_reduction,51OMPD_target_enter,52OMPD_target_exit,53OMPD_update,54OMPD_distribute_parallel,55OMPD_teams_distribute_parallel,56OMPD_target_teams_distribute_parallel,57OMPD_mapper,58OMPD_variant,59OMPD_begin,60OMPD_begin_declare,61};62
63// Helper to unify the enum class OpenMPDirectiveKind with its extension
64// the OpenMPDirectiveKindEx enum which allows to use them together as if they
65// are unsigned values.
66struct OpenMPDirectiveKindExWrapper {67OpenMPDirectiveKindExWrapper(unsigned Value) : Value(Value) {}68OpenMPDirectiveKindExWrapper(OpenMPDirectiveKind DK) : Value(unsigned(DK)) {}69bool operator==(OpenMPDirectiveKindExWrapper V) const {70return Value == V.Value;71}72bool operator!=(OpenMPDirectiveKindExWrapper V) const {73return Value != V.Value;74}75bool operator==(OpenMPDirectiveKind V) const { return Value == unsigned(V); }76bool operator!=(OpenMPDirectiveKind V) const { return Value != unsigned(V); }77bool operator<(OpenMPDirectiveKind V) const { return Value < unsigned(V); }78operator unsigned() const { return Value; }79operator OpenMPDirectiveKind() const { return OpenMPDirectiveKind(Value); }80unsigned Value;81};82
83class DeclDirectiveListParserHelper final {84SmallVector<Expr *, 4> Identifiers;85Parser *P;86OpenMPDirectiveKind Kind;87
88public:89DeclDirectiveListParserHelper(Parser *P, OpenMPDirectiveKind Kind)90: P(P), Kind(Kind) {}91void operator()(CXXScopeSpec &SS, DeclarationNameInfo NameInfo) {92ExprResult Res = P->getActions().OpenMP().ActOnOpenMPIdExpression(93P->getCurScope(), SS, NameInfo, Kind);94if (Res.isUsable())95Identifiers.push_back(Res.get());96}97llvm::ArrayRef<Expr *> getIdentifiers() const { return Identifiers; }98};99} // namespace100
101// Map token string to extended OMP token kind that are
102// OpenMPDirectiveKind + OpenMPDirectiveKindEx.
103static unsigned getOpenMPDirectiveKindEx(StringRef S) {104OpenMPDirectiveKindExWrapper DKind = getOpenMPDirectiveKind(S);105if (DKind != OMPD_unknown)106return DKind;107
108return llvm::StringSwitch<OpenMPDirectiveKindExWrapper>(S)109.Case("cancellation", OMPD_cancellation)110.Case("data", OMPD_data)111.Case("declare", OMPD_declare)112.Case("end", OMPD_end)113.Case("enter", OMPD_enter)114.Case("exit", OMPD_exit)115.Case("point", OMPD_point)116.Case("reduction", OMPD_reduction)117.Case("update", OMPD_update)118.Case("mapper", OMPD_mapper)119.Case("variant", OMPD_variant)120.Case("begin", OMPD_begin)121.Default(OMPD_unknown);122}
123
124static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) {125// Array of foldings: F[i][0] F[i][1] ===> F[i][2].126// E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd127// TODO: add other combined directives in topological order.128static const OpenMPDirectiveKindExWrapper F[][3] = {129{OMPD_begin, OMPD_declare, OMPD_begin_declare},130{OMPD_begin, OMPD_assumes, OMPD_begin_assumes},131{OMPD_end, OMPD_declare, OMPD_end_declare},132{OMPD_end, OMPD_assumes, OMPD_end_assumes},133{OMPD_cancellation, OMPD_point, OMPD_cancellation_point},134{OMPD_declare, OMPD_reduction, OMPD_declare_reduction},135{OMPD_declare, OMPD_mapper, OMPD_declare_mapper},136{OMPD_declare, OMPD_simd, OMPD_declare_simd},137{OMPD_declare, OMPD_target, OMPD_declare_target},138{OMPD_declare, OMPD_variant, OMPD_declare_variant},139{OMPD_begin_declare, OMPD_target, OMPD_begin_declare_target},140{OMPD_begin_declare, OMPD_variant, OMPD_begin_declare_variant},141{OMPD_end_declare, OMPD_variant, OMPD_end_declare_variant},142{OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel},143{OMPD_distribute_parallel, OMPD_for, OMPD_distribute_parallel_for},144{OMPD_distribute_parallel_for, OMPD_simd,145OMPD_distribute_parallel_for_simd},146{OMPD_distribute, OMPD_simd, OMPD_distribute_simd},147{OMPD_end_declare, OMPD_target, OMPD_end_declare_target},148{OMPD_target, OMPD_data, OMPD_target_data},149{OMPD_target, OMPD_enter, OMPD_target_enter},150{OMPD_target, OMPD_exit, OMPD_target_exit},151{OMPD_target, OMPD_update, OMPD_target_update},152{OMPD_target_enter, OMPD_data, OMPD_target_enter_data},153{OMPD_target_exit, OMPD_data, OMPD_target_exit_data},154{OMPD_for, OMPD_simd, OMPD_for_simd},155{OMPD_parallel, OMPD_for, OMPD_parallel_for},156{OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd},157{OMPD_parallel, OMPD_loop, OMPD_parallel_loop},158{OMPD_parallel, OMPD_sections, OMPD_parallel_sections},159{OMPD_taskloop, OMPD_simd, OMPD_taskloop_simd},160{OMPD_target, OMPD_parallel, OMPD_target_parallel},161{OMPD_target, OMPD_simd, OMPD_target_simd},162{OMPD_target_parallel, OMPD_loop, OMPD_target_parallel_loop},163{OMPD_target_parallel, OMPD_for, OMPD_target_parallel_for},164{OMPD_target_parallel_for, OMPD_simd, OMPD_target_parallel_for_simd},165{OMPD_teams, OMPD_distribute, OMPD_teams_distribute},166{OMPD_teams_distribute, OMPD_simd, OMPD_teams_distribute_simd},167{OMPD_teams_distribute, OMPD_parallel, OMPD_teams_distribute_parallel},168{OMPD_teams_distribute_parallel, OMPD_for,169OMPD_teams_distribute_parallel_for},170{OMPD_teams_distribute_parallel_for, OMPD_simd,171OMPD_teams_distribute_parallel_for_simd},172{OMPD_teams, OMPD_loop, OMPD_teams_loop},173{OMPD_target, OMPD_teams, OMPD_target_teams},174{OMPD_target_teams, OMPD_distribute, OMPD_target_teams_distribute},175{OMPD_target_teams, OMPD_loop, OMPD_target_teams_loop},176{OMPD_target_teams_distribute, OMPD_parallel,177OMPD_target_teams_distribute_parallel},178{OMPD_target_teams_distribute, OMPD_simd,179OMPD_target_teams_distribute_simd},180{OMPD_target_teams_distribute_parallel, OMPD_for,181OMPD_target_teams_distribute_parallel_for},182{OMPD_target_teams_distribute_parallel_for, OMPD_simd,183OMPD_target_teams_distribute_parallel_for_simd},184{OMPD_master, OMPD_taskloop, OMPD_master_taskloop},185{OMPD_masked, OMPD_taskloop, OMPD_masked_taskloop},186{OMPD_master_taskloop, OMPD_simd, OMPD_master_taskloop_simd},187{OMPD_masked_taskloop, OMPD_simd, OMPD_masked_taskloop_simd},188{OMPD_parallel, OMPD_master, OMPD_parallel_master},189{OMPD_parallel, OMPD_masked, OMPD_parallel_masked},190{OMPD_parallel_master, OMPD_taskloop, OMPD_parallel_master_taskloop},191{OMPD_parallel_masked, OMPD_taskloop, OMPD_parallel_masked_taskloop},192{OMPD_parallel_master_taskloop, OMPD_simd,193OMPD_parallel_master_taskloop_simd},194{OMPD_parallel_masked_taskloop, OMPD_simd,195OMPD_parallel_masked_taskloop_simd}};196enum { CancellationPoint = 0, DeclareReduction = 1, TargetData = 2 };197Token Tok = P.getCurToken();198OpenMPDirectiveKindExWrapper DKind =199Tok.isAnnotation()200? static_cast<unsigned>(OMPD_unknown)201: getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok));202if (DKind == OMPD_unknown)203return OMPD_unknown;204
205for (const auto &I : F) {206if (DKind != I[0])207continue;208
209Tok = P.getPreprocessor().LookAhead(0);210OpenMPDirectiveKindExWrapper SDKind =211Tok.isAnnotation()212? static_cast<unsigned>(OMPD_unknown)213: getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok));214if (SDKind == OMPD_unknown)215continue;216
217if (SDKind == I[1]) {218P.ConsumeToken();219DKind = I[2];220}221}222return unsigned(DKind) < llvm::omp::Directive_enumSize223? static_cast<OpenMPDirectiveKind>(DKind)224: OMPD_unknown;225}
226
227static DeclarationName parseOpenMPReductionId(Parser &P) {228Token Tok = P.getCurToken();229Sema &Actions = P.getActions();230OverloadedOperatorKind OOK = OO_None;231// Allow to use 'operator' keyword for C++ operators232bool WithOperator = false;233if (Tok.is(tok::kw_operator)) {234P.ConsumeToken();235Tok = P.getCurToken();236WithOperator = true;237}238switch (Tok.getKind()) {239case tok::plus: // '+'240OOK = OO_Plus;241break;242case tok::minus: // '-'243OOK = OO_Minus;244break;245case tok::star: // '*'246OOK = OO_Star;247break;248case tok::amp: // '&'249OOK = OO_Amp;250break;251case tok::pipe: // '|'252OOK = OO_Pipe;253break;254case tok::caret: // '^'255OOK = OO_Caret;256break;257case tok::ampamp: // '&&'258OOK = OO_AmpAmp;259break;260case tok::pipepipe: // '||'261OOK = OO_PipePipe;262break;263case tok::identifier: // identifier264if (!WithOperator)265break;266[[fallthrough]];267default:268P.Diag(Tok.getLocation(), diag::err_omp_expected_reduction_identifier);269P.SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,270Parser::StopBeforeMatch);271return DeclarationName();272}273P.ConsumeToken();274auto &DeclNames = Actions.getASTContext().DeclarationNames;275return OOK == OO_None ? DeclNames.getIdentifier(Tok.getIdentifierInfo())276: DeclNames.getCXXOperatorName(OOK);277}
278
279/// Parse 'omp declare reduction' construct.
280///
281/// declare-reduction-directive:
282/// annot_pragma_openmp 'declare' 'reduction'
283/// '(' <reduction_id> ':' <type> {',' <type>} ':' <expression> ')'
284/// ['initializer' '(' ('omp_priv' '=' <expression>)|<function_call> ')']
285/// annot_pragma_openmp_end
286/// <reduction_id> is either a base language identifier or one of the following
287/// operators: '+', '-', '*', '&', '|', '^', '&&' and '||'.
288///
289Parser::DeclGroupPtrTy290Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {291// Parse '('.292BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);293if (T.expectAndConsume(294diag::err_expected_lparen_after,295getOpenMPDirectiveName(OMPD_declare_reduction).data())) {296SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);297return DeclGroupPtrTy();298}299
300DeclarationName Name = parseOpenMPReductionId(*this);301if (Name.isEmpty() && Tok.is(tok::annot_pragma_openmp_end))302return DeclGroupPtrTy();303
304// Consume ':'.305bool IsCorrect = !ExpectAndConsume(tok::colon);306
307if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))308return DeclGroupPtrTy();309
310IsCorrect = IsCorrect && !Name.isEmpty();311
312if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) {313Diag(Tok.getLocation(), diag::err_expected_type);314IsCorrect = false;315}316
317if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))318return DeclGroupPtrTy();319
320SmallVector<std::pair<QualType, SourceLocation>, 8> ReductionTypes;321// Parse list of types until ':' token.322do {323ColonProtectionRAIIObject ColonRAII(*this);324SourceRange Range;325TypeResult TR = ParseTypeName(&Range, DeclaratorContext::Prototype, AS);326if (TR.isUsable()) {327QualType ReductionType = Actions.OpenMP().ActOnOpenMPDeclareReductionType(328Range.getBegin(), TR);329if (!ReductionType.isNull()) {330ReductionTypes.push_back(331std::make_pair(ReductionType, Range.getBegin()));332}333} else {334SkipUntil(tok::comma, tok::colon, tok::annot_pragma_openmp_end,335StopBeforeMatch);336}337
338if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end))339break;340
341// Consume ','.342if (ExpectAndConsume(tok::comma)) {343IsCorrect = false;344if (Tok.is(tok::annot_pragma_openmp_end)) {345Diag(Tok.getLocation(), diag::err_expected_type);346return DeclGroupPtrTy();347}348}349} while (Tok.isNot(tok::annot_pragma_openmp_end));350
351if (ReductionTypes.empty()) {352SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);353return DeclGroupPtrTy();354}355
356if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))357return DeclGroupPtrTy();358
359// Consume ':'.360if (ExpectAndConsume(tok::colon))361IsCorrect = false;362
363if (Tok.is(tok::annot_pragma_openmp_end)) {364Diag(Tok.getLocation(), diag::err_expected_expression);365return DeclGroupPtrTy();366}367
368DeclGroupPtrTy DRD =369Actions.OpenMP().ActOnOpenMPDeclareReductionDirectiveStart(370getCurScope(), Actions.getCurLexicalContext(), Name, ReductionTypes,371AS);372
373// Parse <combiner> expression and then parse initializer if any for each374// correct type.375unsigned I = 0, E = ReductionTypes.size();376for (Decl *D : DRD.get()) {377TentativeParsingAction TPA(*this);378ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |379Scope::CompoundStmtScope |380Scope::OpenMPDirectiveScope);381// Parse <combiner> expression.382Actions.OpenMP().ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D);383ExprResult CombinerResult = Actions.ActOnFinishFullExpr(384ParseExpression().get(), D->getLocation(), /*DiscardedValue*/ false);385Actions.OpenMP().ActOnOpenMPDeclareReductionCombinerEnd(386D, CombinerResult.get());387
388if (CombinerResult.isInvalid() && Tok.isNot(tok::r_paren) &&389Tok.isNot(tok::annot_pragma_openmp_end)) {390TPA.Commit();391IsCorrect = false;392break;393}394IsCorrect = !T.consumeClose() && IsCorrect && CombinerResult.isUsable();395ExprResult InitializerResult;396if (Tok.isNot(tok::annot_pragma_openmp_end)) {397// Parse <initializer> expression.398if (Tok.is(tok::identifier) &&399Tok.getIdentifierInfo()->isStr("initializer")) {400ConsumeToken();401} else {402Diag(Tok.getLocation(), diag::err_expected) << "'initializer'";403TPA.Commit();404IsCorrect = false;405break;406}407// Parse '('.408BalancedDelimiterTracker T(*this, tok::l_paren,409tok::annot_pragma_openmp_end);410IsCorrect =411!T.expectAndConsume(diag::err_expected_lparen_after, "initializer") &&412IsCorrect;413if (Tok.isNot(tok::annot_pragma_openmp_end)) {414ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |415Scope::CompoundStmtScope |416Scope::OpenMPDirectiveScope);417// Parse expression.418VarDecl *OmpPrivParm =419Actions.OpenMP().ActOnOpenMPDeclareReductionInitializerStart(420getCurScope(), D);421// Check if initializer is omp_priv <init_expr> or something else.422if (Tok.is(tok::identifier) &&423Tok.getIdentifierInfo()->isStr("omp_priv")) {424ConsumeToken();425ParseOpenMPReductionInitializerForDecl(OmpPrivParm);426} else {427InitializerResult = Actions.ActOnFinishFullExpr(428ParseAssignmentExpression().get(), D->getLocation(),429/*DiscardedValue*/ false);430}431Actions.OpenMP().ActOnOpenMPDeclareReductionInitializerEnd(432D, InitializerResult.get(), OmpPrivParm);433if (InitializerResult.isInvalid() && Tok.isNot(tok::r_paren) &&434Tok.isNot(tok::annot_pragma_openmp_end)) {435TPA.Commit();436IsCorrect = false;437break;438}439IsCorrect =440!T.consumeClose() && IsCorrect && !InitializerResult.isInvalid();441}442}443
444++I;445// Revert parsing if not the last type, otherwise accept it, we're done with446// parsing.447if (I != E)448TPA.Revert();449else450TPA.Commit();451}452return Actions.OpenMP().ActOnOpenMPDeclareReductionDirectiveEnd(453getCurScope(), DRD, IsCorrect);454}
455
456void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {457// Parse declarator '=' initializer.458// If a '==' or '+=' is found, suggest a fixit to '='.459if (isTokenEqualOrEqualTypo()) {460ConsumeToken();461
462if (Tok.is(tok::code_completion)) {463cutOffParsing();464Actions.CodeCompletion().CodeCompleteInitializer(getCurScope(),465OmpPrivParm);466Actions.FinalizeDeclaration(OmpPrivParm);467return;468}469
470PreferredType.enterVariableInit(Tok.getLocation(), OmpPrivParm);471ExprResult Init = ParseInitializer();472
473if (Init.isInvalid()) {474SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);475Actions.ActOnInitializerError(OmpPrivParm);476} else {477Actions.AddInitializerToDecl(OmpPrivParm, Init.get(),478/*DirectInit=*/false);479}480} else if (Tok.is(tok::l_paren)) {481// Parse C++ direct initializer: '(' expression-list ')'482BalancedDelimiterTracker T(*this, tok::l_paren);483T.consumeOpen();484
485ExprVector Exprs;486
487SourceLocation LParLoc = T.getOpenLocation();488auto RunSignatureHelp = [this, OmpPrivParm, LParLoc, &Exprs]() {489QualType PreferredType =490Actions.CodeCompletion().ProduceConstructorSignatureHelp(491OmpPrivParm->getType()->getCanonicalTypeInternal(),492OmpPrivParm->getLocation(), Exprs, LParLoc, /*Braced=*/false);493CalledSignatureHelp = true;494return PreferredType;495};496if (ParseExpressionList(Exprs, [&] {497PreferredType.enterFunctionArgument(Tok.getLocation(),498RunSignatureHelp);499})) {500if (PP.isCodeCompletionReached() && !CalledSignatureHelp)501RunSignatureHelp();502Actions.ActOnInitializerError(OmpPrivParm);503SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);504} else {505// Match the ')'.506SourceLocation RLoc = Tok.getLocation();507if (!T.consumeClose())508RLoc = T.getCloseLocation();509
510ExprResult Initializer =511Actions.ActOnParenListExpr(T.getOpenLocation(), RLoc, Exprs);512Actions.AddInitializerToDecl(OmpPrivParm, Initializer.get(),513/*DirectInit=*/true);514}515} else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {516// Parse C++0x braced-init-list.517Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);518
519ExprResult Init(ParseBraceInitializer());520
521if (Init.isInvalid()) {522Actions.ActOnInitializerError(OmpPrivParm);523} else {524Actions.AddInitializerToDecl(OmpPrivParm, Init.get(),525/*DirectInit=*/true);526}527} else {528Actions.ActOnUninitializedDecl(OmpPrivParm);529}530}
531
532/// Parses 'omp declare mapper' directive.
533///
534/// declare-mapper-directive:
535/// annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifier> ':']
536/// <type> <var> ')' [<clause>[[,] <clause>] ... ]
537/// annot_pragma_openmp_end
538/// <mapper-identifier> and <var> are base language identifiers.
539///
540Parser::DeclGroupPtrTy541Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) {542bool IsCorrect = true;543// Parse '('544BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);545if (T.expectAndConsume(diag::err_expected_lparen_after,546getOpenMPDirectiveName(OMPD_declare_mapper).data())) {547SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);548return DeclGroupPtrTy();549}550
551// Parse <mapper-identifier>552auto &DeclNames = Actions.getASTContext().DeclarationNames;553DeclarationName MapperId;554if (PP.LookAhead(0).is(tok::colon)) {555if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_default)) {556Diag(Tok.getLocation(), diag::err_omp_mapper_illegal_identifier);557IsCorrect = false;558} else {559MapperId = DeclNames.getIdentifier(Tok.getIdentifierInfo());560}561ConsumeToken();562// Consume ':'.563ExpectAndConsume(tok::colon);564} else {565// If no mapper identifier is provided, its name is "default" by default566MapperId =567DeclNames.getIdentifier(&Actions.getASTContext().Idents.get("default"));568}569
570if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))571return DeclGroupPtrTy();572
573// Parse <type> <var>574DeclarationName VName;575QualType MapperType;576SourceRange Range;577TypeResult ParsedType = parseOpenMPDeclareMapperVarDecl(Range, VName, AS);578if (ParsedType.isUsable())579MapperType = Actions.OpenMP().ActOnOpenMPDeclareMapperType(Range.getBegin(),580ParsedType);581if (MapperType.isNull())582IsCorrect = false;583if (!IsCorrect) {584SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch);585return DeclGroupPtrTy();586}587
588// Consume ')'.589IsCorrect &= !T.consumeClose();590if (!IsCorrect) {591SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch);592return DeclGroupPtrTy();593}594
595// Enter scope.596DeclarationNameInfo DirName;597SourceLocation Loc = Tok.getLocation();598unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |599Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;600ParseScope OMPDirectiveScope(this, ScopeFlags);601Actions.OpenMP().StartOpenMPDSABlock(OMPD_declare_mapper, DirName,602getCurScope(), Loc);603
604// Add the mapper variable declaration.605ExprResult MapperVarRef =606Actions.OpenMP().ActOnOpenMPDeclareMapperDirectiveVarDecl(607getCurScope(), MapperType, Range.getBegin(), VName);608
609// Parse map clauses.610SmallVector<OMPClause *, 6> Clauses;611while (Tok.isNot(tok::annot_pragma_openmp_end)) {612OpenMPClauseKind CKind = Tok.isAnnotation()613? OMPC_unknown614: getOpenMPClauseKind(PP.getSpelling(Tok));615Actions.OpenMP().StartOpenMPClause(CKind);616OMPClause *Clause =617ParseOpenMPClause(OMPD_declare_mapper, CKind, Clauses.empty());618if (Clause)619Clauses.push_back(Clause);620else621IsCorrect = false;622// Skip ',' if any.623if (Tok.is(tok::comma))624ConsumeToken();625Actions.OpenMP().EndOpenMPClause();626}627if (Clauses.empty()) {628Diag(Tok, diag::err_omp_expected_clause)629<< getOpenMPDirectiveName(OMPD_declare_mapper);630IsCorrect = false;631}632
633// Exit scope.634Actions.OpenMP().EndOpenMPDSABlock(nullptr);635OMPDirectiveScope.Exit();636DeclGroupPtrTy DG = Actions.OpenMP().ActOnOpenMPDeclareMapperDirective(637getCurScope(), Actions.getCurLexicalContext(), MapperId, MapperType,638Range.getBegin(), VName, AS, MapperVarRef.get(), Clauses);639if (!IsCorrect)640return DeclGroupPtrTy();641
642return DG;643}
644
645TypeResult Parser::parseOpenMPDeclareMapperVarDecl(SourceRange &Range,646DeclarationName &Name,647AccessSpecifier AS) {648// Parse the common declaration-specifiers piece.649Parser::DeclSpecContext DSC = Parser::DeclSpecContext::DSC_type_specifier;650DeclSpec DS(AttrFactory);651ParseSpecifierQualifierList(DS, AS, DSC);652
653// Parse the declarator.654DeclaratorContext Context = DeclaratorContext::Prototype;655Declarator DeclaratorInfo(DS, ParsedAttributesView::none(), Context);656ParseDeclarator(DeclaratorInfo);657Range = DeclaratorInfo.getSourceRange();658if (DeclaratorInfo.getIdentifier() == nullptr) {659Diag(Tok.getLocation(), diag::err_omp_mapper_expected_declarator);660return true;661}662Name = Actions.GetNameForDeclarator(DeclaratorInfo).getName();663
664return Actions.OpenMP().ActOnOpenMPDeclareMapperVarDecl(getCurScope(),665DeclaratorInfo);666}
667
668namespace {669/// RAII that recreates function context for correct parsing of clauses of
670/// 'declare simd' construct.
671/// OpenMP, 2.8.2 declare simd Construct
672/// The expressions appearing in the clauses of this directive are evaluated in
673/// the scope of the arguments of the function declaration or definition.
674class FNContextRAII final {675Parser &P;676Sema::CXXThisScopeRAII *ThisScope;677Parser::MultiParseScope Scopes;678bool HasFunScope = false;679FNContextRAII() = delete;680FNContextRAII(const FNContextRAII &) = delete;681FNContextRAII &operator=(const FNContextRAII &) = delete;682
683public:684FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr) : P(P), Scopes(P) {685Decl *D = *Ptr.get().begin();686NamedDecl *ND = dyn_cast<NamedDecl>(D);687RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());688Sema &Actions = P.getActions();689
690// Allow 'this' within late-parsed attributes.691ThisScope = new Sema::CXXThisScopeRAII(Actions, RD, Qualifiers(),692ND && ND->isCXXInstanceMember());693
694// If the Decl is templatized, add template parameters to scope.695// FIXME: Track CurTemplateDepth?696P.ReenterTemplateScopes(Scopes, D);697
698// If the Decl is on a function, add function parameters to the scope.699if (D->isFunctionOrFunctionTemplate()) {700HasFunScope = true;701Scopes.Enter(Scope::FnScope | Scope::DeclScope |702Scope::CompoundStmtScope);703Actions.ActOnReenterFunctionContext(Actions.getCurScope(), D);704}705}706~FNContextRAII() {707if (HasFunScope)708P.getActions().ActOnExitFunctionContext();709delete ThisScope;710}711};712} // namespace713
714/// Parses clauses for 'declare simd' directive.
715/// clause:
716/// 'inbranch' | 'notinbranch'
717/// 'simdlen' '(' <expr> ')'
718/// { 'uniform' '(' <argument_list> ')' }
719/// { 'aligned '(' <argument_list> [ ':' <alignment> ] ')' }
720/// { 'linear '(' <argument_list> [ ':' <step> ] ')' }
721static bool parseDeclareSimdClauses(722Parser &P, OMPDeclareSimdDeclAttr::BranchStateTy &BS, ExprResult &SimdLen,723SmallVectorImpl<Expr *> &Uniforms, SmallVectorImpl<Expr *> &Aligneds,724SmallVectorImpl<Expr *> &Alignments, SmallVectorImpl<Expr *> &Linears,725SmallVectorImpl<unsigned> &LinModifiers, SmallVectorImpl<Expr *> &Steps) {726SourceRange BSRange;727const Token &Tok = P.getCurToken();728bool IsError = false;729while (Tok.isNot(tok::annot_pragma_openmp_end)) {730if (Tok.isNot(tok::identifier))731break;732OMPDeclareSimdDeclAttr::BranchStateTy Out;733IdentifierInfo *II = Tok.getIdentifierInfo();734StringRef ClauseName = II->getName();735// Parse 'inranch|notinbranch' clauses.736if (OMPDeclareSimdDeclAttr::ConvertStrToBranchStateTy(ClauseName, Out)) {737if (BS != OMPDeclareSimdDeclAttr::BS_Undefined && BS != Out) {738P.Diag(Tok, diag::err_omp_declare_simd_inbranch_notinbranch)739<< ClauseName740<< OMPDeclareSimdDeclAttr::ConvertBranchStateTyToStr(BS) << BSRange;741IsError = true;742}743BS = Out;744BSRange = SourceRange(Tok.getLocation(), Tok.getEndLoc());745P.ConsumeToken();746} else if (ClauseName == "simdlen") {747if (SimdLen.isUsable()) {748P.Diag(Tok, diag::err_omp_more_one_clause)749<< getOpenMPDirectiveName(OMPD_declare_simd) << ClauseName << 0;750IsError = true;751}752P.ConsumeToken();753SourceLocation RLoc;754SimdLen = P.ParseOpenMPParensExpr(ClauseName, RLoc);755if (SimdLen.isInvalid())756IsError = true;757} else {758OpenMPClauseKind CKind = getOpenMPClauseKind(ClauseName);759if (CKind == OMPC_uniform || CKind == OMPC_aligned ||760CKind == OMPC_linear) {761SemaOpenMP::OpenMPVarListDataTy Data;762SmallVectorImpl<Expr *> *Vars = &Uniforms;763if (CKind == OMPC_aligned) {764Vars = &Aligneds;765} else if (CKind == OMPC_linear) {766Data.ExtraModifier = OMPC_LINEAR_val;767Vars = &Linears;768}769
770P.ConsumeToken();771if (P.ParseOpenMPVarList(OMPD_declare_simd,772getOpenMPClauseKind(ClauseName), *Vars, Data))773IsError = true;774if (CKind == OMPC_aligned) {775Alignments.append(Aligneds.size() - Alignments.size(),776Data.DepModOrTailExpr);777} else if (CKind == OMPC_linear) {778assert(0 <= Data.ExtraModifier &&779Data.ExtraModifier <= OMPC_LINEAR_unknown &&780"Unexpected linear modifier.");781if (P.getActions().OpenMP().CheckOpenMPLinearModifier(782static_cast<OpenMPLinearClauseKind>(Data.ExtraModifier),783Data.ExtraModifierLoc))784Data.ExtraModifier = OMPC_LINEAR_val;785LinModifiers.append(Linears.size() - LinModifiers.size(),786Data.ExtraModifier);787Steps.append(Linears.size() - Steps.size(), Data.DepModOrTailExpr);788}789} else790// TODO: add parsing of other clauses.791break;792}793// Skip ',' if any.794if (Tok.is(tok::comma))795P.ConsumeToken();796}797return IsError;798}
799
800/// Parse clauses for '#pragma omp declare simd'.
801Parser::DeclGroupPtrTy802Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,803CachedTokens &Toks, SourceLocation Loc) {804PP.EnterToken(Tok, /*IsReinject*/ true);805PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,806/*IsReinject*/ true);807// Consume the previously pushed token.808ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);809ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);810
811FNContextRAII FnContext(*this, Ptr);812OMPDeclareSimdDeclAttr::BranchStateTy BS =813OMPDeclareSimdDeclAttr::BS_Undefined;814ExprResult Simdlen;815SmallVector<Expr *, 4> Uniforms;816SmallVector<Expr *, 4> Aligneds;817SmallVector<Expr *, 4> Alignments;818SmallVector<Expr *, 4> Linears;819SmallVector<unsigned, 4> LinModifiers;820SmallVector<Expr *, 4> Steps;821bool IsError =822parseDeclareSimdClauses(*this, BS, Simdlen, Uniforms, Aligneds,823Alignments, Linears, LinModifiers, Steps);824skipUntilPragmaOpenMPEnd(OMPD_declare_simd);825// Skip the last annot_pragma_openmp_end.826SourceLocation EndLoc = ConsumeAnnotationToken();827if (IsError)828return Ptr;829return Actions.OpenMP().ActOnOpenMPDeclareSimdDirective(830Ptr, BS, Simdlen.get(), Uniforms, Aligneds, Alignments, Linears,831LinModifiers, Steps, SourceRange(Loc, EndLoc));832}
833
834namespace {835/// Constant used in the diagnostics to distinguish the levels in an OpenMP
836/// contexts: selector-set={selector(trait, ...), ...}, ....
837enum OMPContextLvl {838CONTEXT_SELECTOR_SET_LVL = 0,839CONTEXT_SELECTOR_LVL = 1,840CONTEXT_TRAIT_LVL = 2,841};842
843static StringRef stringLiteralParser(Parser &P) {844ExprResult Res = P.ParseStringLiteralExpression(true);845return Res.isUsable() ? Res.getAs<StringLiteral>()->getString() : "";846}
847
848static StringRef getNameFromIdOrString(Parser &P, Token &Tok,849OMPContextLvl Lvl) {850if (Tok.is(tok::identifier) || Tok.is(tok::kw_for)) {851llvm::SmallString<16> Buffer;852StringRef Name = P.getPreprocessor().getSpelling(Tok, Buffer);853(void)P.ConsumeToken();854return Name;855}856
857if (tok::isStringLiteral(Tok.getKind()))858return stringLiteralParser(P);859
860P.Diag(Tok.getLocation(),861diag::warn_omp_declare_variant_string_literal_or_identifier)862<< Lvl;863return "";864}
865
866static bool checkForDuplicates(Parser &P, StringRef Name,867SourceLocation NameLoc,868llvm::StringMap<SourceLocation> &Seen,869OMPContextLvl Lvl) {870auto Res = Seen.try_emplace(Name, NameLoc);871if (Res.second)872return false;873
874// Each trait-set-selector-name, trait-selector-name and trait-name can875// only be specified once.876P.Diag(NameLoc, diag::warn_omp_declare_variant_ctx_mutiple_use)877<< Lvl << Name;878P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here)879<< Lvl << Name;880return true;881}
882} // namespace883
884void Parser::parseOMPTraitPropertyKind(OMPTraitProperty &TIProperty,885llvm::omp::TraitSet Set,886llvm::omp::TraitSelector Selector,887llvm::StringMap<SourceLocation> &Seen) {888TIProperty.Kind = TraitProperty::invalid;889
890SourceLocation NameLoc = Tok.getLocation();891StringRef Name = getNameFromIdOrString(*this, Tok, CONTEXT_TRAIT_LVL);892if (Name.empty()) {893Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options)894<< CONTEXT_TRAIT_LVL << listOpenMPContextTraitProperties(Set, Selector);895return;896}897
898TIProperty.RawString = Name;899TIProperty.Kind = getOpenMPContextTraitPropertyKind(Set, Selector, Name);900if (TIProperty.Kind != TraitProperty::invalid) {901if (checkForDuplicates(*this, Name, NameLoc, Seen, CONTEXT_TRAIT_LVL))902TIProperty.Kind = TraitProperty::invalid;903return;904}905
906// It follows diagnosis and helping notes.907// FIXME: We should move the diagnosis string generation into libFrontend.908Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_property)909<< Name << getOpenMPContextTraitSelectorName(Selector)910<< getOpenMPContextTraitSetName(Set);911
912TraitSet SetForName = getOpenMPContextTraitSetKind(Name);913if (SetForName != TraitSet::invalid) {914Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)915<< Name << CONTEXT_SELECTOR_SET_LVL << CONTEXT_TRAIT_LVL;916Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)917<< Name << "<selector-name>"918<< "(<property-name>)";919return;920}921TraitSelector SelectorForName = getOpenMPContextTraitSelectorKind(Name);922if (SelectorForName != TraitSelector::invalid) {923Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)924<< Name << CONTEXT_SELECTOR_LVL << CONTEXT_TRAIT_LVL;925bool AllowsTraitScore = false;926bool RequiresProperty = false;927isValidTraitSelectorForTraitSet(928SelectorForName, getOpenMPContextTraitSetForSelector(SelectorForName),929AllowsTraitScore, RequiresProperty);930Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)931<< getOpenMPContextTraitSetName(932getOpenMPContextTraitSetForSelector(SelectorForName))933<< Name << (RequiresProperty ? "(<property-name>)" : "");934return;935}936for (const auto &PotentialSet :937{TraitSet::construct, TraitSet::user, TraitSet::implementation,938TraitSet::device}) {939TraitProperty PropertyForName =940getOpenMPContextTraitPropertyKind(PotentialSet, Selector, Name);941if (PropertyForName == TraitProperty::invalid)942continue;943Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)944<< getOpenMPContextTraitSetName(945getOpenMPContextTraitSetForProperty(PropertyForName))946<< getOpenMPContextTraitSelectorName(947getOpenMPContextTraitSelectorForProperty(PropertyForName))948<< ("(" + Name + ")").str();949return;950}951Diag(NameLoc, diag::note_omp_declare_variant_ctx_options)952<< CONTEXT_TRAIT_LVL << listOpenMPContextTraitProperties(Set, Selector);953}
954
955static bool checkExtensionProperty(Parser &P, SourceLocation Loc,956OMPTraitProperty &TIProperty,957OMPTraitSelector &TISelector,958llvm::StringMap<SourceLocation> &Seen) {959assert(TISelector.Kind ==960llvm::omp::TraitSelector::implementation_extension &&961"Only for extension properties, e.g., "962"`implementation={extension(PROPERTY)}`");963if (TIProperty.Kind == TraitProperty::invalid)964return false;965
966if (TIProperty.Kind ==967TraitProperty::implementation_extension_disable_implicit_base)968return true;969
970if (TIProperty.Kind ==971TraitProperty::implementation_extension_allow_templates)972return true;973
974if (TIProperty.Kind ==975TraitProperty::implementation_extension_bind_to_declaration)976return true;977
978auto IsMatchExtension = [](OMPTraitProperty &TP) {979return (TP.Kind ==980llvm::omp::TraitProperty::implementation_extension_match_all ||981TP.Kind ==982llvm::omp::TraitProperty::implementation_extension_match_any ||983TP.Kind ==984llvm::omp::TraitProperty::implementation_extension_match_none);985};986
987if (IsMatchExtension(TIProperty)) {988for (OMPTraitProperty &SeenProp : TISelector.Properties)989if (IsMatchExtension(SeenProp)) {990P.Diag(Loc, diag::err_omp_variant_ctx_second_match_extension);991StringRef SeenName = llvm::omp::getOpenMPContextTraitPropertyName(992SeenProp.Kind, SeenProp.RawString);993SourceLocation SeenLoc = Seen[SeenName];994P.Diag(SeenLoc, diag::note_omp_declare_variant_ctx_used_here)995<< CONTEXT_TRAIT_LVL << SeenName;996return false;997}998return true;999}1000
1001llvm_unreachable("Unknown extension property!");1002}
1003
1004void Parser::parseOMPContextProperty(OMPTraitSelector &TISelector,1005llvm::omp::TraitSet Set,1006llvm::StringMap<SourceLocation> &Seen) {1007assert(TISelector.Kind != TraitSelector::user_condition &&1008"User conditions are special properties not handled here!");1009
1010SourceLocation PropertyLoc = Tok.getLocation();1011OMPTraitProperty TIProperty;1012parseOMPTraitPropertyKind(TIProperty, Set, TISelector.Kind, Seen);1013
1014if (TISelector.Kind == llvm::omp::TraitSelector::implementation_extension)1015if (!checkExtensionProperty(*this, Tok.getLocation(), TIProperty,1016TISelector, Seen))1017TIProperty.Kind = TraitProperty::invalid;1018
1019// If we have an invalid property here we already issued a warning.1020if (TIProperty.Kind == TraitProperty::invalid) {1021if (PropertyLoc != Tok.getLocation())1022Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here)1023<< CONTEXT_TRAIT_LVL;1024return;1025}1026
1027if (isValidTraitPropertyForTraitSetAndSelector(TIProperty.Kind,1028TISelector.Kind, Set)) {1029
1030// If we make it here the property, selector, set, score, condition, ... are1031// all valid (or have been corrected). Thus we can record the property.1032TISelector.Properties.push_back(TIProperty);1033return;1034}1035
1036Diag(PropertyLoc, diag::warn_omp_ctx_incompatible_property_for_selector)1037<< getOpenMPContextTraitPropertyName(TIProperty.Kind,1038TIProperty.RawString)1039<< getOpenMPContextTraitSelectorName(TISelector.Kind)1040<< getOpenMPContextTraitSetName(Set);1041Diag(PropertyLoc, diag::note_omp_ctx_compatible_set_and_selector_for_property)1042<< getOpenMPContextTraitPropertyName(TIProperty.Kind,1043TIProperty.RawString)1044<< getOpenMPContextTraitSelectorName(1045getOpenMPContextTraitSelectorForProperty(TIProperty.Kind))1046<< getOpenMPContextTraitSetName(1047getOpenMPContextTraitSetForProperty(TIProperty.Kind));1048Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here)1049<< CONTEXT_TRAIT_LVL;1050}
1051
1052void Parser::parseOMPTraitSelectorKind(OMPTraitSelector &TISelector,1053llvm::omp::TraitSet Set,1054llvm::StringMap<SourceLocation> &Seen) {1055TISelector.Kind = TraitSelector::invalid;1056
1057SourceLocation NameLoc = Tok.getLocation();1058StringRef Name = getNameFromIdOrString(*this, Tok, CONTEXT_SELECTOR_LVL);1059if (Name.empty()) {1060Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options)1061<< CONTEXT_SELECTOR_LVL << listOpenMPContextTraitSelectors(Set);1062return;1063}1064
1065TISelector.Kind = getOpenMPContextTraitSelectorKind(Name);1066if (TISelector.Kind != TraitSelector::invalid) {1067if (checkForDuplicates(*this, Name, NameLoc, Seen, CONTEXT_SELECTOR_LVL))1068TISelector.Kind = TraitSelector::invalid;1069return;1070}1071
1072// It follows diagnosis and helping notes.1073Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_selector)1074<< Name << getOpenMPContextTraitSetName(Set);1075
1076TraitSet SetForName = getOpenMPContextTraitSetKind(Name);1077if (SetForName != TraitSet::invalid) {1078Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)1079<< Name << CONTEXT_SELECTOR_SET_LVL << CONTEXT_SELECTOR_LVL;1080Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)1081<< Name << "<selector-name>"1082<< "<property-name>";1083return;1084}1085for (const auto &PotentialSet :1086{TraitSet::construct, TraitSet::user, TraitSet::implementation,1087TraitSet::device}) {1088TraitProperty PropertyForName = getOpenMPContextTraitPropertyKind(1089PotentialSet, TraitSelector::invalid, Name);1090if (PropertyForName == TraitProperty::invalid)1091continue;1092Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)1093<< Name << CONTEXT_TRAIT_LVL << CONTEXT_SELECTOR_LVL;1094Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)1095<< getOpenMPContextTraitSetName(1096getOpenMPContextTraitSetForProperty(PropertyForName))1097<< getOpenMPContextTraitSelectorName(1098getOpenMPContextTraitSelectorForProperty(PropertyForName))1099<< ("(" + Name + ")").str();1100return;1101}1102Diag(NameLoc, diag::note_omp_declare_variant_ctx_options)1103<< CONTEXT_SELECTOR_LVL << listOpenMPContextTraitSelectors(Set);1104}
1105
1106/// Parse optional 'score' '(' <expr> ')' ':'.
1107static ExprResult parseContextScore(Parser &P) {1108ExprResult ScoreExpr;1109llvm::SmallString<16> Buffer;1110StringRef SelectorName =1111P.getPreprocessor().getSpelling(P.getCurToken(), Buffer);1112if (SelectorName != "score")1113return ScoreExpr;1114(void)P.ConsumeToken();1115SourceLocation RLoc;1116ScoreExpr = P.ParseOpenMPParensExpr(SelectorName, RLoc);1117// Parse ':'1118if (P.getCurToken().is(tok::colon))1119(void)P.ConsumeAnyToken();1120else1121P.Diag(P.getCurToken(), diag::warn_omp_declare_variant_expected)1122<< "':'"1123<< "score expression";1124return ScoreExpr;1125}
1126
1127/// Parses an OpenMP context selector.
1128///
1129/// <trait-selector-name> ['('[<trait-score>] <trait-property> [, <t-p>]* ')']
1130void Parser::parseOMPContextSelector(1131OMPTraitSelector &TISelector, llvm::omp::TraitSet Set,1132llvm::StringMap<SourceLocation> &SeenSelectors) {1133unsigned short OuterPC = ParenCount;1134
1135// If anything went wrong we issue an error or warning and then skip the rest1136// of the selector. However, commas are ambiguous so we look for the nesting1137// of parentheses here as well.1138auto FinishSelector = [OuterPC, this]() -> void {1139bool Done = false;1140while (!Done) {1141while (!SkipUntil({tok::r_brace, tok::r_paren, tok::comma,1142tok::annot_pragma_openmp_end},1143StopBeforeMatch))1144;1145if (Tok.is(tok::r_paren) && OuterPC > ParenCount)1146(void)ConsumeParen();1147if (OuterPC <= ParenCount) {1148Done = true;1149break;1150}1151if (!Tok.is(tok::comma) && !Tok.is(tok::r_paren)) {1152Done = true;1153break;1154}1155(void)ConsumeAnyToken();1156}1157Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here)1158<< CONTEXT_SELECTOR_LVL;1159};1160
1161SourceLocation SelectorLoc = Tok.getLocation();1162parseOMPTraitSelectorKind(TISelector, Set, SeenSelectors);1163if (TISelector.Kind == TraitSelector::invalid)1164return FinishSelector();1165
1166bool AllowsTraitScore = false;1167bool RequiresProperty = false;1168if (!isValidTraitSelectorForTraitSet(TISelector.Kind, Set, AllowsTraitScore,1169RequiresProperty)) {1170Diag(SelectorLoc, diag::warn_omp_ctx_incompatible_selector_for_set)1171<< getOpenMPContextTraitSelectorName(TISelector.Kind)1172<< getOpenMPContextTraitSetName(Set);1173Diag(SelectorLoc, diag::note_omp_ctx_compatible_set_for_selector)1174<< getOpenMPContextTraitSelectorName(TISelector.Kind)1175<< getOpenMPContextTraitSetName(1176getOpenMPContextTraitSetForSelector(TISelector.Kind))1177<< RequiresProperty;1178return FinishSelector();1179}1180
1181if (!RequiresProperty) {1182TISelector.Properties.push_back(1183{getOpenMPContextTraitPropertyForSelector(TISelector.Kind),1184getOpenMPContextTraitSelectorName(TISelector.Kind)});1185return;1186}1187
1188if (!Tok.is(tok::l_paren)) {1189Diag(SelectorLoc, diag::warn_omp_ctx_selector_without_properties)1190<< getOpenMPContextTraitSelectorName(TISelector.Kind)1191<< getOpenMPContextTraitSetName(Set);1192return FinishSelector();1193}1194
1195if (TISelector.Kind == TraitSelector::user_condition) {1196SourceLocation RLoc;1197ExprResult Condition = ParseOpenMPParensExpr("user condition", RLoc);1198if (!Condition.isUsable())1199return FinishSelector();1200TISelector.ScoreOrCondition = Condition.get();1201TISelector.Properties.push_back(1202{TraitProperty::user_condition_unknown, "<condition>"});1203return;1204}1205
1206BalancedDelimiterTracker BDT(*this, tok::l_paren,1207tok::annot_pragma_openmp_end);1208// Parse '('.1209(void)BDT.consumeOpen();1210
1211SourceLocation ScoreLoc = Tok.getLocation();1212ExprResult Score = parseContextScore(*this);1213
1214if (!AllowsTraitScore && !Score.isUnset()) {1215if (Score.isUsable()) {1216Diag(ScoreLoc, diag::warn_omp_ctx_incompatible_score_for_property)1217<< getOpenMPContextTraitSelectorName(TISelector.Kind)1218<< getOpenMPContextTraitSetName(Set) << Score.get();1219} else {1220Diag(ScoreLoc, diag::warn_omp_ctx_incompatible_score_for_property)1221<< getOpenMPContextTraitSelectorName(TISelector.Kind)1222<< getOpenMPContextTraitSetName(Set) << "<invalid>";1223}1224Score = ExprResult();1225}1226
1227if (Score.isUsable())1228TISelector.ScoreOrCondition = Score.get();1229
1230llvm::StringMap<SourceLocation> SeenProperties;1231do {1232parseOMPContextProperty(TISelector, Set, SeenProperties);1233} while (TryConsumeToken(tok::comma));1234
1235// Parse ')'.1236BDT.consumeClose();1237}
1238
1239void Parser::parseOMPTraitSetKind(OMPTraitSet &TISet,1240llvm::StringMap<SourceLocation> &Seen) {1241TISet.Kind = TraitSet::invalid;1242
1243SourceLocation NameLoc = Tok.getLocation();1244StringRef Name = getNameFromIdOrString(*this, Tok, CONTEXT_SELECTOR_SET_LVL);1245if (Name.empty()) {1246Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_options)1247<< CONTEXT_SELECTOR_SET_LVL << listOpenMPContextTraitSets();1248return;1249}1250
1251TISet.Kind = getOpenMPContextTraitSetKind(Name);1252if (TISet.Kind != TraitSet::invalid) {1253if (checkForDuplicates(*this, Name, NameLoc, Seen,1254CONTEXT_SELECTOR_SET_LVL))1255TISet.Kind = TraitSet::invalid;1256return;1257}1258
1259// It follows diagnosis and helping notes.1260Diag(NameLoc, diag::warn_omp_declare_variant_ctx_not_a_set) << Name;1261
1262TraitSelector SelectorForName = getOpenMPContextTraitSelectorKind(Name);1263if (SelectorForName != TraitSelector::invalid) {1264Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)1265<< Name << CONTEXT_SELECTOR_LVL << CONTEXT_SELECTOR_SET_LVL;1266bool AllowsTraitScore = false;1267bool RequiresProperty = false;1268isValidTraitSelectorForTraitSet(1269SelectorForName, getOpenMPContextTraitSetForSelector(SelectorForName),1270AllowsTraitScore, RequiresProperty);1271Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)1272<< getOpenMPContextTraitSetName(1273getOpenMPContextTraitSetForSelector(SelectorForName))1274<< Name << (RequiresProperty ? "(<property-name>)" : "");1275return;1276}1277for (const auto &PotentialSet :1278{TraitSet::construct, TraitSet::user, TraitSet::implementation,1279TraitSet::device}) {1280TraitProperty PropertyForName = getOpenMPContextTraitPropertyKind(1281PotentialSet, TraitSelector::invalid, Name);1282if (PropertyForName == TraitProperty::invalid)1283continue;1284Diag(NameLoc, diag::note_omp_declare_variant_ctx_is_a)1285<< Name << CONTEXT_TRAIT_LVL << CONTEXT_SELECTOR_SET_LVL;1286Diag(NameLoc, diag::note_omp_declare_variant_ctx_try)1287<< getOpenMPContextTraitSetName(1288getOpenMPContextTraitSetForProperty(PropertyForName))1289<< getOpenMPContextTraitSelectorName(1290getOpenMPContextTraitSelectorForProperty(PropertyForName))1291<< ("(" + Name + ")").str();1292return;1293}1294Diag(NameLoc, diag::note_omp_declare_variant_ctx_options)1295<< CONTEXT_SELECTOR_SET_LVL << listOpenMPContextTraitSets();1296}
1297
1298/// Parses an OpenMP context selector set.
1299///
1300/// <trait-set-selector-name> '=' '{' <trait-selector> [, <trait-selector>]* '}'
1301void Parser::parseOMPContextSelectorSet(1302OMPTraitSet &TISet, llvm::StringMap<SourceLocation> &SeenSets) {1303auto OuterBC = BraceCount;1304
1305// If anything went wrong we issue an error or warning and then skip the rest1306// of the set. However, commas are ambiguous so we look for the nesting1307// of braces here as well.1308auto FinishSelectorSet = [this, OuterBC]() -> void {1309bool Done = false;1310while (!Done) {1311while (!SkipUntil({tok::comma, tok::r_brace, tok::r_paren,1312tok::annot_pragma_openmp_end},1313StopBeforeMatch))1314;1315if (Tok.is(tok::r_brace) && OuterBC > BraceCount)1316(void)ConsumeBrace();1317if (OuterBC <= BraceCount) {1318Done = true;1319break;1320}1321if (!Tok.is(tok::comma) && !Tok.is(tok::r_brace)) {1322Done = true;1323break;1324}1325(void)ConsumeAnyToken();1326}1327Diag(Tok.getLocation(), diag::note_omp_declare_variant_ctx_continue_here)1328<< CONTEXT_SELECTOR_SET_LVL;1329};1330
1331parseOMPTraitSetKind(TISet, SeenSets);1332if (TISet.Kind == TraitSet::invalid)1333return FinishSelectorSet();1334
1335// Parse '='.1336if (!TryConsumeToken(tok::equal))1337Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected)1338<< "="1339<< ("context set name \"" + getOpenMPContextTraitSetName(TISet.Kind) +1340"\"")1341.str();1342
1343// Parse '{'.1344if (Tok.is(tok::l_brace)) {1345(void)ConsumeBrace();1346} else {1347Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected)1348<< "{"1349<< ("'=' that follows the context set name \"" +1350getOpenMPContextTraitSetName(TISet.Kind) + "\"")1351.str();1352}1353
1354llvm::StringMap<SourceLocation> SeenSelectors;1355do {1356OMPTraitSelector TISelector;1357parseOMPContextSelector(TISelector, TISet.Kind, SeenSelectors);1358if (TISelector.Kind != TraitSelector::invalid &&1359!TISelector.Properties.empty())1360TISet.Selectors.push_back(TISelector);1361} while (TryConsumeToken(tok::comma));1362
1363// Parse '}'.1364if (Tok.is(tok::r_brace)) {1365(void)ConsumeBrace();1366} else {1367Diag(Tok.getLocation(), diag::warn_omp_declare_variant_expected)1368<< "}"1369<< ("context selectors for the context set \"" +1370getOpenMPContextTraitSetName(TISet.Kind) + "\"")1371.str();1372}1373}
1374
1375/// Parse OpenMP context selectors:
1376///
1377/// <trait-set-selector> [, <trait-set-selector>]*
1378bool Parser::parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo &TI) {1379llvm::StringMap<SourceLocation> SeenSets;1380do {1381OMPTraitSet TISet;1382parseOMPContextSelectorSet(TISet, SeenSets);1383if (TISet.Kind != TraitSet::invalid && !TISet.Selectors.empty())1384TI.Sets.push_back(TISet);1385} while (TryConsumeToken(tok::comma));1386
1387return false;1388}
1389
1390/// Parse clauses for '#pragma omp declare variant ( variant-func-id ) clause'.
1391void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,1392CachedTokens &Toks,1393SourceLocation Loc) {1394PP.EnterToken(Tok, /*IsReinject*/ true);1395PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,1396/*IsReinject*/ true);1397// Consume the previously pushed token.1398ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);1399ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);1400
1401FNContextRAII FnContext(*this, Ptr);1402// Parse function declaration id.1403SourceLocation RLoc;1404// Parse with IsAddressOfOperand set to true to parse methods as DeclRefExprs1405// instead of MemberExprs.1406ExprResult AssociatedFunction;1407{1408// Do not mark function as is used to prevent its emission if this is the1409// only place where it is used.1410EnterExpressionEvaluationContext Unevaluated(1411Actions, Sema::ExpressionEvaluationContext::Unevaluated);1412AssociatedFunction = ParseOpenMPParensExpr(1413getOpenMPDirectiveName(OMPD_declare_variant), RLoc,1414/*IsAddressOfOperand=*/true);1415}1416if (!AssociatedFunction.isUsable()) {1417if (!Tok.is(tok::annot_pragma_openmp_end))1418while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch))1419;1420// Skip the last annot_pragma_openmp_end.1421(void)ConsumeAnnotationToken();1422return;1423}1424
1425OMPTraitInfo *ParentTI =1426Actions.OpenMP().getOMPTraitInfoForSurroundingScope();1427ASTContext &ASTCtx = Actions.getASTContext();1428OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo();1429SmallVector<Expr *, 6> AdjustNothing;1430SmallVector<Expr *, 6> AdjustNeedDevicePtr;1431SmallVector<OMPInteropInfo, 3> AppendArgs;1432SourceLocation AdjustArgsLoc, AppendArgsLoc;1433
1434// At least one clause is required.1435if (Tok.is(tok::annot_pragma_openmp_end)) {1436Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause)1437<< (getLangOpts().OpenMP < 51 ? 0 : 1);1438}1439
1440bool IsError = false;1441while (Tok.isNot(tok::annot_pragma_openmp_end)) {1442OpenMPClauseKind CKind = Tok.isAnnotation()1443? OMPC_unknown1444: getOpenMPClauseKind(PP.getSpelling(Tok));1445if (!isAllowedClauseForDirective(OMPD_declare_variant, CKind,1446getLangOpts().OpenMP)) {1447Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause)1448<< (getLangOpts().OpenMP < 51 ? 0 : 1);1449IsError = true;1450}1451if (!IsError) {1452switch (CKind) {1453case OMPC_match:1454IsError = parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI);1455break;1456case OMPC_adjust_args: {1457AdjustArgsLoc = Tok.getLocation();1458ConsumeToken();1459SemaOpenMP::OpenMPVarListDataTy Data;1460SmallVector<Expr *> Vars;1461IsError = ParseOpenMPVarList(OMPD_declare_variant, OMPC_adjust_args,1462Vars, Data);1463if (!IsError)1464llvm::append_range(Data.ExtraModifier == OMPC_ADJUST_ARGS_nothing1465? AdjustNothing1466: AdjustNeedDevicePtr,1467Vars);1468break;1469}1470case OMPC_append_args:1471if (!AppendArgs.empty()) {1472Diag(AppendArgsLoc, diag::err_omp_more_one_clause)1473<< getOpenMPDirectiveName(OMPD_declare_variant)1474<< getOpenMPClauseName(CKind) << 0;1475IsError = true;1476}1477if (!IsError) {1478AppendArgsLoc = Tok.getLocation();1479ConsumeToken();1480IsError = parseOpenMPAppendArgs(AppendArgs);1481}1482break;1483default:1484llvm_unreachable("Unexpected clause for declare variant.");1485}1486}1487if (IsError) {1488while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch))1489;1490// Skip the last annot_pragma_openmp_end.1491(void)ConsumeAnnotationToken();1492return;1493}1494// Skip ',' if any.1495if (Tok.is(tok::comma))1496ConsumeToken();1497}1498
1499std::optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =1500Actions.OpenMP().checkOpenMPDeclareVariantFunction(1501Ptr, AssociatedFunction.get(), TI, AppendArgs.size(),1502SourceRange(Loc, Tok.getLocation()));1503
1504if (DeclVarData && !TI.Sets.empty())1505Actions.OpenMP().ActOnOpenMPDeclareVariantDirective(1506DeclVarData->first, DeclVarData->second, TI, AdjustNothing,1507AdjustNeedDevicePtr, AppendArgs, AdjustArgsLoc, AppendArgsLoc,1508SourceRange(Loc, Tok.getLocation()));1509
1510// Skip the last annot_pragma_openmp_end.1511(void)ConsumeAnnotationToken();1512}
1513
1514bool Parser::parseOpenMPAppendArgs(1515SmallVectorImpl<OMPInteropInfo> &InteropInfos) {1516bool HasError = false;1517// Parse '('.1518BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);1519if (T.expectAndConsume(diag::err_expected_lparen_after,1520getOpenMPClauseName(OMPC_append_args).data()))1521return true;1522
1523// Parse the list of append-ops, each is;1524// interop(interop-type[,interop-type]...)1525while (Tok.is(tok::identifier) && Tok.getIdentifierInfo()->isStr("interop")) {1526ConsumeToken();1527BalancedDelimiterTracker IT(*this, tok::l_paren,1528tok::annot_pragma_openmp_end);1529if (IT.expectAndConsume(diag::err_expected_lparen_after, "interop"))1530return true;1531
1532OMPInteropInfo InteropInfo;1533if (ParseOMPInteropInfo(InteropInfo, OMPC_append_args))1534HasError = true;1535else1536InteropInfos.push_back(InteropInfo);1537
1538IT.consumeClose();1539if (Tok.is(tok::comma))1540ConsumeToken();1541}1542if (!HasError && InteropInfos.empty()) {1543HasError = true;1544Diag(Tok.getLocation(), diag::err_omp_unexpected_append_op);1545SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,1546StopBeforeMatch);1547}1548HasError = T.consumeClose() || HasError;1549return HasError;1550}
1551
1552bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc,1553OMPTraitInfo &TI,1554OMPTraitInfo *ParentTI) {1555// Parse 'match'.1556OpenMPClauseKind CKind = Tok.isAnnotation()1557? OMPC_unknown1558: getOpenMPClauseKind(PP.getSpelling(Tok));1559if (CKind != OMPC_match) {1560Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause)1561<< (getLangOpts().OpenMP < 51 ? 0 : 1);1562return true;1563}1564(void)ConsumeToken();1565// Parse '('.1566BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);1567if (T.expectAndConsume(diag::err_expected_lparen_after,1568getOpenMPClauseName(OMPC_match).data()))1569return true;1570
1571// Parse inner context selectors.1572parseOMPContextSelectors(Loc, TI);1573
1574// Parse ')'1575(void)T.consumeClose();1576
1577if (!ParentTI)1578return false;1579
1580// Merge the parent/outer trait info into the one we just parsed and diagnose1581// problems.1582// TODO: Keep some source location in the TI to provide better diagnostics.1583// TODO: Perform some kind of equivalence check on the condition and score1584// expressions.1585for (const OMPTraitSet &ParentSet : ParentTI->Sets) {1586bool MergedSet = false;1587for (OMPTraitSet &Set : TI.Sets) {1588if (Set.Kind != ParentSet.Kind)1589continue;1590MergedSet = true;1591for (const OMPTraitSelector &ParentSelector : ParentSet.Selectors) {1592bool MergedSelector = false;1593for (OMPTraitSelector &Selector : Set.Selectors) {1594if (Selector.Kind != ParentSelector.Kind)1595continue;1596MergedSelector = true;1597for (const OMPTraitProperty &ParentProperty :1598ParentSelector.Properties) {1599bool MergedProperty = false;1600for (OMPTraitProperty &Property : Selector.Properties) {1601// Ignore "equivalent" properties.1602if (Property.Kind != ParentProperty.Kind)1603continue;1604
1605// If the kind is the same but the raw string not, we don't want1606// to skip out on the property.1607MergedProperty |= Property.RawString == ParentProperty.RawString;1608
1609if (Property.RawString == ParentProperty.RawString &&1610Selector.ScoreOrCondition == ParentSelector.ScoreOrCondition)1611continue;1612
1613if (Selector.Kind == llvm::omp::TraitSelector::user_condition) {1614Diag(Loc, diag::err_omp_declare_variant_nested_user_condition);1615} else if (Selector.ScoreOrCondition !=1616ParentSelector.ScoreOrCondition) {1617Diag(Loc, diag::err_omp_declare_variant_duplicate_nested_trait)1618<< getOpenMPContextTraitPropertyName(1619ParentProperty.Kind, ParentProperty.RawString)1620<< getOpenMPContextTraitSelectorName(ParentSelector.Kind)1621<< getOpenMPContextTraitSetName(ParentSet.Kind);1622}1623}1624if (!MergedProperty)1625Selector.Properties.push_back(ParentProperty);1626}1627}1628if (!MergedSelector)1629Set.Selectors.push_back(ParentSelector);1630}1631}1632if (!MergedSet)1633TI.Sets.push_back(ParentSet);1634}1635
1636return false;1637}
1638
1639/// <clause> [clause[ [,] clause] ... ]
1640///
1641/// clauses: for error directive
1642/// 'at' '(' compilation | execution ')'
1643/// 'severity' '(' fatal | warning ')'
1644/// 'message' '(' msg-string ')'
1645/// ....
1646void Parser::ParseOpenMPClauses(OpenMPDirectiveKind DKind,1647SmallVectorImpl<OMPClause *> &Clauses,1648SourceLocation Loc) {1649std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses;1650while (Tok.isNot(tok::annot_pragma_openmp_end)) {1651OpenMPClauseKind CKind = Tok.isAnnotation()1652? OMPC_unknown1653: getOpenMPClauseKind(PP.getSpelling(Tok));1654Actions.OpenMP().StartOpenMPClause(CKind);1655OMPClause *Clause =1656ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]);1657SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,1658StopBeforeMatch);1659SeenClauses[unsigned(CKind)] = true;1660if (Clause != nullptr)1661Clauses.push_back(Clause);1662if (Tok.is(tok::annot_pragma_openmp_end)) {1663Actions.OpenMP().EndOpenMPClause();1664break;1665}1666// Skip ',' if any.1667if (Tok.is(tok::comma))1668ConsumeToken();1669Actions.OpenMP().EndOpenMPClause();1670}1671}
1672
1673/// `omp assumes` or `omp begin/end assumes` <clause> [[,]<clause>]...
1674/// where
1675///
1676/// clause:
1677/// 'ext_IMPL_DEFINED'
1678/// 'absent' '(' directive-name [, directive-name]* ')'
1679/// 'contains' '(' directive-name [, directive-name]* ')'
1680/// 'holds' '(' scalar-expression ')'
1681/// 'no_openmp'
1682/// 'no_openmp_routines'
1683/// 'no_parallelism'
1684///
1685void Parser::ParseOpenMPAssumesDirective(OpenMPDirectiveKind DKind,1686SourceLocation Loc) {1687SmallVector<std::string, 4> Assumptions;1688bool SkippedClauses = false;1689
1690auto SkipBraces = [&](llvm::StringRef Spelling, bool IssueNote) {1691BalancedDelimiterTracker T(*this, tok::l_paren,1692tok::annot_pragma_openmp_end);1693if (T.expectAndConsume(diag::err_expected_lparen_after, Spelling.data()))1694return;1695T.skipToEnd();1696if (IssueNote && T.getCloseLocation().isValid())1697Diag(T.getCloseLocation(),1698diag::note_omp_assumption_clause_continue_here);1699};1700
1701/// Helper to determine which AssumptionClauseMapping (ACM) in the1702/// AssumptionClauseMappings table matches \p RawString. The return value is1703/// the index of the matching ACM into the table or -1 if there was no match.1704auto MatchACMClause = [&](StringRef RawString) {1705llvm::StringSwitch<int> SS(RawString);1706unsigned ACMIdx = 0;1707for (const AssumptionClauseMappingInfo &ACMI : AssumptionClauseMappings) {1708if (ACMI.StartsWith)1709SS.StartsWith(ACMI.Identifier, ACMIdx++);1710else1711SS.Case(ACMI.Identifier, ACMIdx++);1712}1713return SS.Default(-1);1714};1715
1716while (Tok.isNot(tok::annot_pragma_openmp_end)) {1717IdentifierInfo *II = nullptr;1718SourceLocation StartLoc = Tok.getLocation();1719int Idx = -1;1720if (Tok.isAnyIdentifier()) {1721II = Tok.getIdentifierInfo();1722Idx = MatchACMClause(II->getName());1723}1724ConsumeAnyToken();1725
1726bool NextIsLPar = Tok.is(tok::l_paren);1727// Handle unknown clauses by skipping them.1728if (Idx == -1) {1729Diag(StartLoc, diag::warn_omp_unknown_assumption_clause_missing_id)1730<< llvm::omp::getOpenMPDirectiveName(DKind)1731<< llvm::omp::getAllAssumeClauseOptions() << NextIsLPar;1732if (NextIsLPar)1733SkipBraces(II ? II->getName() : "", /* IssueNote */ true);1734SkippedClauses = true;1735continue;1736}1737const AssumptionClauseMappingInfo &ACMI = AssumptionClauseMappings[Idx];1738if (ACMI.HasDirectiveList || ACMI.HasExpression) {1739// TODO: We ignore absent, contains, and holds assumptions for now. We1740// also do not verify the content in the parenthesis at all.1741SkippedClauses = true;1742SkipBraces(II->getName(), /* IssueNote */ false);1743continue;1744}1745
1746if (NextIsLPar) {1747Diag(Tok.getLocation(),1748diag::warn_omp_unknown_assumption_clause_without_args)1749<< II;1750SkipBraces(II->getName(), /* IssueNote */ true);1751}1752
1753assert(II && "Expected an identifier clause!");1754std::string Assumption = II->getName().str();1755if (ACMI.StartsWith)1756Assumption = "ompx_" + Assumption.substr(ACMI.Identifier.size());1757else1758Assumption = "omp_" + Assumption;1759Assumptions.push_back(Assumption);1760}1761
1762Actions.OpenMP().ActOnOpenMPAssumesDirective(Loc, DKind, Assumptions,1763SkippedClauses);1764}
1765
1766void Parser::ParseOpenMPEndAssumesDirective(SourceLocation Loc) {1767if (Actions.OpenMP().isInOpenMPAssumeScope())1768Actions.OpenMP().ActOnOpenMPEndAssumesDirective();1769else1770Diag(Loc, diag::err_expected_begin_assumes);1771}
1772
1773/// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
1774///
1775/// default-clause:
1776/// 'default' '(' 'none' | 'shared' | 'private' | 'firstprivate' ')
1777///
1778/// proc_bind-clause:
1779/// 'proc_bind' '(' 'master' | 'close' | 'spread' ')
1780///
1781/// device_type-clause:
1782/// 'device_type' '(' 'host' | 'nohost' | 'any' )'
1783namespace {1784struct SimpleClauseData {1785unsigned Type;1786SourceLocation Loc;1787SourceLocation LOpen;1788SourceLocation TypeLoc;1789SourceLocation RLoc;1790SimpleClauseData(unsigned Type, SourceLocation Loc, SourceLocation LOpen,1791SourceLocation TypeLoc, SourceLocation RLoc)1792: Type(Type), Loc(Loc), LOpen(LOpen), TypeLoc(TypeLoc), RLoc(RLoc) {}1793};1794} // anonymous namespace1795
1796static std::optional<SimpleClauseData>1797parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) {1798const Token &Tok = P.getCurToken();1799SourceLocation Loc = Tok.getLocation();1800SourceLocation LOpen = P.ConsumeToken();1801// Parse '('.1802BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end);1803if (T.expectAndConsume(diag::err_expected_lparen_after,1804getOpenMPClauseName(Kind).data()))1805return std::nullopt;1806
1807unsigned Type = getOpenMPSimpleClauseType(1808Kind, Tok.isAnnotation() ? "" : P.getPreprocessor().getSpelling(Tok),1809P.getLangOpts());1810SourceLocation TypeLoc = Tok.getLocation();1811if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&1812Tok.isNot(tok::annot_pragma_openmp_end))1813P.ConsumeAnyToken();1814
1815// Parse ')'.1816SourceLocation RLoc = Tok.getLocation();1817if (!T.consumeClose())1818RLoc = T.getCloseLocation();1819
1820return SimpleClauseData(Type, Loc, LOpen, TypeLoc, RLoc);1821}
1822
1823void Parser::ParseOMPDeclareTargetClauses(1824SemaOpenMP::DeclareTargetContextInfo &DTCI) {1825SourceLocation DeviceTypeLoc;1826bool RequiresToOrLinkOrIndirectClause = false;1827bool HasToOrLinkOrIndirectClause = false;1828while (Tok.isNot(tok::annot_pragma_openmp_end)) {1829OMPDeclareTargetDeclAttr::MapTypeTy MT = OMPDeclareTargetDeclAttr::MT_To;1830bool HasIdentifier = Tok.is(tok::identifier);1831if (HasIdentifier) {1832// If we see any clause we need a to or link clause.1833RequiresToOrLinkOrIndirectClause = true;1834IdentifierInfo *II = Tok.getIdentifierInfo();1835StringRef ClauseName = II->getName();1836bool IsDeviceTypeClause =1837getLangOpts().OpenMP >= 50 &&1838getOpenMPClauseKind(ClauseName) == OMPC_device_type;1839
1840bool IsIndirectClause = getLangOpts().OpenMP >= 51 &&1841getOpenMPClauseKind(ClauseName) == OMPC_indirect;1842if (DTCI.Indirect && IsIndirectClause) {1843Diag(Tok, diag::err_omp_more_one_clause)1844<< getOpenMPDirectiveName(OMPD_declare_target)1845<< getOpenMPClauseName(OMPC_indirect) << 0;1846break;1847}1848bool IsToEnterOrLinkClause =1849OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT);1850assert((!IsDeviceTypeClause || !IsToEnterOrLinkClause) &&1851"Cannot be both!");1852
1853// Starting with OpenMP 5.2 the `to` clause has been replaced by the1854// `enter` clause.1855if (getLangOpts().OpenMP >= 52 && ClauseName == "to") {1856Diag(Tok, diag::err_omp_declare_target_unexpected_to_clause);1857break;1858}1859if (getLangOpts().OpenMP <= 51 && ClauseName == "enter") {1860Diag(Tok, diag::err_omp_declare_target_unexpected_enter_clause);1861break;1862}1863
1864if (!IsDeviceTypeClause && !IsIndirectClause &&1865DTCI.Kind == OMPD_begin_declare_target) {1866Diag(Tok, diag::err_omp_declare_target_unexpected_clause)1867<< ClauseName << (getLangOpts().OpenMP >= 51 ? 3 : 0);1868break;1869}1870if (!IsDeviceTypeClause && !IsToEnterOrLinkClause && !IsIndirectClause) {1871Diag(Tok, getLangOpts().OpenMP >= 521872? diag::err_omp_declare_target_unexpected_clause_521873: diag::err_omp_declare_target_unexpected_clause)1874<< ClauseName1875<< (getLangOpts().OpenMP >= 511876? 41877: getLangOpts().OpenMP >= 50 ? 2 : 1);1878break;1879}1880
1881if (IsToEnterOrLinkClause || IsIndirectClause)1882HasToOrLinkOrIndirectClause = true;1883
1884if (IsIndirectClause) {1885if (!ParseOpenMPIndirectClause(DTCI, /*ParseOnly*/ false))1886break;1887continue;1888}1889// Parse 'device_type' clause and go to next clause if any.1890if (IsDeviceTypeClause) {1891std::optional<SimpleClauseData> DevTypeData =1892parseOpenMPSimpleClause(*this, OMPC_device_type);1893if (DevTypeData) {1894if (DeviceTypeLoc.isValid()) {1895// We already saw another device_type clause, diagnose it.1896Diag(DevTypeData->Loc,1897diag::warn_omp_more_one_device_type_clause);1898break;1899}1900switch (static_cast<OpenMPDeviceType>(DevTypeData->Type)) {1901case OMPC_DEVICE_TYPE_any:1902DTCI.DT = OMPDeclareTargetDeclAttr::DT_Any;1903break;1904case OMPC_DEVICE_TYPE_host:1905DTCI.DT = OMPDeclareTargetDeclAttr::DT_Host;1906break;1907case OMPC_DEVICE_TYPE_nohost:1908DTCI.DT = OMPDeclareTargetDeclAttr::DT_NoHost;1909break;1910case OMPC_DEVICE_TYPE_unknown:1911llvm_unreachable("Unexpected device_type");1912}1913DeviceTypeLoc = DevTypeData->Loc;1914}1915continue;1916}1917ConsumeToken();1918}1919
1920if (DTCI.Kind == OMPD_declare_target || HasIdentifier) {1921auto &&Callback = [this, MT, &DTCI](CXXScopeSpec &SS,1922DeclarationNameInfo NameInfo) {1923NamedDecl *ND = Actions.OpenMP().lookupOpenMPDeclareTargetName(1924getCurScope(), SS, NameInfo);1925if (!ND)1926return;1927SemaOpenMP::DeclareTargetContextInfo::MapInfo MI{MT, NameInfo.getLoc()};1928bool FirstMapping = DTCI.ExplicitlyMapped.try_emplace(ND, MI).second;1929if (!FirstMapping)1930Diag(NameInfo.getLoc(), diag::err_omp_declare_target_multiple)1931<< NameInfo.getName();1932};1933if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback,1934/*AllowScopeSpecifier=*/true))1935break;1936}1937
1938if (Tok.is(tok::l_paren)) {1939Diag(Tok,1940diag::err_omp_begin_declare_target_unexpected_implicit_to_clause);1941break;1942}1943if (!HasIdentifier && Tok.isNot(tok::annot_pragma_openmp_end)) {1944Diag(Tok,1945getLangOpts().OpenMP >= 521946? diag::err_omp_declare_target_wrong_clause_after_implicit_enter1947: diag::err_omp_declare_target_wrong_clause_after_implicit_to);1948break;1949}1950
1951// Consume optional ','.1952if (Tok.is(tok::comma))1953ConsumeToken();1954}1955
1956if (DTCI.Indirect && DTCI.DT != OMPDeclareTargetDeclAttr::DT_Any)1957Diag(DeviceTypeLoc, diag::err_omp_declare_target_indirect_device_type);1958
1959// For declare target require at least 'to' or 'link' to be present.1960if (DTCI.Kind == OMPD_declare_target && RequiresToOrLinkOrIndirectClause &&1961!HasToOrLinkOrIndirectClause)1962Diag(DTCI.Loc,1963getLangOpts().OpenMP >= 521964? diag::err_omp_declare_target_missing_enter_or_link_clause1965: diag::err_omp_declare_target_missing_to_or_link_clause)1966<< (getLangOpts().OpenMP >= 51 ? 1 : 0);1967
1968SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);1969}
1970
1971void Parser::skipUntilPragmaOpenMPEnd(OpenMPDirectiveKind DKind) {1972// The last seen token is annot_pragma_openmp_end - need to check for1973// extra tokens.1974if (Tok.is(tok::annot_pragma_openmp_end))1975return;1976
1977Diag(Tok, diag::warn_omp_extra_tokens_at_eol)1978<< getOpenMPDirectiveName(DKind);1979while (Tok.isNot(tok::annot_pragma_openmp_end))1980ConsumeAnyToken();1981}
1982
1983void Parser::parseOMPEndDirective(OpenMPDirectiveKind BeginKind,1984OpenMPDirectiveKind ExpectedKind,1985OpenMPDirectiveKind FoundKind,1986SourceLocation BeginLoc,1987SourceLocation FoundLoc,1988bool SkipUntilOpenMPEnd) {1989int DiagSelection = ExpectedKind == OMPD_end_declare_target ? 0 : 1;1990
1991if (FoundKind == ExpectedKind) {1992ConsumeAnyToken();1993skipUntilPragmaOpenMPEnd(ExpectedKind);1994return;1995}1996
1997Diag(FoundLoc, diag::err_expected_end_declare_target_or_variant)1998<< DiagSelection;1999Diag(BeginLoc, diag::note_matching)2000<< ("'#pragma omp " + getOpenMPDirectiveName(BeginKind) + "'").str();2001if (SkipUntilOpenMPEnd)2002SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);2003}
2004
2005void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind BeginDKind,2006OpenMPDirectiveKind EndDKind,2007SourceLocation DKLoc) {2008parseOMPEndDirective(BeginDKind, OMPD_end_declare_target, EndDKind, DKLoc,2009Tok.getLocation(),2010/* SkipUntilOpenMPEnd */ false);2011// Skip the last annot_pragma_openmp_end.2012if (Tok.is(tok::annot_pragma_openmp_end))2013ConsumeAnnotationToken();2014}
2015
2016/// Parsing of declarative OpenMP directives.
2017///
2018/// threadprivate-directive:
2019/// annot_pragma_openmp 'threadprivate' simple-variable-list
2020/// annot_pragma_openmp_end
2021///
2022/// allocate-directive:
2023/// annot_pragma_openmp 'allocate' simple-variable-list [<clause>]
2024/// annot_pragma_openmp_end
2025///
2026/// declare-reduction-directive:
2027/// annot_pragma_openmp 'declare' 'reduction' [...]
2028/// annot_pragma_openmp_end
2029///
2030/// declare-mapper-directive:
2031/// annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifer> ':']
2032/// <type> <var> ')' [<clause>[[,] <clause>] ... ]
2033/// annot_pragma_openmp_end
2034///
2035/// declare-simd-directive:
2036/// annot_pragma_openmp 'declare simd' {<clause> [,]}
2037/// annot_pragma_openmp_end
2038/// <function declaration/definition>
2039///
2040/// requires directive:
2041/// annot_pragma_openmp 'requires' <clause> [[[,] <clause>] ... ]
2042/// annot_pragma_openmp_end
2043///
2044/// assumes directive:
2045/// annot_pragma_openmp 'assumes' <clause> [[[,] <clause>] ... ]
2046/// annot_pragma_openmp_end
2047/// or
2048/// annot_pragma_openmp 'begin assumes' <clause> [[[,] <clause>] ... ]
2049/// annot_pragma_openmp 'end assumes'
2050/// annot_pragma_openmp_end
2051///
2052Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(2053AccessSpecifier &AS, ParsedAttributes &Attrs, bool Delayed,2054DeclSpec::TST TagType, Decl *Tag) {2055assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) &&2056"Not an OpenMP directive!");2057ParsingOpenMPDirectiveRAII DirScope(*this);2058ParenBraceBracketBalancer BalancerRAIIObj(*this);2059
2060SourceLocation Loc;2061OpenMPDirectiveKind DKind;2062if (Delayed) {2063TentativeParsingAction TPA(*this);2064Loc = ConsumeAnnotationToken();2065DKind = parseOpenMPDirectiveKind(*this);2066if (DKind == OMPD_declare_reduction || DKind == OMPD_declare_mapper) {2067// Need to delay parsing until completion of the parent class.2068TPA.Revert();2069CachedTokens Toks;2070unsigned Cnt = 1;2071Toks.push_back(Tok);2072while (Cnt && Tok.isNot(tok::eof)) {2073(void)ConsumeAnyToken();2074if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp))2075++Cnt;2076else if (Tok.is(tok::annot_pragma_openmp_end))2077--Cnt;2078Toks.push_back(Tok);2079}2080// Skip last annot_pragma_openmp_end.2081if (Cnt == 0)2082(void)ConsumeAnyToken();2083auto *LP = new LateParsedPragma(this, AS);2084LP->takeToks(Toks);2085getCurrentClass().LateParsedDeclarations.push_back(LP);2086return nullptr;2087}2088TPA.Commit();2089} else {2090Loc = ConsumeAnnotationToken();2091DKind = parseOpenMPDirectiveKind(*this);2092}2093
2094switch (DKind) {2095case OMPD_threadprivate: {2096ConsumeToken();2097DeclDirectiveListParserHelper Helper(this, DKind);2098if (!ParseOpenMPSimpleVarList(DKind, Helper,2099/*AllowScopeSpecifier=*/true)) {2100skipUntilPragmaOpenMPEnd(DKind);2101// Skip the last annot_pragma_openmp_end.2102ConsumeAnnotationToken();2103return Actions.OpenMP().ActOnOpenMPThreadprivateDirective(2104Loc, Helper.getIdentifiers());2105}2106break;2107}2108case OMPD_allocate: {2109ConsumeToken();2110DeclDirectiveListParserHelper Helper(this, DKind);2111if (!ParseOpenMPSimpleVarList(DKind, Helper,2112/*AllowScopeSpecifier=*/true)) {2113SmallVector<OMPClause *, 1> Clauses;2114if (Tok.isNot(tok::annot_pragma_openmp_end)) {2115std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses;2116while (Tok.isNot(tok::annot_pragma_openmp_end)) {2117OpenMPClauseKind CKind =2118Tok.isAnnotation() ? OMPC_unknown2119: getOpenMPClauseKind(PP.getSpelling(Tok));2120Actions.OpenMP().StartOpenMPClause(CKind);2121OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind,2122!SeenClauses[unsigned(CKind)]);2123SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,2124StopBeforeMatch);2125SeenClauses[unsigned(CKind)] = true;2126if (Clause != nullptr)2127Clauses.push_back(Clause);2128if (Tok.is(tok::annot_pragma_openmp_end)) {2129Actions.OpenMP().EndOpenMPClause();2130break;2131}2132// Skip ',' if any.2133if (Tok.is(tok::comma))2134ConsumeToken();2135Actions.OpenMP().EndOpenMPClause();2136}2137skipUntilPragmaOpenMPEnd(DKind);2138}2139// Skip the last annot_pragma_openmp_end.2140ConsumeAnnotationToken();2141return Actions.OpenMP().ActOnOpenMPAllocateDirective(2142Loc, Helper.getIdentifiers(), Clauses);2143}2144break;2145}2146case OMPD_requires: {2147SourceLocation StartLoc = ConsumeToken();2148SmallVector<OMPClause *, 5> Clauses;2149llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1);2150if (Tok.is(tok::annot_pragma_openmp_end)) {2151Diag(Tok, diag::err_omp_expected_clause)2152<< getOpenMPDirectiveName(OMPD_requires);2153break;2154}2155while (Tok.isNot(tok::annot_pragma_openmp_end)) {2156OpenMPClauseKind CKind = Tok.isAnnotation()2157? OMPC_unknown2158: getOpenMPClauseKind(PP.getSpelling(Tok));2159Actions.OpenMP().StartOpenMPClause(CKind);2160OMPClause *Clause = ParseOpenMPClause(OMPD_requires, CKind,2161!SeenClauses[unsigned(CKind)]);2162SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,2163StopBeforeMatch);2164SeenClauses[unsigned(CKind)] = true;2165if (Clause != nullptr)2166Clauses.push_back(Clause);2167if (Tok.is(tok::annot_pragma_openmp_end)) {2168Actions.OpenMP().EndOpenMPClause();2169break;2170}2171// Skip ',' if any.2172if (Tok.is(tok::comma))2173ConsumeToken();2174Actions.OpenMP().EndOpenMPClause();2175}2176// Consume final annot_pragma_openmp_end2177if (Clauses.empty()) {2178Diag(Tok, diag::err_omp_expected_clause)2179<< getOpenMPDirectiveName(OMPD_requires);2180ConsumeAnnotationToken();2181return nullptr;2182}2183ConsumeAnnotationToken();2184return Actions.OpenMP().ActOnOpenMPRequiresDirective(StartLoc, Clauses);2185}2186case OMPD_error: {2187SmallVector<OMPClause *, 1> Clauses;2188SourceLocation StartLoc = ConsumeToken();2189ParseOpenMPClauses(DKind, Clauses, StartLoc);2190Actions.OpenMP().ActOnOpenMPErrorDirective(Clauses, StartLoc,2191SourceLocation(),2192/*InExContext = */ false);2193break;2194}2195case OMPD_assumes:2196case OMPD_begin_assumes:2197ParseOpenMPAssumesDirective(DKind, ConsumeToken());2198break;2199case OMPD_end_assumes:2200ParseOpenMPEndAssumesDirective(ConsumeToken());2201break;2202case OMPD_declare_reduction:2203ConsumeToken();2204if (DeclGroupPtrTy Res = ParseOpenMPDeclareReductionDirective(AS)) {2205skipUntilPragmaOpenMPEnd(OMPD_declare_reduction);2206// Skip the last annot_pragma_openmp_end.2207ConsumeAnnotationToken();2208return Res;2209}2210break;2211case OMPD_declare_mapper: {2212ConsumeToken();2213if (DeclGroupPtrTy Res = ParseOpenMPDeclareMapperDirective(AS)) {2214// Skip the last annot_pragma_openmp_end.2215ConsumeAnnotationToken();2216return Res;2217}2218break;2219}2220case OMPD_begin_declare_variant: {2221// The syntax is:2222// { #pragma omp begin declare variant clause }2223// <function-declaration-or-definition-sequence>2224// { #pragma omp end declare variant }2225//2226ConsumeToken();2227OMPTraitInfo *ParentTI =2228Actions.OpenMP().getOMPTraitInfoForSurroundingScope();2229ASTContext &ASTCtx = Actions.getASTContext();2230OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo();2231if (parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI)) {2232while (!SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch))2233;2234// Skip the last annot_pragma_openmp_end.2235(void)ConsumeAnnotationToken();2236break;2237}2238
2239// Skip last tokens.2240skipUntilPragmaOpenMPEnd(OMPD_begin_declare_variant);2241
2242ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);2243
2244VariantMatchInfo VMI;2245TI.getAsVariantMatchInfo(ASTCtx, VMI);2246
2247std::function<void(StringRef)> DiagUnknownTrait =2248[this, Loc](StringRef ISATrait) {2249// TODO Track the selector locations in a way that is accessible here2250// to improve the diagnostic location.2251Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) << ISATrait;2252};2253TargetOMPContext OMPCtx(2254ASTCtx, std::move(DiagUnknownTrait),2255/* CurrentFunctionDecl */ nullptr,2256/* ConstructTraits */ ArrayRef<llvm::omp::TraitProperty>());2257
2258if (isVariantApplicableInContext(VMI, OMPCtx, /* DeviceSetOnly */ true)) {2259Actions.OpenMP().ActOnOpenMPBeginDeclareVariant(Loc, TI);2260break;2261}2262
2263// Elide all the code till the matching end declare variant was found.2264unsigned Nesting = 1;2265SourceLocation DKLoc;2266OpenMPDirectiveKind DK = OMPD_unknown;2267do {2268DKLoc = Tok.getLocation();2269DK = parseOpenMPDirectiveKind(*this);2270if (DK == OMPD_end_declare_variant)2271--Nesting;2272else if (DK == OMPD_begin_declare_variant)2273++Nesting;2274if (!Nesting || isEofOrEom())2275break;2276ConsumeAnyToken();2277} while (true);2278
2279parseOMPEndDirective(OMPD_begin_declare_variant, OMPD_end_declare_variant,2280DK, Loc, DKLoc, /* SkipUntilOpenMPEnd */ true);2281if (isEofOrEom())2282return nullptr;2283break;2284}2285case OMPD_end_declare_variant: {2286if (Actions.OpenMP().isInOpenMPDeclareVariantScope())2287Actions.OpenMP().ActOnOpenMPEndDeclareVariant();2288else2289Diag(Loc, diag::err_expected_begin_declare_variant);2290ConsumeToken();2291break;2292}2293case OMPD_declare_variant:2294case OMPD_declare_simd: {2295// The syntax is:2296// { #pragma omp declare {simd|variant} }2297// <function-declaration-or-definition>2298//2299CachedTokens Toks;2300Toks.push_back(Tok);2301ConsumeToken();2302while (Tok.isNot(tok::annot_pragma_openmp_end)) {2303Toks.push_back(Tok);2304ConsumeAnyToken();2305}2306Toks.push_back(Tok);2307ConsumeAnyToken();2308
2309DeclGroupPtrTy Ptr;2310if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp)) {2311Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, Delayed,2312TagType, Tag);2313} else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) {2314// Here we expect to see some function declaration.2315if (AS == AS_none) {2316assert(TagType == DeclSpec::TST_unspecified);2317ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);2318MaybeParseCXX11Attributes(Attrs);2319ParsingDeclSpec PDS(*this);2320Ptr = ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs, &PDS);2321} else {2322Ptr =2323ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag);2324}2325}2326if (!Ptr) {2327Diag(Loc, diag::err_omp_decl_in_declare_simd_variant)2328<< (DKind == OMPD_declare_simd ? 0 : 1);2329return DeclGroupPtrTy();2330}2331if (DKind == OMPD_declare_simd)2332return ParseOMPDeclareSimdClauses(Ptr, Toks, Loc);2333assert(DKind == OMPD_declare_variant &&2334"Expected declare variant directive only");2335ParseOMPDeclareVariantClauses(Ptr, Toks, Loc);2336return Ptr;2337}2338case OMPD_begin_declare_target:2339case OMPD_declare_target: {2340SourceLocation DTLoc = ConsumeAnyToken();2341bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end);2342SemaOpenMP::DeclareTargetContextInfo DTCI(DKind, DTLoc);2343if (HasClauses)2344ParseOMPDeclareTargetClauses(DTCI);2345bool HasImplicitMappings = DKind == OMPD_begin_declare_target ||2346!HasClauses ||2347(DTCI.ExplicitlyMapped.empty() && DTCI.Indirect);2348
2349// Skip the last annot_pragma_openmp_end.2350ConsumeAnyToken();2351
2352if (HasImplicitMappings) {2353Actions.OpenMP().ActOnStartOpenMPDeclareTargetContext(DTCI);2354return nullptr;2355}2356
2357Actions.OpenMP().ActOnFinishedOpenMPDeclareTargetContext(DTCI);2358llvm::SmallVector<Decl *, 4> Decls;2359for (auto &It : DTCI.ExplicitlyMapped)2360Decls.push_back(It.first);2361return Actions.BuildDeclaratorGroup(Decls);2362}2363case OMPD_end_declare_target: {2364if (!Actions.OpenMP().isInOpenMPDeclareTargetContext()) {2365Diag(Tok, diag::err_omp_unexpected_directive)2366<< 1 << getOpenMPDirectiveName(DKind);2367break;2368}2369const SemaOpenMP::DeclareTargetContextInfo &DTCI =2370Actions.OpenMP().ActOnOpenMPEndDeclareTargetDirective();2371ParseOMPEndDeclareTargetDirective(DTCI.Kind, DKind, DTCI.Loc);2372return nullptr;2373}2374case OMPD_unknown:2375Diag(Tok, diag::err_omp_unknown_directive);2376break;2377default:2378switch (getDirectiveCategory(DKind)) {2379case Category::Executable:2380case Category::Meta:2381case Category::Subsidiary:2382case Category::Utility:2383Diag(Tok, diag::err_omp_unexpected_directive)2384<< 1 << getOpenMPDirectiveName(DKind);2385break;2386case Category::Declarative:2387case Category::Informational:2388break;2389}2390}2391while (Tok.isNot(tok::annot_pragma_openmp_end))2392ConsumeAnyToken();2393ConsumeAnyToken();2394return nullptr;2395}
2396
2397StmtResult Parser::ParseOpenMPExecutableDirective(2398ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc,2399bool ReadDirectiveWithinMetadirective) {2400assert(isOpenMPExecutableDirective(DKind) && "Unexpected directive category");2401
2402bool HasAssociatedStatement = true;2403Association Assoc = getDirectiveAssociation(DKind);2404
2405// OMPD_ordered has None as association, but it comes in two variants,2406// the second of which is associated with a block.2407// OMPD_scan and OMPD_section are both "separating", but section is treated2408// as if it was associated with a statement, while scan is not.2409if (DKind != OMPD_ordered && DKind != OMPD_section &&2410(Assoc == Association::None || Assoc == Association::Separating)) {2411if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==2412ParsedStmtContext()) {2413Diag(Tok, diag::err_omp_immediate_directive)2414<< getOpenMPDirectiveName(DKind) << 0;2415if (DKind == OMPD_error) {2416SkipUntil(tok::annot_pragma_openmp_end);2417return StmtError();2418}2419}2420HasAssociatedStatement = false;2421}2422
2423SourceLocation EndLoc;2424SmallVector<OMPClause *, 5> Clauses;2425llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1);2426DeclarationNameInfo DirName;2427OpenMPDirectiveKind CancelRegion = OMPD_unknown;2428unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |2429Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;2430
2431// Special processing for flush and depobj clauses.2432Token ImplicitTok;2433bool ImplicitClauseAllowed = false;2434if (DKind == OMPD_flush || DKind == OMPD_depobj) {2435ImplicitTok = Tok;2436ImplicitClauseAllowed = true;2437}2438ConsumeToken();2439// Parse directive name of the 'critical' directive if any.2440if (DKind == OMPD_critical) {2441BalancedDelimiterTracker T(*this, tok::l_paren,2442tok::annot_pragma_openmp_end);2443if (!T.consumeOpen()) {2444if (Tok.isAnyIdentifier()) {2445DirName =2446DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation());2447ConsumeAnyToken();2448} else {2449Diag(Tok, diag::err_omp_expected_identifier_for_critical);2450}2451T.consumeClose();2452}2453} else if (DKind == OMPD_cancellation_point || DKind == OMPD_cancel) {2454CancelRegion = parseOpenMPDirectiveKind(*this);2455if (Tok.isNot(tok::annot_pragma_openmp_end))2456ConsumeToken();2457}2458
2459if (isOpenMPLoopDirective(DKind))2460ScopeFlags |= Scope::OpenMPLoopDirectiveScope;2461if (isOpenMPSimdDirective(DKind))2462ScopeFlags |= Scope::OpenMPSimdDirectiveScope;2463ParseScope OMPDirectiveScope(this, ScopeFlags);2464Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(),2465Loc);2466
2467while (Tok.isNot(tok::annot_pragma_openmp_end)) {2468// If we are parsing for a directive within a metadirective, the directive2469// ends with a ')'.2470if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) {2471while (Tok.isNot(tok::annot_pragma_openmp_end))2472ConsumeAnyToken();2473break;2474}2475bool HasImplicitClause = false;2476if (ImplicitClauseAllowed && Tok.is(tok::l_paren)) {2477HasImplicitClause = true;2478// Push copy of the current token back to stream to properly parse2479// pseudo-clause OMPFlushClause or OMPDepobjClause.2480PP.EnterToken(Tok, /*IsReinject*/ true);2481PP.EnterToken(ImplicitTok, /*IsReinject*/ true);2482ConsumeAnyToken();2483}2484OpenMPClauseKind CKind = Tok.isAnnotation()2485? OMPC_unknown2486: getOpenMPClauseKind(PP.getSpelling(Tok));2487if (HasImplicitClause) {2488assert(CKind == OMPC_unknown && "Must be unknown implicit clause.");2489if (DKind == OMPD_flush) {2490CKind = OMPC_flush;2491} else {2492assert(DKind == OMPD_depobj && "Expected flush or depobj directives.");2493CKind = OMPC_depobj;2494}2495}2496// No more implicit clauses allowed.2497ImplicitClauseAllowed = false;2498Actions.OpenMP().StartOpenMPClause(CKind);2499HasImplicitClause = false;2500OMPClause *Clause =2501ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]);2502SeenClauses[unsigned(CKind)] = true;2503if (Clause)2504Clauses.push_back(Clause);2505
2506// Skip ',' if any.2507if (Tok.is(tok::comma))2508ConsumeToken();2509Actions.OpenMP().EndOpenMPClause();2510}2511// End location of the directive.2512EndLoc = Tok.getLocation();2513// Consume final annot_pragma_openmp_end.2514ConsumeAnnotationToken();2515
2516if (DKind == OMPD_ordered) {2517// If the depend or doacross clause is specified, the ordered construct2518// is a stand-alone directive.2519for (auto CK : {OMPC_depend, OMPC_doacross}) {2520if (SeenClauses[unsigned(CK)]) {2521if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==2522ParsedStmtContext()) {2523Diag(Loc, diag::err_omp_immediate_directive)2524<< getOpenMPDirectiveName(DKind) << 1 << getOpenMPClauseName(CK);2525}2526HasAssociatedStatement = false;2527}2528}2529}2530
2531if (DKind == OMPD_tile && !SeenClauses[unsigned(OMPC_sizes)]) {2532Diag(Loc, diag::err_omp_required_clause)2533<< getOpenMPDirectiveName(OMPD_tile) << "sizes";2534}2535
2536StmtResult AssociatedStmt;2537if (HasAssociatedStatement) {2538// The body is a block scope like in Lambdas and Blocks.2539Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope());2540// FIXME: We create a bogus CompoundStmt scope to hold the contents of2541// the captured region. Code elsewhere assumes that any FunctionScopeInfo2542// should have at least one compound statement scope within it.2543ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);2544{2545Sema::CompoundScopeRAII Scope(Actions);2546AssociatedStmt = ParseStatement();2547
2548if (AssociatedStmt.isUsable() && isOpenMPLoopDirective(DKind) &&2549getLangOpts().OpenMPIRBuilder)2550AssociatedStmt =2551Actions.OpenMP().ActOnOpenMPLoopnest(AssociatedStmt.get());2552}2553AssociatedStmt =2554Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);2555} else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data ||2556DKind == OMPD_target_exit_data) {2557Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope());2558AssociatedStmt = (Sema::CompoundScopeRAII(Actions),2559Actions.ActOnCompoundStmt(Loc, Loc, std::nullopt,2560/*isStmtExpr=*/false));2561AssociatedStmt =2562Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);2563}2564
2565StmtResult Directive = Actions.OpenMP().ActOnOpenMPExecutableDirective(2566DKind, DirName, CancelRegion, Clauses, AssociatedStmt.get(), Loc, EndLoc);2567
2568// Exit scope.2569Actions.OpenMP().EndOpenMPDSABlock(Directive.get());2570OMPDirectiveScope.Exit();2571
2572return Directive;2573}
2574
2575/// Parsing of declarative or executable OpenMP directives.
2576///
2577/// threadprivate-directive:
2578/// annot_pragma_openmp 'threadprivate' simple-variable-list
2579/// annot_pragma_openmp_end
2580///
2581/// allocate-directive:
2582/// annot_pragma_openmp 'allocate' simple-variable-list
2583/// annot_pragma_openmp_end
2584///
2585/// declare-reduction-directive:
2586/// annot_pragma_openmp 'declare' 'reduction' '(' <reduction_id> ':'
2587/// <type> {',' <type>} ':' <expression> ')' ['initializer' '('
2588/// ('omp_priv' '=' <expression>|<function_call>) ')']
2589/// annot_pragma_openmp_end
2590///
2591/// declare-mapper-directive:
2592/// annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifer> ':']
2593/// <type> <var> ')' [<clause>[[,] <clause>] ... ]
2594/// annot_pragma_openmp_end
2595///
2596/// executable-directive:
2597/// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |
2598/// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] |
2599/// 'parallel for' | 'parallel sections' | 'parallel master' | 'task' |
2600/// 'taskyield' | 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'error'
2601/// | 'atomic' | 'for simd' | 'parallel for simd' | 'target' | 'target
2602/// data' | 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' |
2603/// 'master taskloop' | 'master taskloop simd' | 'parallel master
2604/// taskloop' | 'parallel master taskloop simd' | 'distribute' | 'target
2605/// enter data' | 'target exit data' | 'target parallel' | 'target
2606/// parallel for' | 'target update' | 'distribute parallel for' |
2607/// 'distribute paralle for simd' | 'distribute simd' | 'target parallel
2608/// for simd' | 'target simd' | 'teams distribute' | 'teams distribute
2609/// simd' | 'teams distribute parallel for simd' | 'teams distribute
2610/// parallel for' | 'target teams' | 'target teams distribute' | 'target
2611/// teams distribute parallel for' | 'target teams distribute parallel
2612/// for simd' | 'target teams distribute simd' | 'masked' |
2613/// 'parallel masked' {clause} annot_pragma_openmp_end
2614///
2615StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(2616ParsedStmtContext StmtCtx, bool ReadDirectiveWithinMetadirective) {2617if (!ReadDirectiveWithinMetadirective)2618assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) &&2619"Not an OpenMP directive!");2620ParsingOpenMPDirectiveRAII DirScope(*this);2621ParenBraceBracketBalancer BalancerRAIIObj(*this);2622SourceLocation Loc = ReadDirectiveWithinMetadirective2623? Tok.getLocation()2624: ConsumeAnnotationToken();2625OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this);2626if (ReadDirectiveWithinMetadirective && DKind == OMPD_unknown) {2627Diag(Tok, diag::err_omp_unknown_directive);2628return StmtError();2629}2630
2631StmtResult Directive = StmtError();2632
2633bool IsExecutable = [&]() {2634if (DKind == OMPD_error) // OMPD_error is handled as executable2635return true;2636auto Res = getDirectiveCategory(DKind);2637return Res == Category::Executable || Res == Category::Subsidiary;2638}();2639
2640if (IsExecutable) {2641Directive = ParseOpenMPExecutableDirective(2642StmtCtx, DKind, Loc, ReadDirectiveWithinMetadirective);2643assert(!Directive.isUnset() && "Executable directive remained unprocessed");2644return Directive;2645}2646
2647switch (DKind) {2648case OMPD_nothing:2649ConsumeToken();2650// If we are parsing the directive within a metadirective, the directive2651// ends with a ')'.2652if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren))2653while (Tok.isNot(tok::annot_pragma_openmp_end))2654ConsumeAnyToken();2655else2656skipUntilPragmaOpenMPEnd(DKind);2657if (Tok.is(tok::annot_pragma_openmp_end))2658ConsumeAnnotationToken();2659// return an empty statement2660return StmtEmpty();2661case OMPD_metadirective: {2662ConsumeToken();2663SmallVector<VariantMatchInfo, 4> VMIs;2664
2665// First iteration of parsing all clauses of metadirective.2666// This iteration only parses and collects all context selector ignoring the2667// associated directives.2668TentativeParsingAction TPA(*this);2669ASTContext &ASTContext = Actions.getASTContext();2670
2671BalancedDelimiterTracker T(*this, tok::l_paren,2672tok::annot_pragma_openmp_end);2673while (Tok.isNot(tok::annot_pragma_openmp_end)) {2674OpenMPClauseKind CKind = Tok.isAnnotation()2675? OMPC_unknown2676: getOpenMPClauseKind(PP.getSpelling(Tok));2677SourceLocation Loc = ConsumeToken();2678
2679// Parse '('.2680if (T.expectAndConsume(diag::err_expected_lparen_after,2681getOpenMPClauseName(CKind).data()))2682return Directive;2683
2684OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo();2685if (CKind == OMPC_when) {2686// parse and get OMPTraitInfo to pass to the When clause2687parseOMPContextSelectors(Loc, TI);2688if (TI.Sets.size() == 0) {2689Diag(Tok, diag::err_omp_expected_context_selector) << "when clause";2690TPA.Commit();2691return Directive;2692}2693
2694// Parse ':'2695if (Tok.is(tok::colon))2696ConsumeAnyToken();2697else {2698Diag(Tok, diag::err_omp_expected_colon) << "when clause";2699TPA.Commit();2700return Directive;2701}2702}2703// Skip Directive for now. We will parse directive in the second iteration2704int paren = 0;2705while (Tok.isNot(tok::r_paren) || paren != 0) {2706if (Tok.is(tok::l_paren))2707paren++;2708if (Tok.is(tok::r_paren))2709paren--;2710if (Tok.is(tok::annot_pragma_openmp_end)) {2711Diag(Tok, diag::err_omp_expected_punc)2712<< getOpenMPClauseName(CKind) << 0;2713TPA.Commit();2714return Directive;2715}2716ConsumeAnyToken();2717}2718// Parse ')'2719if (Tok.is(tok::r_paren))2720T.consumeClose();2721
2722VariantMatchInfo VMI;2723TI.getAsVariantMatchInfo(ASTContext, VMI);2724
2725VMIs.push_back(VMI);2726}2727
2728TPA.Revert();2729// End of the first iteration. Parser is reset to the start of metadirective2730
2731std::function<void(StringRef)> DiagUnknownTrait =2732[this, Loc](StringRef ISATrait) {2733// TODO Track the selector locations in a way that is accessible here2734// to improve the diagnostic location.2735Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) << ISATrait;2736};2737TargetOMPContext OMPCtx(ASTContext, std::move(DiagUnknownTrait),2738/* CurrentFunctionDecl */ nullptr,2739ArrayRef<llvm::omp::TraitProperty>());2740
2741// A single match is returned for OpenMP 5.02742int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx);2743
2744int Idx = 0;2745// In OpenMP 5.0 metadirective is either replaced by another directive or2746// ignored.2747// TODO: In OpenMP 5.1 generate multiple directives based upon the matches2748// found by getBestWhenMatchForContext.2749while (Tok.isNot(tok::annot_pragma_openmp_end)) {2750// OpenMP 5.0 implementation - Skip to the best index found.2751if (Idx++ != BestIdx) {2752ConsumeToken(); // Consume clause name2753T.consumeOpen(); // Consume '('2754int paren = 0;2755// Skip everything inside the clause2756while (Tok.isNot(tok::r_paren) || paren != 0) {2757if (Tok.is(tok::l_paren))2758paren++;2759if (Tok.is(tok::r_paren))2760paren--;2761ConsumeAnyToken();2762}2763// Parse ')'2764if (Tok.is(tok::r_paren))2765T.consumeClose();2766continue;2767}2768
2769OpenMPClauseKind CKind = Tok.isAnnotation()2770? OMPC_unknown2771: getOpenMPClauseKind(PP.getSpelling(Tok));2772SourceLocation Loc = ConsumeToken();2773
2774// Parse '('.2775T.consumeOpen();2776
2777// Skip ContextSelectors for when clause2778if (CKind == OMPC_when) {2779OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo();2780// parse and skip the ContextSelectors2781parseOMPContextSelectors(Loc, TI);2782
2783// Parse ':'2784ConsumeAnyToken();2785}2786
2787// If no directive is passed, skip in OpenMP 5.0.2788// TODO: Generate nothing directive from OpenMP 5.1.2789if (Tok.is(tok::r_paren)) {2790SkipUntil(tok::annot_pragma_openmp_end);2791break;2792}2793
2794// Parse Directive2795Directive = ParseOpenMPDeclarativeOrExecutableDirective(2796StmtCtx,2797/*ReadDirectiveWithinMetadirective=*/true);2798break;2799}2800break;2801}2802case OMPD_threadprivate: {2803// FIXME: Should this be permitted in C++?2804if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==2805ParsedStmtContext()) {2806Diag(Tok, diag::err_omp_immediate_directive)2807<< getOpenMPDirectiveName(DKind) << 0;2808}2809ConsumeToken();2810DeclDirectiveListParserHelper Helper(this, DKind);2811if (!ParseOpenMPSimpleVarList(DKind, Helper,2812/*AllowScopeSpecifier=*/false)) {2813skipUntilPragmaOpenMPEnd(DKind);2814DeclGroupPtrTy Res = Actions.OpenMP().ActOnOpenMPThreadprivateDirective(2815Loc, Helper.getIdentifiers());2816Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());2817}2818SkipUntil(tok::annot_pragma_openmp_end);2819break;2820}2821case OMPD_allocate: {2822// FIXME: Should this be permitted in C++?2823if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==2824ParsedStmtContext()) {2825Diag(Tok, diag::err_omp_immediate_directive)2826<< getOpenMPDirectiveName(DKind) << 0;2827}2828ConsumeToken();2829DeclDirectiveListParserHelper Helper(this, DKind);2830if (!ParseOpenMPSimpleVarList(DKind, Helper,2831/*AllowScopeSpecifier=*/false)) {2832SmallVector<OMPClause *, 1> Clauses;2833if (Tok.isNot(tok::annot_pragma_openmp_end)) {2834llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1);2835while (Tok.isNot(tok::annot_pragma_openmp_end)) {2836OpenMPClauseKind CKind =2837Tok.isAnnotation() ? OMPC_unknown2838: getOpenMPClauseKind(PP.getSpelling(Tok));2839Actions.OpenMP().StartOpenMPClause(CKind);2840OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind,2841!SeenClauses[unsigned(CKind)]);2842SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,2843StopBeforeMatch);2844SeenClauses[unsigned(CKind)] = true;2845if (Clause != nullptr)2846Clauses.push_back(Clause);2847if (Tok.is(tok::annot_pragma_openmp_end)) {2848Actions.OpenMP().EndOpenMPClause();2849break;2850}2851// Skip ',' if any.2852if (Tok.is(tok::comma))2853ConsumeToken();2854Actions.OpenMP().EndOpenMPClause();2855}2856skipUntilPragmaOpenMPEnd(DKind);2857}2858DeclGroupPtrTy Res = Actions.OpenMP().ActOnOpenMPAllocateDirective(2859Loc, Helper.getIdentifiers(), Clauses);2860Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());2861}2862SkipUntil(tok::annot_pragma_openmp_end);2863break;2864}2865case OMPD_declare_reduction:2866ConsumeToken();2867if (DeclGroupPtrTy Res =2868ParseOpenMPDeclareReductionDirective(/*AS=*/AS_none)) {2869skipUntilPragmaOpenMPEnd(OMPD_declare_reduction);2870ConsumeAnyToken();2871Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());2872} else {2873SkipUntil(tok::annot_pragma_openmp_end);2874}2875break;2876case OMPD_declare_mapper: {2877ConsumeToken();2878if (DeclGroupPtrTy Res =2879ParseOpenMPDeclareMapperDirective(/*AS=*/AS_none)) {2880// Skip the last annot_pragma_openmp_end.2881ConsumeAnnotationToken();2882Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());2883} else {2884SkipUntil(tok::annot_pragma_openmp_end);2885}2886break;2887}2888case OMPD_declare_target: {2889SourceLocation DTLoc = ConsumeAnyToken();2890bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end);2891SemaOpenMP::DeclareTargetContextInfo DTCI(DKind, DTLoc);2892if (HasClauses)2893ParseOMPDeclareTargetClauses(DTCI);2894bool HasImplicitMappings =2895!HasClauses || (DTCI.ExplicitlyMapped.empty() && DTCI.Indirect);2896
2897if (HasImplicitMappings) {2898Diag(Tok, diag::err_omp_unexpected_directive)2899<< 1 << getOpenMPDirectiveName(DKind);2900SkipUntil(tok::annot_pragma_openmp_end);2901break;2902}2903
2904// Skip the last annot_pragma_openmp_end.2905ConsumeAnyToken();2906
2907Actions.OpenMP().ActOnFinishedOpenMPDeclareTargetContext(DTCI);2908break;2909}2910case OMPD_declare_simd:2911case OMPD_begin_declare_target:2912case OMPD_end_declare_target:2913case OMPD_requires:2914case OMPD_begin_declare_variant:2915case OMPD_end_declare_variant:2916case OMPD_declare_variant:2917Diag(Tok, diag::err_omp_unexpected_directive)2918<< 1 << getOpenMPDirectiveName(DKind);2919SkipUntil(tok::annot_pragma_openmp_end);2920break;2921case OMPD_unknown:2922default:2923Diag(Tok, diag::err_omp_unknown_directive);2924SkipUntil(tok::annot_pragma_openmp_end);2925break;2926}2927return Directive;2928}
2929
2930// Parses simple list:
2931// simple-variable-list:
2932// '(' id-expression {, id-expression} ')'
2933//
2934bool Parser::ParseOpenMPSimpleVarList(2935OpenMPDirectiveKind Kind,2936const llvm::function_ref<void(CXXScopeSpec &, DeclarationNameInfo)>2937&Callback,2938bool AllowScopeSpecifier) {2939// Parse '('.2940BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);2941if (T.expectAndConsume(diag::err_expected_lparen_after,2942getOpenMPDirectiveName(Kind).data()))2943return true;2944bool IsCorrect = true;2945bool NoIdentIsFound = true;2946
2947// Read tokens while ')' or annot_pragma_openmp_end is not found.2948while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {2949CXXScopeSpec SS;2950UnqualifiedId Name;2951// Read var name.2952Token PrevTok = Tok;2953NoIdentIsFound = false;2954
2955if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&2956ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,2957/*ObjectHasErrors=*/false, false)) {2958IsCorrect = false;2959SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,2960StopBeforeMatch);2961} else if (ParseUnqualifiedId(SS, /*ObjectType=*/nullptr,2962/*ObjectHadErrors=*/false, false, false,2963false, false, nullptr, Name)) {2964IsCorrect = false;2965SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,2966StopBeforeMatch);2967} else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&2968Tok.isNot(tok::annot_pragma_openmp_end)) {2969IsCorrect = false;2970SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,2971StopBeforeMatch);2972Diag(PrevTok.getLocation(), diag::err_expected)2973<< tok::identifier2974<< SourceRange(PrevTok.getLocation(), PrevTokLocation);2975} else {2976Callback(SS, Actions.GetNameFromUnqualifiedId(Name));2977}2978// Consume ','.2979if (Tok.is(tok::comma)) {2980ConsumeToken();2981}2982}2983
2984if (NoIdentIsFound) {2985Diag(Tok, diag::err_expected) << tok::identifier;2986IsCorrect = false;2987}2988
2989// Parse ')'.2990IsCorrect = !T.consumeClose() && IsCorrect;2991
2992return !IsCorrect;2993}
2994
2995OMPClause *Parser::ParseOpenMPSizesClause() {2996SourceLocation ClauseNameLoc, OpenLoc, CloseLoc;2997SmallVector<Expr *, 4> ValExprs;2998if (ParseOpenMPExprListClause(OMPC_sizes, ClauseNameLoc, OpenLoc, CloseLoc,2999ValExprs))3000return nullptr;3001
3002return Actions.OpenMP().ActOnOpenMPSizesClause(ValExprs, ClauseNameLoc,3003OpenLoc, CloseLoc);3004}
3005
3006OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) {3007SourceLocation Loc = Tok.getLocation();3008ConsumeAnyToken();3009
3010// Parse '('.3011BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);3012if (T.expectAndConsume(diag::err_expected_lparen_after, "uses_allocator"))3013return nullptr;3014SmallVector<SemaOpenMP::UsesAllocatorsData, 4> Data;3015do {3016CXXScopeSpec SS;3017Token Replacement;3018ExprResult Allocator =3019getLangOpts().CPlusPlus3020? ParseCXXIdExpression()3021: tryParseCXXIdExpression(SS, /*isAddressOfOperand=*/false,3022Replacement);3023if (Allocator.isInvalid()) {3024SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,3025StopBeforeMatch);3026break;3027}3028SemaOpenMP::UsesAllocatorsData &D = Data.emplace_back();3029D.Allocator = Allocator.get();3030if (Tok.is(tok::l_paren)) {3031BalancedDelimiterTracker T(*this, tok::l_paren,3032tok::annot_pragma_openmp_end);3033T.consumeOpen();3034ExprResult AllocatorTraits =3035getLangOpts().CPlusPlus ? ParseCXXIdExpression() : ParseExpression();3036T.consumeClose();3037if (AllocatorTraits.isInvalid()) {3038SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,3039StopBeforeMatch);3040break;3041}3042D.AllocatorTraits = AllocatorTraits.get();3043D.LParenLoc = T.getOpenLocation();3044D.RParenLoc = T.getCloseLocation();3045}3046if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren))3047Diag(Tok, diag::err_omp_expected_punc) << "uses_allocators" << 0;3048// Parse ','3049if (Tok.is(tok::comma))3050ConsumeAnyToken();3051} while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end));3052T.consumeClose();3053return Actions.OpenMP().ActOnOpenMPUsesAllocatorClause(3054Loc, T.getOpenLocation(), T.getCloseLocation(), Data);3055}
3056
3057/// Parsing of OpenMP clauses.
3058///
3059/// clause:
3060/// if-clause | final-clause | num_threads-clause | safelen-clause |
3061/// default-clause | private-clause | firstprivate-clause | shared-clause
3062/// | linear-clause | aligned-clause | collapse-clause | bind-clause |
3063/// lastprivate-clause | reduction-clause | proc_bind-clause |
3064/// schedule-clause | copyin-clause | copyprivate-clause | untied-clause |
3065/// mergeable-clause | flush-clause | read-clause | write-clause |
3066/// update-clause | capture-clause | seq_cst-clause | device-clause |
3067/// simdlen-clause | threads-clause | simd-clause | num_teams-clause |
3068/// thread_limit-clause | priority-clause | grainsize-clause |
3069/// nogroup-clause | num_tasks-clause | hint-clause | to-clause |
3070/// from-clause | is_device_ptr-clause | task_reduction-clause |
3071/// in_reduction-clause | allocator-clause | allocate-clause |
3072/// acq_rel-clause | acquire-clause | release-clause | relaxed-clause |
3073/// depobj-clause | destroy-clause | detach-clause | inclusive-clause |
3074/// exclusive-clause | uses_allocators-clause | use_device_addr-clause |
3075/// has_device_addr
3076///
3077OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,3078OpenMPClauseKind CKind, bool FirstClause) {3079OMPClauseKind = CKind;3080OMPClause *Clause = nullptr;3081bool ErrorFound = false;3082bool WrongDirective = false;3083// Check if clause is allowed for the given directive.3084if (CKind != OMPC_unknown &&3085!isAllowedClauseForDirective(DKind, CKind, getLangOpts().OpenMP)) {3086Diag(Tok, diag::err_omp_unexpected_clause)3087<< getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);3088ErrorFound = true;3089WrongDirective = true;3090}3091
3092switch (CKind) {3093case OMPC_final:3094case OMPC_num_threads:3095case OMPC_safelen:3096case OMPC_simdlen:3097case OMPC_collapse:3098case OMPC_ordered:3099case OMPC_num_teams:3100case OMPC_thread_limit:3101case OMPC_priority:3102case OMPC_grainsize:3103case OMPC_num_tasks:3104case OMPC_hint:3105case OMPC_allocator:3106case OMPC_depobj:3107case OMPC_detach:3108case OMPC_novariants:3109case OMPC_nocontext:3110case OMPC_filter:3111case OMPC_partial:3112case OMPC_align:3113case OMPC_message:3114case OMPC_ompx_dyn_cgroup_mem:3115// OpenMP [2.5, Restrictions]3116// At most one num_threads clause can appear on the directive.3117// OpenMP [2.8.1, simd construct, Restrictions]3118// Only one safelen clause can appear on a simd directive.3119// Only one simdlen clause can appear on a simd directive.3120// Only one collapse clause can appear on a simd directive.3121// OpenMP [2.11.1, task Construct, Restrictions]3122// At most one if clause can appear on the directive.3123// At most one final clause can appear on the directive.3124// OpenMP [teams Construct, Restrictions]3125// At most one num_teams clause can appear on the directive.3126// At most one thread_limit clause can appear on the directive.3127// OpenMP [2.9.1, task Construct, Restrictions]3128// At most one priority clause can appear on the directive.3129// OpenMP [2.9.2, taskloop Construct, Restrictions]3130// At most one grainsize clause can appear on the directive.3131// OpenMP [2.9.2, taskloop Construct, Restrictions]3132// At most one num_tasks clause can appear on the directive.3133// OpenMP [2.11.3, allocate Directive, Restrictions]3134// At most one allocator clause can appear on the directive.3135// OpenMP 5.0, 2.10.1 task Construct, Restrictions.3136// At most one detach clause can appear on the directive.3137// OpenMP 5.1, 2.3.6 dispatch Construct, Restrictions.3138// At most one novariants clause can appear on a dispatch directive.3139// At most one nocontext clause can appear on a dispatch directive.3140// OpenMP [5.1, error directive, Restrictions]3141// At most one message clause can appear on the directive3142if (!FirstClause) {3143Diag(Tok, diag::err_omp_more_one_clause)3144<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3145ErrorFound = true;3146}3147
3148if ((CKind == OMPC_ordered || CKind == OMPC_partial) &&3149PP.LookAhead(/*N=*/0).isNot(tok::l_paren))3150Clause = ParseOpenMPClause(CKind, WrongDirective);3151else if (CKind == OMPC_grainsize || CKind == OMPC_num_tasks)3152Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective);3153else3154Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective);3155break;3156case OMPC_fail:3157case OMPC_default:3158case OMPC_proc_bind:3159case OMPC_atomic_default_mem_order:3160case OMPC_at:3161case OMPC_severity:3162case OMPC_bind:3163// OpenMP [2.14.3.1, Restrictions]3164// Only a single default clause may be specified on a parallel, task or3165// teams directive.3166// OpenMP [2.5, parallel Construct, Restrictions]3167// At most one proc_bind clause can appear on the directive.3168// OpenMP [5.0, Requires directive, Restrictions]3169// At most one atomic_default_mem_order clause can appear3170// on the directive3171// OpenMP [5.1, error directive, Restrictions]3172// At most one at clause can appear on the directive3173// At most one severity clause can appear on the directive3174// OpenMP 5.1, 2.11.7 loop Construct, Restrictions.3175// At most one bind clause can appear on a loop directive.3176if (!FirstClause) {3177Diag(Tok, diag::err_omp_more_one_clause)3178<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3179ErrorFound = true;3180}3181
3182Clause = ParseOpenMPSimpleClause(CKind, WrongDirective);3183break;3184case OMPC_device:3185case OMPC_schedule:3186case OMPC_dist_schedule:3187case OMPC_defaultmap:3188case OMPC_order:3189// OpenMP [2.7.1, Restrictions, p. 3]3190// Only one schedule clause can appear on a loop directive.3191// OpenMP 4.5 [2.10.4, Restrictions, p. 106]3192// At most one defaultmap clause can appear on the directive.3193// OpenMP 5.0 [2.12.5, target construct, Restrictions]3194// At most one device clause can appear on the directive.3195// OpenMP 5.1 [2.11.3, order clause, Restrictions]3196// At most one order clause may appear on a construct.3197if ((getLangOpts().OpenMP < 50 || CKind != OMPC_defaultmap) &&3198(CKind != OMPC_order || getLangOpts().OpenMP >= 51) && !FirstClause) {3199Diag(Tok, diag::err_omp_more_one_clause)3200<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3201ErrorFound = true;3202}3203[[fallthrough]];3204case OMPC_if:3205Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective);3206break;3207case OMPC_nowait:3208case OMPC_untied:3209case OMPC_mergeable:3210case OMPC_read:3211case OMPC_write:3212case OMPC_capture:3213case OMPC_compare:3214case OMPC_seq_cst:3215case OMPC_acq_rel:3216case OMPC_acquire:3217case OMPC_release:3218case OMPC_relaxed:3219case OMPC_weak:3220case OMPC_threads:3221case OMPC_simd:3222case OMPC_nogroup:3223case OMPC_unified_address:3224case OMPC_unified_shared_memory:3225case OMPC_reverse_offload:3226case OMPC_dynamic_allocators:3227case OMPC_full:3228// OpenMP [2.7.1, Restrictions, p. 9]3229// Only one ordered clause can appear on a loop directive.3230// OpenMP [2.7.1, Restrictions, C/C++, p. 4]3231// Only one nowait clause can appear on a for directive.3232// OpenMP [5.0, Requires directive, Restrictions]3233// Each of the requires clauses can appear at most once on the directive.3234if (!FirstClause) {3235Diag(Tok, diag::err_omp_more_one_clause)3236<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3237ErrorFound = true;3238}3239
3240Clause = ParseOpenMPClause(CKind, WrongDirective);3241break;3242case OMPC_update:3243if (!FirstClause) {3244Diag(Tok, diag::err_omp_more_one_clause)3245<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3246ErrorFound = true;3247}3248
3249Clause = (DKind == OMPD_depobj)3250? ParseOpenMPSimpleClause(CKind, WrongDirective)3251: ParseOpenMPClause(CKind, WrongDirective);3252break;3253case OMPC_private:3254case OMPC_firstprivate:3255case OMPC_lastprivate:3256case OMPC_shared:3257case OMPC_reduction:3258case OMPC_task_reduction:3259case OMPC_in_reduction:3260case OMPC_linear:3261case OMPC_aligned:3262case OMPC_copyin:3263case OMPC_copyprivate:3264case OMPC_flush:3265case OMPC_depend:3266case OMPC_map:3267case OMPC_to:3268case OMPC_from:3269case OMPC_use_device_ptr:3270case OMPC_use_device_addr:3271case OMPC_is_device_ptr:3272case OMPC_has_device_addr:3273case OMPC_allocate:3274case OMPC_nontemporal:3275case OMPC_inclusive:3276case OMPC_exclusive:3277case OMPC_affinity:3278case OMPC_doacross:3279case OMPC_enter:3280if (getLangOpts().OpenMP >= 52 && DKind == OMPD_ordered &&3281CKind == OMPC_depend)3282Diag(Tok, diag::warn_omp_depend_in_ordered_deprecated);3283Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective);3284break;3285case OMPC_sizes:3286if (!FirstClause) {3287Diag(Tok, diag::err_omp_more_one_clause)3288<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3289ErrorFound = true;3290}3291
3292Clause = ParseOpenMPSizesClause();3293break;3294case OMPC_uses_allocators:3295Clause = ParseOpenMPUsesAllocatorClause(DKind);3296break;3297case OMPC_destroy:3298if (DKind != OMPD_interop) {3299if (!FirstClause) {3300Diag(Tok, diag::err_omp_more_one_clause)3301<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;3302ErrorFound = true;3303}3304Clause = ParseOpenMPClause(CKind, WrongDirective);3305break;3306}3307[[fallthrough]];3308case OMPC_init:3309case OMPC_use:3310Clause = ParseOpenMPInteropClause(CKind, WrongDirective);3311break;3312case OMPC_device_type:3313case OMPC_unknown:3314skipUntilPragmaOpenMPEnd(DKind);3315break;3316case OMPC_threadprivate:3317case OMPC_uniform:3318case OMPC_match:3319if (!WrongDirective)3320Diag(Tok, diag::err_omp_unexpected_clause)3321<< getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);3322SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);3323break;3324case OMPC_ompx_attribute:3325Clause = ParseOpenMPOMPXAttributesClause(WrongDirective);3326break;3327case OMPC_ompx_bare:3328if (WrongDirective)3329Diag(Tok, diag::note_ompx_bare_clause)3330<< getOpenMPClauseName(CKind) << "target teams";3331if (!ErrorFound && !getLangOpts().OpenMPExtensions) {3332Diag(Tok, diag::err_omp_unexpected_clause_extension_only)3333<< getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);3334ErrorFound = true;3335}3336Clause = ParseOpenMPClause(CKind, WrongDirective);3337break;3338default:3339break;3340}3341return ErrorFound ? nullptr : Clause;3342}
3343
3344/// Parses simple expression in parens for single-expression clauses of OpenMP
3345/// constructs.
3346/// \param RLoc Returned location of right paren.
3347ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName,3348SourceLocation &RLoc,3349bool IsAddressOfOperand) {3350BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);3351if (T.expectAndConsume(diag::err_expected_lparen_after, ClauseName.data()))3352return ExprError();3353
3354SourceLocation ELoc = Tok.getLocation();3355ExprResult LHS(3356ParseCastExpression(AnyCastExpr, IsAddressOfOperand, NotTypeCast));3357ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));3358Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false);3359
3360// Parse ')'.3361RLoc = Tok.getLocation();3362if (!T.consumeClose())3363RLoc = T.getCloseLocation();3364
3365return Val;3366}
3367
3368/// Parsing of OpenMP clauses with single expressions like 'final',
3369/// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams',
3370/// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks', 'hint' or
3371/// 'detach'.
3372///
3373/// final-clause:
3374/// 'final' '(' expression ')'
3375///
3376/// num_threads-clause:
3377/// 'num_threads' '(' expression ')'
3378///
3379/// safelen-clause:
3380/// 'safelen' '(' expression ')'
3381///
3382/// simdlen-clause:
3383/// 'simdlen' '(' expression ')'
3384///
3385/// collapse-clause:
3386/// 'collapse' '(' expression ')'
3387///
3388/// priority-clause:
3389/// 'priority' '(' expression ')'
3390///
3391/// grainsize-clause:
3392/// 'grainsize' '(' expression ')'
3393///
3394/// num_tasks-clause:
3395/// 'num_tasks' '(' expression ')'
3396///
3397/// hint-clause:
3398/// 'hint' '(' expression ')'
3399///
3400/// allocator-clause:
3401/// 'allocator' '(' expression ')'
3402///
3403/// detach-clause:
3404/// 'detach' '(' event-handler-expression ')'
3405///
3406/// align-clause
3407/// 'align' '(' positive-integer-constant ')'
3408///
3409OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind,3410bool ParseOnly) {3411SourceLocation Loc = ConsumeToken();3412SourceLocation LLoc = Tok.getLocation();3413SourceLocation RLoc;3414
3415ExprResult Val = ParseOpenMPParensExpr(getOpenMPClauseName(Kind), RLoc);3416
3417if (Val.isInvalid())3418return nullptr;3419
3420if (ParseOnly)3421return nullptr;3422return Actions.OpenMP().ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc,3423LLoc, RLoc);3424}
3425
3426/// Parse indirect clause for '#pragma omp declare target' directive.
3427/// 'indirect' '[' '(' invoked-by-fptr ')' ']'
3428/// where invoked-by-fptr is a constant boolean expression that evaluates to
3429/// true or false at compile time.
3430bool Parser::ParseOpenMPIndirectClause(3431SemaOpenMP::DeclareTargetContextInfo &DTCI, bool ParseOnly) {3432SourceLocation Loc = ConsumeToken();3433SourceLocation RLoc;3434
3435if (Tok.isNot(tok::l_paren)) {3436if (ParseOnly)3437return false;3438DTCI.Indirect = nullptr;3439return true;3440}3441
3442ExprResult Val =3443ParseOpenMPParensExpr(getOpenMPClauseName(OMPC_indirect), RLoc);3444if (Val.isInvalid())3445return false;3446
3447if (ParseOnly)3448return false;3449
3450if (!Val.get()->isValueDependent() && !Val.get()->isTypeDependent() &&3451!Val.get()->isInstantiationDependent() &&3452!Val.get()->containsUnexpandedParameterPack()) {3453ExprResult Ret = Actions.CheckBooleanCondition(Loc, Val.get());3454if (Ret.isInvalid())3455return false;3456llvm::APSInt Result;3457Ret = Actions.VerifyIntegerConstantExpression(Val.get(), &Result,3458Sema::AllowFold);3459if (Ret.isInvalid())3460return false;3461DTCI.Indirect = Val.get();3462return true;3463}3464return false;3465}
3466
3467/// Parses a comma-separated list of interop-types and a prefer_type list.
3468///
3469bool Parser::ParseOMPInteropInfo(OMPInteropInfo &InteropInfo,3470OpenMPClauseKind Kind) {3471const Token &Tok = getCurToken();3472bool HasError = false;3473bool IsTarget = false;3474bool IsTargetSync = false;3475
3476while (Tok.is(tok::identifier)) {3477// Currently prefer_type is only allowed with 'init' and it must be first.3478bool PreferTypeAllowed = Kind == OMPC_init &&3479InteropInfo.PreferTypes.empty() && !IsTarget &&3480!IsTargetSync;3481if (Tok.getIdentifierInfo()->isStr("target")) {3482// OpenMP 5.1 [2.15.1, interop Construct, Restrictions]3483// Each interop-type may be specified on an action-clause at most3484// once.3485if (IsTarget)3486Diag(Tok, diag::warn_omp_more_one_interop_type) << "target";3487IsTarget = true;3488ConsumeToken();3489} else if (Tok.getIdentifierInfo()->isStr("targetsync")) {3490if (IsTargetSync)3491Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync";3492IsTargetSync = true;3493ConsumeToken();3494} else if (Tok.getIdentifierInfo()->isStr("prefer_type") &&3495PreferTypeAllowed) {3496ConsumeToken();3497BalancedDelimiterTracker PT(*this, tok::l_paren,3498tok::annot_pragma_openmp_end);3499if (PT.expectAndConsume(diag::err_expected_lparen_after, "prefer_type"))3500HasError = true;3501
3502while (Tok.isNot(tok::r_paren)) {3503SourceLocation Loc = Tok.getLocation();3504ExprResult LHS = ParseCastExpression(AnyCastExpr);3505ExprResult PTExpr = Actions.CorrectDelayedTyposInExpr(3506ParseRHSOfBinaryExpression(LHS, prec::Conditional));3507PTExpr = Actions.ActOnFinishFullExpr(PTExpr.get(), Loc,3508/*DiscardedValue=*/false);3509if (PTExpr.isUsable()) {3510InteropInfo.PreferTypes.push_back(PTExpr.get());3511} else {3512HasError = true;3513SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,3514StopBeforeMatch);3515}3516
3517if (Tok.is(tok::comma))3518ConsumeToken();3519}3520PT.consumeClose();3521} else {3522HasError = true;3523Diag(Tok, diag::err_omp_expected_interop_type);3524ConsumeToken();3525}3526if (!Tok.is(tok::comma))3527break;3528ConsumeToken();3529}3530
3531if (!HasError && !IsTarget && !IsTargetSync) {3532Diag(Tok, diag::err_omp_expected_interop_type);3533HasError = true;3534}3535
3536if (Kind == OMPC_init) {3537if (Tok.isNot(tok::colon) && (IsTarget || IsTargetSync))3538Diag(Tok, diag::warn_pragma_expected_colon) << "interop types";3539if (Tok.is(tok::colon))3540ConsumeToken();3541}3542
3543// As of OpenMP 5.1,there are two interop-types, "target" and3544// "targetsync". Either or both are allowed for a single interop.3545InteropInfo.IsTarget = IsTarget;3546InteropInfo.IsTargetSync = IsTargetSync;3547
3548return HasError;3549}
3550
3551/// Parsing of OpenMP clauses that use an interop-var.
3552///
3553/// init-clause:
3554/// init([interop-modifier, ]interop-type[[, interop-type] ... ]:interop-var)
3555///
3556/// destroy-clause:
3557/// destroy(interop-var)
3558///
3559/// use-clause:
3560/// use(interop-var)
3561///
3562/// interop-modifier:
3563/// prefer_type(preference-list)
3564///
3565/// preference-list:
3566/// foreign-runtime-id [, foreign-runtime-id]...
3567///
3568/// foreign-runtime-id:
3569/// <string-literal> | <constant-integral-expression>
3570///
3571/// interop-type:
3572/// target | targetsync
3573///
3574OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind,3575bool ParseOnly) {3576SourceLocation Loc = ConsumeToken();3577// Parse '('.3578BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);3579if (T.expectAndConsume(diag::err_expected_lparen_after,3580getOpenMPClauseName(Kind).data()))3581return nullptr;3582
3583bool InteropError = false;3584OMPInteropInfo InteropInfo;3585if (Kind == OMPC_init)3586InteropError = ParseOMPInteropInfo(InteropInfo, OMPC_init);3587
3588// Parse the variable.3589SourceLocation VarLoc = Tok.getLocation();3590ExprResult InteropVarExpr =3591Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());3592if (!InteropVarExpr.isUsable()) {3593SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,3594StopBeforeMatch);3595}3596
3597// Parse ')'.3598SourceLocation RLoc = Tok.getLocation();3599if (!T.consumeClose())3600RLoc = T.getCloseLocation();3601
3602if (ParseOnly || !InteropVarExpr.isUsable() || InteropError)3603return nullptr;3604
3605if (Kind == OMPC_init)3606return Actions.OpenMP().ActOnOpenMPInitClause(3607InteropVarExpr.get(), InteropInfo, Loc, T.getOpenLocation(), VarLoc,3608RLoc);3609if (Kind == OMPC_use)3610return Actions.OpenMP().ActOnOpenMPUseClause(3611InteropVarExpr.get(), Loc, T.getOpenLocation(), VarLoc, RLoc);3612
3613if (Kind == OMPC_destroy)3614return Actions.OpenMP().ActOnOpenMPDestroyClause(3615InteropVarExpr.get(), Loc, T.getOpenLocation(), VarLoc, RLoc);3616
3617llvm_unreachable("Unexpected interop variable clause.");3618}
3619
3620OMPClause *Parser::ParseOpenMPOMPXAttributesClause(bool ParseOnly) {3621SourceLocation Loc = ConsumeToken();3622// Parse '('.3623BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);3624if (T.expectAndConsume(diag::err_expected_lparen_after,3625getOpenMPClauseName(OMPC_ompx_attribute).data()))3626return nullptr;3627
3628ParsedAttributes ParsedAttrs(AttrFactory);3629ParseAttributes(PAKM_GNU | PAKM_CXX11, ParsedAttrs);3630
3631// Parse ')'.3632if (T.consumeClose())3633return nullptr;3634
3635if (ParseOnly)3636return nullptr;3637
3638SmallVector<Attr *> Attrs;3639for (const ParsedAttr &PA : ParsedAttrs) {3640switch (PA.getKind()) {3641case ParsedAttr::AT_AMDGPUFlatWorkGroupSize:3642if (!PA.checkExactlyNumArgs(Actions, 2))3643continue;3644if (auto *A = Actions.AMDGPU().CreateAMDGPUFlatWorkGroupSizeAttr(3645PA, PA.getArgAsExpr(0), PA.getArgAsExpr(1)))3646Attrs.push_back(A);3647continue;3648case ParsedAttr::AT_AMDGPUWavesPerEU:3649if (!PA.checkAtLeastNumArgs(Actions, 1) ||3650!PA.checkAtMostNumArgs(Actions, 2))3651continue;3652if (auto *A = Actions.AMDGPU().CreateAMDGPUWavesPerEUAttr(3653PA, PA.getArgAsExpr(0),3654PA.getNumArgs() > 1 ? PA.getArgAsExpr(1) : nullptr))3655Attrs.push_back(A);3656continue;3657case ParsedAttr::AT_CUDALaunchBounds:3658if (!PA.checkAtLeastNumArgs(Actions, 1) ||3659!PA.checkAtMostNumArgs(Actions, 2))3660continue;3661if (auto *A = Actions.CreateLaunchBoundsAttr(3662PA, PA.getArgAsExpr(0),3663PA.getNumArgs() > 1 ? PA.getArgAsExpr(1) : nullptr,3664PA.getNumArgs() > 2 ? PA.getArgAsExpr(2) : nullptr))3665Attrs.push_back(A);3666continue;3667default:3668Diag(Loc, diag::warn_omp_invalid_attribute_for_ompx_attributes) << PA;3669continue;3670};3671}3672
3673return Actions.OpenMP().ActOnOpenMPXAttributeClause(3674Attrs, Loc, T.getOpenLocation(), T.getCloseLocation());3675}
3676
3677/// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
3678///
3679/// default-clause:
3680/// 'default' '(' 'none' | 'shared' | 'private' | 'firstprivate' ')'
3681///
3682/// proc_bind-clause:
3683/// 'proc_bind' '(' 'master' | 'close' | 'spread' ')'
3684///
3685/// bind-clause:
3686/// 'bind' '(' 'teams' | 'parallel' | 'thread' ')'
3687///
3688/// update-clause:
3689/// 'update' '(' 'in' | 'out' | 'inout' | 'mutexinoutset' |
3690/// 'inoutset' ')'
3691///
3692OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind,3693bool ParseOnly) {3694std::optional<SimpleClauseData> Val = parseOpenMPSimpleClause(*this, Kind);3695if (!Val || ParseOnly)3696return nullptr;3697if (getLangOpts().OpenMP < 51 && Kind == OMPC_default &&3698(static_cast<DefaultKind>(Val->Type) == OMP_DEFAULT_private ||3699static_cast<DefaultKind>(Val->Type) ==3700OMP_DEFAULT_firstprivate)) {3701Diag(Val->LOpen, diag::err_omp_invalid_dsa)3702<< getOpenMPClauseName(static_cast<DefaultKind>(Val->Type) ==3703OMP_DEFAULT_private
3704? OMPC_private3705: OMPC_firstprivate)3706<< getOpenMPClauseName(OMPC_default) << "5.1";3707return nullptr;3708}3709return Actions.OpenMP().ActOnOpenMPSimpleClause(3710Kind, Val->Type, Val->TypeLoc, Val->LOpen, Val->Loc, Val->RLoc);3711}
3712
3713/// Parsing of OpenMP clauses like 'ordered'.
3714///
3715/// ordered-clause:
3716/// 'ordered'
3717///
3718/// nowait-clause:
3719/// 'nowait'
3720///
3721/// untied-clause:
3722/// 'untied'
3723///
3724/// mergeable-clause:
3725/// 'mergeable'
3726///
3727/// read-clause:
3728/// 'read'
3729///
3730/// threads-clause:
3731/// 'threads'
3732///
3733/// simd-clause:
3734/// 'simd'
3735///
3736/// nogroup-clause:
3737/// 'nogroup'
3738///
3739OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind, bool ParseOnly) {3740SourceLocation Loc = Tok.getLocation();3741ConsumeAnyToken();3742
3743if (ParseOnly)3744return nullptr;3745return Actions.OpenMP().ActOnOpenMPClause(Kind, Loc, Tok.getLocation());3746}
3747
3748/// Parsing of OpenMP clauses with single expressions and some additional
3749/// argument like 'schedule' or 'dist_schedule'.
3750///
3751/// schedule-clause:
3752/// 'schedule' '(' [ modifier [ ',' modifier ] ':' ] kind [',' expression ]
3753/// ')'
3754///
3755/// if-clause:
3756/// 'if' '(' [ directive-name-modifier ':' ] expression ')'
3757///
3758/// defaultmap:
3759/// 'defaultmap' '(' modifier [ ':' kind ] ')'
3760///
3761/// device-clause:
3762/// 'device' '(' [ device-modifier ':' ] expression ')'
3763///
3764OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind,3765OpenMPClauseKind Kind,3766bool ParseOnly) {3767SourceLocation Loc = ConsumeToken();3768SourceLocation DelimLoc;3769// Parse '('.3770BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);3771if (T.expectAndConsume(diag::err_expected_lparen_after,3772getOpenMPClauseName(Kind).data()))3773return nullptr;3774
3775ExprResult Val;3776SmallVector<unsigned, 4> Arg;3777SmallVector<SourceLocation, 4> KLoc;3778if (Kind == OMPC_schedule) {3779enum { Modifier1, Modifier2, ScheduleKind, NumberOfElements };3780Arg.resize(NumberOfElements);3781KLoc.resize(NumberOfElements);3782Arg[Modifier1] = OMPC_SCHEDULE_MODIFIER_unknown;3783Arg[Modifier2] = OMPC_SCHEDULE_MODIFIER_unknown;3784Arg[ScheduleKind] = OMPC_SCHEDULE_unknown;3785unsigned KindModifier = getOpenMPSimpleClauseType(3786Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());3787if (KindModifier > OMPC_SCHEDULE_unknown) {3788// Parse 'modifier'3789Arg[Modifier1] = KindModifier;3790KLoc[Modifier1] = Tok.getLocation();3791if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3792Tok.isNot(tok::annot_pragma_openmp_end))3793ConsumeAnyToken();3794if (Tok.is(tok::comma)) {3795// Parse ',' 'modifier'3796ConsumeAnyToken();3797KindModifier = getOpenMPSimpleClauseType(3798Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());3799Arg[Modifier2] = KindModifier > OMPC_SCHEDULE_unknown3800? KindModifier3801: (unsigned)OMPC_SCHEDULE_unknown;3802KLoc[Modifier2] = Tok.getLocation();3803if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3804Tok.isNot(tok::annot_pragma_openmp_end))3805ConsumeAnyToken();3806}3807// Parse ':'3808if (Tok.is(tok::colon))3809ConsumeAnyToken();3810else3811Diag(Tok, diag::warn_pragma_expected_colon) << "schedule modifier";3812KindModifier = getOpenMPSimpleClauseType(3813Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());3814}3815Arg[ScheduleKind] = KindModifier;3816KLoc[ScheduleKind] = Tok.getLocation();3817if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3818Tok.isNot(tok::annot_pragma_openmp_end))3819ConsumeAnyToken();3820if ((Arg[ScheduleKind] == OMPC_SCHEDULE_static ||3821Arg[ScheduleKind] == OMPC_SCHEDULE_dynamic ||3822Arg[ScheduleKind] == OMPC_SCHEDULE_guided) &&3823Tok.is(tok::comma))3824DelimLoc = ConsumeAnyToken();3825} else if (Kind == OMPC_dist_schedule) {3826Arg.push_back(getOpenMPSimpleClauseType(3827Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()));3828KLoc.push_back(Tok.getLocation());3829if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3830Tok.isNot(tok::annot_pragma_openmp_end))3831ConsumeAnyToken();3832if (Arg.back() == OMPC_DIST_SCHEDULE_static && Tok.is(tok::comma))3833DelimLoc = ConsumeAnyToken();3834} else if (Kind == OMPC_defaultmap) {3835// Get a defaultmap modifier3836unsigned Modifier = getOpenMPSimpleClauseType(3837Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());3838// Set defaultmap modifier to unknown if it is either scalar, aggregate, or3839// pointer3840if (Modifier < OMPC_DEFAULTMAP_MODIFIER_unknown)3841Modifier = OMPC_DEFAULTMAP_MODIFIER_unknown;3842Arg.push_back(Modifier);3843KLoc.push_back(Tok.getLocation());3844if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3845Tok.isNot(tok::annot_pragma_openmp_end))3846ConsumeAnyToken();3847// Parse ':'3848if (Tok.is(tok::colon) || getLangOpts().OpenMP < 50) {3849if (Tok.is(tok::colon))3850ConsumeAnyToken();3851else if (Arg.back() != OMPC_DEFAULTMAP_MODIFIER_unknown)3852Diag(Tok, diag::warn_pragma_expected_colon) << "defaultmap modifier";3853// Get a defaultmap kind3854Arg.push_back(getOpenMPSimpleClauseType(3855Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()));3856KLoc.push_back(Tok.getLocation());3857if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3858Tok.isNot(tok::annot_pragma_openmp_end))3859ConsumeAnyToken();3860} else {3861Arg.push_back(OMPC_DEFAULTMAP_unknown);3862KLoc.push_back(SourceLocation());3863}3864} else if (Kind == OMPC_order) {3865enum { Modifier, OrderKind, NumberOfElements };3866Arg.resize(NumberOfElements);3867KLoc.resize(NumberOfElements);3868Arg[Modifier] = OMPC_ORDER_MODIFIER_unknown;3869Arg[OrderKind] = OMPC_ORDER_unknown;3870unsigned KindModifier = getOpenMPSimpleClauseType(3871Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());3872if (KindModifier > OMPC_ORDER_unknown) {3873// Parse 'modifier'3874Arg[Modifier] = KindModifier;3875KLoc[Modifier] = Tok.getLocation();3876if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3877Tok.isNot(tok::annot_pragma_openmp_end))3878ConsumeAnyToken();3879// Parse ':'3880if (Tok.is(tok::colon))3881ConsumeAnyToken();3882else3883Diag(Tok, diag::warn_pragma_expected_colon) << "order modifier";3884KindModifier = getOpenMPSimpleClauseType(3885Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());3886}3887Arg[OrderKind] = KindModifier;3888KLoc[OrderKind] = Tok.getLocation();3889if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&3890Tok.isNot(tok::annot_pragma_openmp_end))3891ConsumeAnyToken();3892} else if (Kind == OMPC_device) {3893// Only target executable directives support extended device construct.3894if (isOpenMPTargetExecutionDirective(DKind) && getLangOpts().OpenMP >= 50 &&3895NextToken().is(tok::colon)) {3896// Parse optional <device modifier> ':'3897Arg.push_back(getOpenMPSimpleClauseType(3898Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()));3899KLoc.push_back(Tok.getLocation());3900ConsumeAnyToken();3901// Parse ':'3902ConsumeAnyToken();3903} else {3904Arg.push_back(OMPC_DEVICE_unknown);3905KLoc.emplace_back();3906}3907} else if (Kind == OMPC_grainsize) {3908// Parse optional <grainsize modifier> ':'3909OpenMPGrainsizeClauseModifier Modifier =3910static_cast<OpenMPGrainsizeClauseModifier>(getOpenMPSimpleClauseType(3911Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok),3912getLangOpts()));3913if (getLangOpts().OpenMP >= 51) {3914if (NextToken().is(tok::colon)) {3915Arg.push_back(Modifier);3916KLoc.push_back(Tok.getLocation());3917// Parse modifier3918ConsumeAnyToken();3919// Parse ':'3920ConsumeAnyToken();3921} else {3922if (Modifier == OMPC_GRAINSIZE_strict) {3923Diag(Tok, diag::err_modifier_expected_colon) << "strict";3924// Parse modifier3925ConsumeAnyToken();3926}3927Arg.push_back(OMPC_GRAINSIZE_unknown);3928KLoc.emplace_back();3929}3930} else {3931Arg.push_back(OMPC_GRAINSIZE_unknown);3932KLoc.emplace_back();3933}3934} else if (Kind == OMPC_num_tasks) {3935// Parse optional <num_tasks modifier> ':'3936OpenMPNumTasksClauseModifier Modifier =3937static_cast<OpenMPNumTasksClauseModifier>(getOpenMPSimpleClauseType(3938Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok),3939getLangOpts()));3940if (getLangOpts().OpenMP >= 51) {3941if (NextToken().is(tok::colon)) {3942Arg.push_back(Modifier);3943KLoc.push_back(Tok.getLocation());3944// Parse modifier3945ConsumeAnyToken();3946// Parse ':'3947ConsumeAnyToken();3948} else {3949if (Modifier == OMPC_NUMTASKS_strict) {3950Diag(Tok, diag::err_modifier_expected_colon) << "strict";3951// Parse modifier3952ConsumeAnyToken();3953}3954Arg.push_back(OMPC_NUMTASKS_unknown);3955KLoc.emplace_back();3956}3957} else {3958Arg.push_back(OMPC_NUMTASKS_unknown);3959KLoc.emplace_back();3960}3961} else {3962assert(Kind == OMPC_if);3963KLoc.push_back(Tok.getLocation());3964TentativeParsingAction TPA(*this);3965auto DK = parseOpenMPDirectiveKind(*this);3966Arg.push_back(DK);3967if (DK != OMPD_unknown) {3968ConsumeToken();3969if (Tok.is(tok::colon) && getLangOpts().OpenMP > 40) {3970TPA.Commit();3971DelimLoc = ConsumeToken();3972} else {3973TPA.Revert();3974Arg.back() = unsigned(OMPD_unknown);3975}3976} else {3977TPA.Revert();3978}3979}3980
3981bool NeedAnExpression = (Kind == OMPC_schedule && DelimLoc.isValid()) ||3982(Kind == OMPC_dist_schedule && DelimLoc.isValid()) ||3983Kind == OMPC_if || Kind == OMPC_device ||3984Kind == OMPC_grainsize || Kind == OMPC_num_tasks;3985if (NeedAnExpression) {3986SourceLocation ELoc = Tok.getLocation();3987ExprResult LHS(ParseCastExpression(AnyCastExpr, false, NotTypeCast));3988Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional);3989Val =3990Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false);3991}3992
3993// Parse ')'.3994SourceLocation RLoc = Tok.getLocation();3995if (!T.consumeClose())3996RLoc = T.getCloseLocation();3997
3998if (NeedAnExpression && Val.isInvalid())3999return nullptr;4000
4001if (ParseOnly)4002return nullptr;4003return Actions.OpenMP().ActOnOpenMPSingleExprWithArgClause(4004Kind, Arg, Val.get(), Loc, T.getOpenLocation(), KLoc, DelimLoc, RLoc);4005}
4006
4007static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,4008UnqualifiedId &ReductionId) {4009if (ReductionIdScopeSpec.isEmpty()) {4010auto OOK = OO_None;4011switch (P.getCurToken().getKind()) {4012case tok::plus:4013OOK = OO_Plus;4014break;4015case tok::minus:4016OOK = OO_Minus;4017break;4018case tok::star:4019OOK = OO_Star;4020break;4021case tok::amp:4022OOK = OO_Amp;4023break;4024case tok::pipe:4025OOK = OO_Pipe;4026break;4027case tok::caret:4028OOK = OO_Caret;4029break;4030case tok::ampamp:4031OOK = OO_AmpAmp;4032break;4033case tok::pipepipe:4034OOK = OO_PipePipe;4035break;4036default:4037break;4038}4039if (OOK != OO_None) {4040SourceLocation OpLoc = P.ConsumeToken();4041SourceLocation SymbolLocations[] = {OpLoc, OpLoc, SourceLocation()};4042ReductionId.setOperatorFunctionId(OpLoc, OOK, SymbolLocations);4043return false;4044}4045}4046return P.ParseUnqualifiedId(4047ReductionIdScopeSpec, /*ObjectType=*/nullptr,4048/*ObjectHadErrors=*/false, /*EnteringContext*/ false,4049/*AllowDestructorName*/ false,4050/*AllowConstructorName*/ false,4051/*AllowDeductionGuide*/ false, nullptr, ReductionId);4052}
4053
4054/// Checks if the token is a valid map-type-modifier.
4055/// FIXME: It will return an OpenMPMapClauseKind if that's what it parses.
4056static OpenMPMapModifierKind isMapModifier(Parser &P) {4057Token Tok = P.getCurToken();4058if (!Tok.is(tok::identifier))4059return OMPC_MAP_MODIFIER_unknown;4060
4061Preprocessor &PP = P.getPreprocessor();4062OpenMPMapModifierKind TypeModifier =4063static_cast<OpenMPMapModifierKind>(getOpenMPSimpleClauseType(4064OMPC_map, PP.getSpelling(Tok), P.getLangOpts()));4065return TypeModifier;4066}
4067
4068/// Parse the mapper modifier in map, to, and from clauses.
4069bool Parser::parseMapperModifier(SemaOpenMP::OpenMPVarListDataTy &Data) {4070// Parse '('.4071BalancedDelimiterTracker T(*this, tok::l_paren, tok::colon);4072if (T.expectAndConsume(diag::err_expected_lparen_after, "mapper")) {4073SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,4074StopBeforeMatch);4075return true;4076}4077// Parse mapper-identifier4078if (getLangOpts().CPlusPlus)4079ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec,4080/*ObjectType=*/nullptr,4081/*ObjectHasErrors=*/false,4082/*EnteringContext=*/false);4083if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_default)) {4084Diag(Tok.getLocation(), diag::err_omp_mapper_illegal_identifier);4085SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,4086StopBeforeMatch);4087return true;4088}4089auto &DeclNames = Actions.getASTContext().DeclarationNames;4090Data.ReductionOrMapperId = DeclarationNameInfo(4091DeclNames.getIdentifier(Tok.getIdentifierInfo()), Tok.getLocation());4092ConsumeToken();4093// Parse ')'.4094return T.consumeClose();4095}
4096
4097static OpenMPMapClauseKind isMapType(Parser &P);4098
4099/// Parse map-type-modifiers in map clause.
4100/// map([ [map-type-modifier[,] [map-type-modifier[,] ...] [map-type] : ] list)
4101/// where, map-type-modifier ::= always | close | mapper(mapper-identifier) |
4102/// present
4103/// where, map-type ::= alloc | delete | from | release | to | tofrom
4104bool Parser::parseMapTypeModifiers(SemaOpenMP::OpenMPVarListDataTy &Data) {4105bool HasMapType = false;4106SourceLocation PreMapLoc = Tok.getLocation();4107StringRef PreMapName = "";4108while (getCurToken().isNot(tok::colon)) {4109OpenMPMapModifierKind TypeModifier = isMapModifier(*this);4110OpenMPMapClauseKind MapKind = isMapType(*this);4111if (TypeModifier == OMPC_MAP_MODIFIER_always ||4112TypeModifier == OMPC_MAP_MODIFIER_close ||4113TypeModifier == OMPC_MAP_MODIFIER_present ||4114TypeModifier == OMPC_MAP_MODIFIER_ompx_hold) {4115Data.MapTypeModifiers.push_back(TypeModifier);4116Data.MapTypeModifiersLoc.push_back(Tok.getLocation());4117if (PP.LookAhead(0).isNot(tok::comma) &&4118PP.LookAhead(0).isNot(tok::colon) && getLangOpts().OpenMP >= 52)4119Diag(Tok.getLocation(), diag::err_omp_missing_comma)4120<< "map type modifier";4121ConsumeToken();4122} else if (TypeModifier == OMPC_MAP_MODIFIER_mapper) {4123Data.MapTypeModifiers.push_back(TypeModifier);4124Data.MapTypeModifiersLoc.push_back(Tok.getLocation());4125ConsumeToken();4126if (parseMapperModifier(Data))4127return true;4128if (Tok.isNot(tok::comma) && Tok.isNot(tok::colon) &&4129getLangOpts().OpenMP >= 52)4130Diag(Data.MapTypeModifiersLoc.back(), diag::err_omp_missing_comma)4131<< "map type modifier";4132
4133} else if (getLangOpts().OpenMP >= 60 && MapKind != OMPC_MAP_unknown) {4134if (!HasMapType) {4135HasMapType = true;4136Data.ExtraModifier = MapKind;4137MapKind = OMPC_MAP_unknown;4138PreMapLoc = Tok.getLocation();4139PreMapName = Tok.getIdentifierInfo()->getName();4140} else {4141Diag(Tok, diag::err_omp_more_one_map_type);4142Diag(PreMapLoc, diag::note_previous_map_type_specified_here)4143<< PreMapName;4144}4145ConsumeToken();4146} else {4147// For the case of unknown map-type-modifier or a map-type.4148// Map-type is followed by a colon; the function returns when it4149// encounters a token followed by a colon.4150if (Tok.is(tok::comma)) {4151Diag(Tok, diag::err_omp_map_type_modifier_missing);4152ConsumeToken();4153continue;4154}4155// Potential map-type token as it is followed by a colon.4156if (PP.LookAhead(0).is(tok::colon)) {4157if (getLangOpts().OpenMP >= 60) {4158break;4159} else {4160return false;4161}4162}4163
4164Diag(Tok, diag::err_omp_unknown_map_type_modifier)4165<< (getLangOpts().OpenMP >= 51 ? (getLangOpts().OpenMP >= 52 ? 2 : 1)4166: 0)4167<< getLangOpts().OpenMPExtensions;4168ConsumeToken();4169}4170if (getCurToken().is(tok::comma))4171ConsumeToken();4172}4173if (getLangOpts().OpenMP >= 60 && !HasMapType) {4174if (!Tok.is(tok::colon)) {4175Diag(Tok, diag::err_omp_unknown_map_type);4176ConsumeToken();4177} else {4178Data.ExtraModifier = OMPC_MAP_unknown;4179}4180}4181return false;4182}
4183
4184/// Checks if the token is a valid map-type.
4185/// If it is not MapType kind, OMPC_MAP_unknown is returned.
4186static OpenMPMapClauseKind isMapType(Parser &P) {4187Token Tok = P.getCurToken();4188// The map-type token can be either an identifier or the C++ delete keyword.4189if (!Tok.isOneOf(tok::identifier, tok::kw_delete))4190return OMPC_MAP_unknown;4191Preprocessor &PP = P.getPreprocessor();4192unsigned MapType =4193getOpenMPSimpleClauseType(OMPC_map, PP.getSpelling(Tok), P.getLangOpts());4194if (MapType == OMPC_MAP_to || MapType == OMPC_MAP_from ||4195MapType == OMPC_MAP_tofrom || MapType == OMPC_MAP_alloc ||4196MapType == OMPC_MAP_delete || MapType == OMPC_MAP_release)4197return static_cast<OpenMPMapClauseKind>(MapType);4198return OMPC_MAP_unknown;4199}
4200
4201/// Parse map-type in map clause.
4202/// map([ [map-type-modifier[,] [map-type-modifier[,] ...] map-type : ] list)
4203/// where, map-type ::= to | from | tofrom | alloc | release | delete
4204static void parseMapType(Parser &P, SemaOpenMP::OpenMPVarListDataTy &Data) {4205Token Tok = P.getCurToken();4206if (Tok.is(tok::colon)) {4207P.Diag(Tok, diag::err_omp_map_type_missing);4208return;4209}4210Data.ExtraModifier = isMapType(P);4211if (Data.ExtraModifier == OMPC_MAP_unknown)4212P.Diag(Tok, diag::err_omp_unknown_map_type);4213P.ConsumeToken();4214}
4215
4216/// Parses simple expression in parens for single-expression clauses of OpenMP
4217/// constructs.
4218ExprResult Parser::ParseOpenMPIteratorsExpr() {4219assert(Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator" &&4220"Expected 'iterator' token.");4221SourceLocation IteratorKwLoc = ConsumeToken();4222
4223BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);4224if (T.expectAndConsume(diag::err_expected_lparen_after, "iterator"))4225return ExprError();4226
4227SourceLocation LLoc = T.getOpenLocation();4228SmallVector<SemaOpenMP::OMPIteratorData, 4> Data;4229while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {4230// Check if the type parsing is required.4231ParsedType IteratorType;4232if (Tok.isNot(tok::identifier) || NextToken().isNot(tok::equal)) {4233// identifier '=' is not found - parse type.4234TypeResult TR = ParseTypeName();4235if (TR.isInvalid()) {4236T.skipToEnd();4237return ExprError();4238}4239IteratorType = TR.get();4240}4241
4242// Parse identifier.4243IdentifierInfo *II = nullptr;4244SourceLocation IdLoc;4245if (Tok.is(tok::identifier)) {4246II = Tok.getIdentifierInfo();4247IdLoc = ConsumeToken();4248} else {4249Diag(Tok, diag::err_expected_unqualified_id) << 0;4250}4251
4252// Parse '='.4253SourceLocation AssignLoc;4254if (Tok.is(tok::equal))4255AssignLoc = ConsumeToken();4256else4257Diag(Tok, diag::err_omp_expected_equal_in_iterator);4258
4259// Parse range-specification - <begin> ':' <end> [ ':' <step> ]4260ColonProtectionRAIIObject ColonRAII(*this);4261// Parse <begin>4262SourceLocation Loc = Tok.getLocation();4263ExprResult LHS = ParseCastExpression(AnyCastExpr);4264ExprResult Begin = Actions.CorrectDelayedTyposInExpr(4265ParseRHSOfBinaryExpression(LHS, prec::Conditional));4266Begin = Actions.ActOnFinishFullExpr(Begin.get(), Loc,4267/*DiscardedValue=*/false);4268// Parse ':'.4269SourceLocation ColonLoc;4270if (Tok.is(tok::colon))4271ColonLoc = ConsumeToken();4272
4273// Parse <end>4274Loc = Tok.getLocation();4275LHS = ParseCastExpression(AnyCastExpr);4276ExprResult End = Actions.CorrectDelayedTyposInExpr(4277ParseRHSOfBinaryExpression(LHS, prec::Conditional));4278End = Actions.ActOnFinishFullExpr(End.get(), Loc,4279/*DiscardedValue=*/false);4280
4281SourceLocation SecColonLoc;4282ExprResult Step;4283// Parse optional step.4284if (Tok.is(tok::colon)) {4285// Parse ':'4286SecColonLoc = ConsumeToken();4287// Parse <step>4288Loc = Tok.getLocation();4289LHS = ParseCastExpression(AnyCastExpr);4290Step = Actions.CorrectDelayedTyposInExpr(4291ParseRHSOfBinaryExpression(LHS, prec::Conditional));4292Step = Actions.ActOnFinishFullExpr(Step.get(), Loc,4293/*DiscardedValue=*/false);4294}4295
4296// Parse ',' or ')'4297if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren))4298Diag(Tok, diag::err_omp_expected_punc_after_iterator);4299if (Tok.is(tok::comma))4300ConsumeToken();4301
4302SemaOpenMP::OMPIteratorData &D = Data.emplace_back();4303D.DeclIdent = II;4304D.DeclIdentLoc = IdLoc;4305D.Type = IteratorType;4306D.AssignLoc = AssignLoc;4307D.ColonLoc = ColonLoc;4308D.SecColonLoc = SecColonLoc;4309D.Range.Begin = Begin.get();4310D.Range.End = End.get();4311D.Range.Step = Step.get();4312}4313
4314// Parse ')'.4315SourceLocation RLoc = Tok.getLocation();4316if (!T.consumeClose())4317RLoc = T.getCloseLocation();4318
4319return Actions.OpenMP().ActOnOMPIteratorExpr(getCurScope(), IteratorKwLoc,4320LLoc, RLoc, Data);4321}
4322
4323bool Parser::ParseOpenMPReservedLocator(OpenMPClauseKind Kind,4324SemaOpenMP::OpenMPVarListDataTy &Data,4325const LangOptions &LangOpts) {4326// Currently the only reserved locator is 'omp_all_memory' which is only4327// allowed on a depend clause.4328if (Kind != OMPC_depend || LangOpts.OpenMP < 51)4329return false;4330
4331if (Tok.is(tok::identifier) &&4332Tok.getIdentifierInfo()->isStr("omp_all_memory")) {4333
4334if (Data.ExtraModifier == OMPC_DEPEND_outallmemory ||4335Data.ExtraModifier == OMPC_DEPEND_inoutallmemory)4336Diag(Tok, diag::warn_omp_more_one_omp_all_memory);4337else if (Data.ExtraModifier != OMPC_DEPEND_out &&4338Data.ExtraModifier != OMPC_DEPEND_inout)4339Diag(Tok, diag::err_omp_requires_out_inout_depend_type);4340else4341Data.ExtraModifier = Data.ExtraModifier == OMPC_DEPEND_out4342? OMPC_DEPEND_outallmemory4343: OMPC_DEPEND_inoutallmemory;4344ConsumeToken();4345return true;4346}4347return false;4348}
4349
4350/// Parse step size expression. Returns true if parsing is successfull,
4351/// otherwise returns false.
4352static bool parseStepSize(Parser &P, SemaOpenMP::OpenMPVarListDataTy &Data,4353OpenMPClauseKind CKind, SourceLocation ELoc) {4354ExprResult Tail = P.ParseAssignmentExpression();4355Sema &Actions = P.getActions();4356Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc,4357/*DiscardedValue*/ false);4358if (Tail.isUsable()) {4359Data.DepModOrTailExpr = Tail.get();4360Token CurTok = P.getCurToken();4361if (CurTok.isNot(tok::r_paren) && CurTok.isNot(tok::comma)) {4362P.Diag(CurTok, diag::err_expected_punc) << "step expression";4363}4364return true;4365}4366return false;4367}
4368
4369/// Parses clauses with list.
4370bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,4371OpenMPClauseKind Kind,4372SmallVectorImpl<Expr *> &Vars,4373SemaOpenMP::OpenMPVarListDataTy &Data) {4374UnqualifiedId UnqualifiedReductionId;4375bool InvalidReductionId = false;4376bool IsInvalidMapperModifier = false;4377
4378// Parse '('.4379BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);4380if (T.expectAndConsume(diag::err_expected_lparen_after,4381getOpenMPClauseName(Kind).data()))4382return true;4383
4384bool HasIterator = false;4385bool InvalidIterator = false;4386bool NeedRParenForLinear = false;4387BalancedDelimiterTracker LinearT(*this, tok::l_paren,4388tok::annot_pragma_openmp_end);4389// Handle reduction-identifier for reduction clause.4390if (Kind == OMPC_reduction || Kind == OMPC_task_reduction ||4391Kind == OMPC_in_reduction) {4392Data.ExtraModifier = OMPC_REDUCTION_unknown;4393if (Kind == OMPC_reduction && getLangOpts().OpenMP >= 50 &&4394(Tok.is(tok::identifier) || Tok.is(tok::kw_default)) &&4395NextToken().is(tok::comma)) {4396// Parse optional reduction modifier.4397Data.ExtraModifier =4398getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts());4399Data.ExtraModifierLoc = Tok.getLocation();4400ConsumeToken();4401assert(Tok.is(tok::comma) && "Expected comma.");4402(void)ConsumeToken();4403}4404ColonProtectionRAIIObject ColonRAII(*this);4405if (getLangOpts().CPlusPlus)4406ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec,4407/*ObjectType=*/nullptr,4408/*ObjectHasErrors=*/false,4409/*EnteringContext=*/false);4410InvalidReductionId = ParseReductionId(4411*this, Data.ReductionOrMapperIdScopeSpec, UnqualifiedReductionId);4412if (InvalidReductionId) {4413SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,4414StopBeforeMatch);4415}4416if (Tok.is(tok::colon))4417Data.ColonLoc = ConsumeToken();4418else4419Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier";4420if (!InvalidReductionId)4421Data.ReductionOrMapperId =4422Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId);4423} else if (Kind == OMPC_depend || Kind == OMPC_doacross) {4424if (getLangOpts().OpenMP >= 50) {4425if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") {4426// Handle optional dependence modifier.4427// iterator(iterators-definition)4428// where iterators-definition is iterator-specifier [,4429// iterators-definition ]4430// where iterator-specifier is [ iterator-type ] identifier =4431// range-specification4432HasIterator = true;4433EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);4434ExprResult IteratorRes = ParseOpenMPIteratorsExpr();4435Data.DepModOrTailExpr = IteratorRes.get();4436// Parse ','4437ExpectAndConsume(tok::comma);4438}4439}4440// Handle dependency type for depend clause.4441ColonProtectionRAIIObject ColonRAII(*this);4442Data.ExtraModifier = getOpenMPSimpleClauseType(4443Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "",4444getLangOpts());4445Data.ExtraModifierLoc = Tok.getLocation();4446if ((Kind == OMPC_depend && Data.ExtraModifier == OMPC_DEPEND_unknown) ||4447(Kind == OMPC_doacross &&4448Data.ExtraModifier == OMPC_DOACROSS_unknown)) {4449SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,4450StopBeforeMatch);4451} else {4452ConsumeToken();4453// Special processing for depend(source) clause.4454if (DKind == OMPD_ordered && Kind == OMPC_depend &&4455Data.ExtraModifier == OMPC_DEPEND_source) {4456// Parse ')'.4457T.consumeClose();4458return false;4459}4460}4461if (Tok.is(tok::colon)) {4462Data.ColonLoc = ConsumeToken();4463} else if (Kind != OMPC_doacross || Tok.isNot(tok::r_paren)) {4464Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren4465: diag::warn_pragma_expected_colon)4466<< (Kind == OMPC_depend ? "dependency type" : "dependence-type");4467}4468if (Kind == OMPC_doacross) {4469if (Tok.is(tok::identifier) &&4470Tok.getIdentifierInfo()->isStr("omp_cur_iteration")) {4471Data.ExtraModifier = Data.ExtraModifier == OMPC_DOACROSS_source4472? OMPC_DOACROSS_source_omp_cur_iteration4473: OMPC_DOACROSS_sink_omp_cur_iteration;4474ConsumeToken();4475}4476if (Data.ExtraModifier == OMPC_DOACROSS_sink_omp_cur_iteration) {4477if (Tok.isNot(tok::minus)) {4478Diag(Tok, diag::err_omp_sink_and_source_iteration_not_allowd)4479<< getOpenMPClauseName(Kind) << 0 << 0;4480SkipUntil(tok::r_paren);4481return false;4482} else {4483ConsumeToken();4484SourceLocation Loc = Tok.getLocation();4485uint64_t Value = 0;4486if (Tok.isNot(tok::numeric_constant) ||4487(PP.parseSimpleIntegerLiteral(Tok, Value) && Value != 1)) {4488Diag(Loc, diag::err_omp_sink_and_source_iteration_not_allowd)4489<< getOpenMPClauseName(Kind) << 0 << 0;4490SkipUntil(tok::r_paren);4491return false;4492}4493}4494}4495if (Data.ExtraModifier == OMPC_DOACROSS_source_omp_cur_iteration) {4496if (Tok.isNot(tok::r_paren)) {4497Diag(Tok, diag::err_omp_sink_and_source_iteration_not_allowd)4498<< getOpenMPClauseName(Kind) << 1 << 1;4499SkipUntil(tok::r_paren);4500return false;4501}4502}4503// Only the 'sink' case has the expression list.4504if (Kind == OMPC_doacross &&4505(Data.ExtraModifier == OMPC_DOACROSS_source ||4506Data.ExtraModifier == OMPC_DOACROSS_source_omp_cur_iteration ||4507Data.ExtraModifier == OMPC_DOACROSS_sink_omp_cur_iteration)) {4508// Parse ')'.4509T.consumeClose();4510return false;4511}4512}4513} else if (Kind == OMPC_linear) {4514// Try to parse modifier if any.4515Data.ExtraModifier = OMPC_LINEAR_val;4516if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) {4517Data.ExtraModifier =4518getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts());4519Data.ExtraModifierLoc = ConsumeToken();4520LinearT.consumeOpen();4521NeedRParenForLinear = true;4522if (getLangOpts().OpenMP >= 52)4523Diag(Data.ExtraModifierLoc, diag::err_omp_deprecate_old_syntax)4524<< "linear-modifier(list)" << getOpenMPClauseName(Kind)4525<< "linear(list: [linear-modifier,] step(step-size))";4526}4527} else if (Kind == OMPC_lastprivate) {4528// Try to parse modifier if any.4529Data.ExtraModifier = OMPC_LASTPRIVATE_unknown;4530// Conditional modifier allowed only in OpenMP 5.0 and not supported in4531// distribute and taskloop based directives.4532if ((getLangOpts().OpenMP >= 50 && !isOpenMPDistributeDirective(DKind) &&4533!isOpenMPTaskLoopDirective(DKind)) &&4534Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::colon)) {4535Data.ExtraModifier =4536getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts());4537Data.ExtraModifierLoc = Tok.getLocation();4538ConsumeToken();4539assert(Tok.is(tok::colon) && "Expected colon.");4540Data.ColonLoc = ConsumeToken();4541}4542} else if (Kind == OMPC_map) {4543// Handle optional iterator map modifier.4544if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") {4545HasIterator = true;4546EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);4547Data.MapTypeModifiers.push_back(OMPC_MAP_MODIFIER_iterator);4548Data.MapTypeModifiersLoc.push_back(Tok.getLocation());4549ExprResult IteratorRes = ParseOpenMPIteratorsExpr();4550Data.IteratorExpr = IteratorRes.get();4551// Parse ','4552ExpectAndConsume(tok::comma);4553if (getLangOpts().OpenMP < 52) {4554Diag(Tok, diag::err_omp_unknown_map_type_modifier)4555<< (getLangOpts().OpenMP >= 51 ? 1 : 0)4556<< getLangOpts().OpenMPExtensions;4557InvalidIterator = true;4558}4559}4560// Handle map type for map clause.4561ColonProtectionRAIIObject ColonRAII(*this);4562
4563// The first identifier may be a list item, a map-type or a4564// map-type-modifier. The map-type can also be delete which has the same4565// spelling of the C++ delete keyword.4566Data.ExtraModifier = OMPC_MAP_unknown;4567Data.ExtraModifierLoc = Tok.getLocation();4568
4569// Check for presence of a colon in the map clause.4570TentativeParsingAction TPA(*this);4571bool ColonPresent = false;4572if (SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,4573StopBeforeMatch)) {4574if (Tok.is(tok::colon))4575ColonPresent = true;4576}4577TPA.Revert();4578// Only parse map-type-modifier[s] and map-type if a colon is present in4579// the map clause.4580if (ColonPresent) {4581if (getLangOpts().OpenMP >= 60 && getCurToken().is(tok::colon))4582Diag(Tok, diag::err_omp_map_modifier_specification_list);4583IsInvalidMapperModifier = parseMapTypeModifiers(Data);4584if (getLangOpts().OpenMP < 60 && !IsInvalidMapperModifier)4585parseMapType(*this, Data);4586else4587SkipUntil(tok::colon, tok::annot_pragma_openmp_end, StopBeforeMatch);4588}4589if (Data.ExtraModifier == OMPC_MAP_unknown) {4590Data.ExtraModifier = OMPC_MAP_tofrom;4591if (getLangOpts().OpenMP >= 52) {4592if (DKind == OMPD_target_enter_data)4593Data.ExtraModifier = OMPC_MAP_to;4594else if (DKind == OMPD_target_exit_data)4595Data.ExtraModifier = OMPC_MAP_from;4596}4597Data.IsMapTypeImplicit = true;4598}4599
4600if (Tok.is(tok::colon))4601Data.ColonLoc = ConsumeToken();4602} else if (Kind == OMPC_to || Kind == OMPC_from) {4603while (Tok.is(tok::identifier)) {4604auto Modifier = static_cast<OpenMPMotionModifierKind>(4605getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts()));4606if (Modifier == OMPC_MOTION_MODIFIER_unknown)4607break;4608Data.MotionModifiers.push_back(Modifier);4609Data.MotionModifiersLoc.push_back(Tok.getLocation());4610ConsumeToken();4611if (Modifier == OMPC_MOTION_MODIFIER_mapper) {4612IsInvalidMapperModifier = parseMapperModifier(Data);4613if (IsInvalidMapperModifier)4614break;4615}4616// OpenMP < 5.1 doesn't permit a ',' or additional modifiers.4617if (getLangOpts().OpenMP < 51)4618break;4619// OpenMP 5.1 accepts an optional ',' even if the next character is ':'.4620// TODO: Is that intentional?4621if (Tok.is(tok::comma))4622ConsumeToken();4623}4624if (!Data.MotionModifiers.empty() && Tok.isNot(tok::colon)) {4625if (!IsInvalidMapperModifier) {4626if (getLangOpts().OpenMP < 51)4627Diag(Tok, diag::warn_pragma_expected_colon) << ")";4628else4629Diag(Tok, diag::warn_pragma_expected_colon) << "motion modifier";4630}4631SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,4632StopBeforeMatch);4633}4634// OpenMP 5.1 permits a ':' even without a preceding modifier. TODO: Is4635// that intentional?4636if ((!Data.MotionModifiers.empty() || getLangOpts().OpenMP >= 51) &&4637Tok.is(tok::colon))4638Data.ColonLoc = ConsumeToken();4639} else if (Kind == OMPC_allocate ||4640(Kind == OMPC_affinity && Tok.is(tok::identifier) &&4641PP.getSpelling(Tok) == "iterator")) {4642// Handle optional allocator expression followed by colon delimiter.4643ColonProtectionRAIIObject ColonRAII(*this);4644TentativeParsingAction TPA(*this);4645// OpenMP 5.0, 2.10.1, task Construct.4646// where aff-modifier is one of the following:4647// iterator(iterators-definition)4648ExprResult Tail;4649if (Kind == OMPC_allocate) {4650Tail = ParseAssignmentExpression();4651} else {4652HasIterator = true;4653EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);4654Tail = ParseOpenMPIteratorsExpr();4655}4656Tail = Actions.CorrectDelayedTyposInExpr(Tail);4657Tail = Actions.ActOnFinishFullExpr(Tail.get(), T.getOpenLocation(),4658/*DiscardedValue=*/false);4659if (Tail.isUsable()) {4660if (Tok.is(tok::colon)) {4661Data.DepModOrTailExpr = Tail.get();4662Data.ColonLoc = ConsumeToken();4663TPA.Commit();4664} else {4665// Colon not found, parse only list of variables.4666TPA.Revert();4667}4668} else {4669// Parsing was unsuccessfull, revert and skip to the end of clause or4670// directive.4671TPA.Revert();4672SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,4673StopBeforeMatch);4674}4675} else if (Kind == OMPC_adjust_args) {4676// Handle adjust-op for adjust_args clause.4677ColonProtectionRAIIObject ColonRAII(*this);4678Data.ExtraModifier = getOpenMPSimpleClauseType(4679Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "",4680getLangOpts());4681Data.ExtraModifierLoc = Tok.getLocation();4682if (Data.ExtraModifier == OMPC_ADJUST_ARGS_unknown) {4683Diag(Tok, diag::err_omp_unknown_adjust_args_op);4684SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);4685} else {4686ConsumeToken();4687if (Tok.is(tok::colon))4688Data.ColonLoc = Tok.getLocation();4689ExpectAndConsume(tok::colon, diag::warn_pragma_expected_colon,4690"adjust-op");4691}4692}4693
4694bool IsComma =4695(Kind != OMPC_reduction && Kind != OMPC_task_reduction &&4696Kind != OMPC_in_reduction && Kind != OMPC_depend &&4697Kind != OMPC_doacross && Kind != OMPC_map && Kind != OMPC_adjust_args) ||4698(Kind == OMPC_reduction && !InvalidReductionId) ||4699(Kind == OMPC_map && Data.ExtraModifier != OMPC_MAP_unknown) ||4700(Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown) ||4701(Kind == OMPC_doacross && Data.ExtraModifier != OMPC_DOACROSS_unknown) ||4702(Kind == OMPC_adjust_args &&4703Data.ExtraModifier != OMPC_ADJUST_ARGS_unknown);4704const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);4705while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&4706Tok.isNot(tok::annot_pragma_openmp_end))) {4707ParseScope OMPListScope(this, Scope::OpenMPDirectiveScope);4708ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);4709if (!ParseOpenMPReservedLocator(Kind, Data, getLangOpts())) {4710// Parse variable4711ExprResult VarExpr =4712Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());4713if (VarExpr.isUsable()) {4714Vars.push_back(VarExpr.get());4715} else {4716SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,4717StopBeforeMatch);4718}4719}4720// Skip ',' if any4721IsComma = Tok.is(tok::comma);4722if (IsComma)4723ConsumeToken();4724else if (Tok.isNot(tok::r_paren) &&4725Tok.isNot(tok::annot_pragma_openmp_end) &&4726(!MayHaveTail || Tok.isNot(tok::colon)))4727Diag(Tok, diag::err_omp_expected_punc)4728<< ((Kind == OMPC_flush) ? getOpenMPDirectiveName(OMPD_flush)4729: getOpenMPClauseName(Kind))4730<< (Kind == OMPC_flush);4731}4732
4733// Parse ')' for linear clause with modifier.4734if (NeedRParenForLinear)4735LinearT.consumeClose();4736
4737// Parse ':' linear modifiers (val, uval, ref or step(step-size))4738// or parse ':' alignment.4739const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);4740bool StepFound = false;4741bool ModifierFound = false;4742if (MustHaveTail) {4743Data.ColonLoc = Tok.getLocation();4744SourceLocation ELoc = ConsumeToken();4745
4746if (getLangOpts().OpenMP >= 52 && Kind == OMPC_linear) {4747while (Tok.isNot(tok::r_paren)) {4748if (Tok.is(tok::identifier)) {4749// identifier could be a linear kind (val, uval, ref) or step4750// modifier or step size4751OpenMPLinearClauseKind LinKind =4752static_cast<OpenMPLinearClauseKind>(getOpenMPSimpleClauseType(4753Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok),4754getLangOpts()));4755
4756if (LinKind == OMPC_LINEAR_step) {4757if (StepFound)4758Diag(Tok, diag::err_omp_multiple_step_or_linear_modifier) << 0;4759
4760BalancedDelimiterTracker StepT(*this, tok::l_paren,4761tok::annot_pragma_openmp_end);4762SourceLocation StepModifierLoc = ConsumeToken();4763// parse '('4764if (StepT.consumeOpen())4765Diag(StepModifierLoc, diag::err_expected_lparen_after) << "step";4766
4767// parse step size expression4768StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation());4769if (StepFound)4770Data.StepModifierLoc = StepModifierLoc;4771
4772// parse ')'4773StepT.consumeClose();4774} else if (LinKind >= 0 && LinKind < OMPC_LINEAR_step) {4775if (ModifierFound)4776Diag(Tok, diag::err_omp_multiple_step_or_linear_modifier) << 1;4777
4778Data.ExtraModifier = LinKind;4779Data.ExtraModifierLoc = ConsumeToken();4780ModifierFound = true;4781} else {4782StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation());4783}4784} else {4785// parse an integer expression as step size4786StepFound = parseStepSize(*this, Data, Kind, Tok.getLocation());4787}4788
4789if (Tok.is(tok::comma))4790ConsumeToken();4791if (Tok.is(tok::r_paren) || Tok.is(tok::annot_pragma_openmp_end))4792break;4793}4794if (!StepFound && !ModifierFound)4795Diag(ELoc, diag::err_expected_expression);4796} else {4797// for OMPC_aligned and OMPC_linear (with OpenMP <= 5.1)4798ExprResult Tail = ParseAssignmentExpression();4799Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc,4800/*DiscardedValue*/ false);4801if (Tail.isUsable())4802Data.DepModOrTailExpr = Tail.get();4803else4804SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,4805StopBeforeMatch);4806}4807}4808
4809// Parse ')'.4810Data.RLoc = Tok.getLocation();4811if (!T.consumeClose())4812Data.RLoc = T.getCloseLocation();4813// Exit from scope when the iterator is used in depend clause.4814if (HasIterator)4815ExitScope();4816return (Kind != OMPC_depend && Kind != OMPC_doacross && Kind != OMPC_map &&4817Vars.empty()) ||4818(MustHaveTail && !Data.DepModOrTailExpr && StepFound) ||4819InvalidReductionId || IsInvalidMapperModifier || InvalidIterator;4820}
4821
4822/// Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
4823/// 'shared', 'copyin', 'copyprivate', 'flush', 'reduction', 'task_reduction',
4824/// 'in_reduction', 'nontemporal', 'exclusive' or 'inclusive'.
4825///
4826/// private-clause:
4827/// 'private' '(' list ')'
4828/// firstprivate-clause:
4829/// 'firstprivate' '(' list ')'
4830/// lastprivate-clause:
4831/// 'lastprivate' '(' list ')'
4832/// shared-clause:
4833/// 'shared' '(' list ')'
4834/// linear-clause:
4835/// 'linear' '(' linear-list [ ':' linear-step ] ')'
4836/// aligned-clause:
4837/// 'aligned' '(' list [ ':' alignment ] ')'
4838/// reduction-clause:
4839/// 'reduction' '(' [ modifier ',' ] reduction-identifier ':' list ')'
4840/// task_reduction-clause:
4841/// 'task_reduction' '(' reduction-identifier ':' list ')'
4842/// in_reduction-clause:
4843/// 'in_reduction' '(' reduction-identifier ':' list ')'
4844/// copyprivate-clause:
4845/// 'copyprivate' '(' list ')'
4846/// flush-clause:
4847/// 'flush' '(' list ')'
4848/// depend-clause:
4849/// 'depend' '(' in | out | inout : list | source ')'
4850/// map-clause:
4851/// 'map' '(' [ [ always [,] ] [ close [,] ]
4852/// [ mapper '(' mapper-identifier ')' [,] ]
4853/// to | from | tofrom | alloc | release | delete ':' ] list ')';
4854/// to-clause:
4855/// 'to' '(' [ mapper '(' mapper-identifier ')' ':' ] list ')'
4856/// from-clause:
4857/// 'from' '(' [ mapper '(' mapper-identifier ')' ':' ] list ')'
4858/// use_device_ptr-clause:
4859/// 'use_device_ptr' '(' list ')'
4860/// use_device_addr-clause:
4861/// 'use_device_addr' '(' list ')'
4862/// is_device_ptr-clause:
4863/// 'is_device_ptr' '(' list ')'
4864/// has_device_addr-clause:
4865/// 'has_device_addr' '(' list ')'
4866/// allocate-clause:
4867/// 'allocate' '(' [ allocator ':' ] list ')'
4868/// nontemporal-clause:
4869/// 'nontemporal' '(' list ')'
4870/// inclusive-clause:
4871/// 'inclusive' '(' list ')'
4872/// exclusive-clause:
4873/// 'exclusive' '(' list ')'
4874///
4875/// For 'linear' clause linear-list may have the following forms:
4876/// list
4877/// modifier(list)
4878/// where modifier is 'val' (C) or 'ref', 'val' or 'uval'(C++).
4879OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,4880OpenMPClauseKind Kind,4881bool ParseOnly) {4882SourceLocation Loc = Tok.getLocation();4883SourceLocation LOpen = ConsumeToken();4884SmallVector<Expr *, 4> Vars;4885SemaOpenMP::OpenMPVarListDataTy Data;4886
4887if (ParseOpenMPVarList(DKind, Kind, Vars, Data))4888return nullptr;4889
4890if (ParseOnly)4891return nullptr;4892OMPVarListLocTy Locs(Loc, LOpen, Data.RLoc);4893return Actions.OpenMP().ActOnOpenMPVarListClause(Kind, Vars, Locs, Data);4894}
4895
4896bool Parser::ParseOpenMPExprListClause(OpenMPClauseKind Kind,4897SourceLocation &ClauseNameLoc,4898SourceLocation &OpenLoc,4899SourceLocation &CloseLoc,4900SmallVectorImpl<Expr *> &Exprs,4901bool ReqIntConst) {4902assert(getOpenMPClauseName(Kind) == PP.getSpelling(Tok) &&4903"Expected parsing to start at clause name");4904ClauseNameLoc = ConsumeToken();4905
4906// Parse inside of '(' and ')'.4907BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);4908if (T.consumeOpen()) {4909Diag(Tok, diag::err_expected) << tok::l_paren;4910return true;4911}4912
4913// Parse the list with interleaved commas.4914do {4915ExprResult Val =4916ReqIntConst ? ParseConstantExpression() : ParseAssignmentExpression();4917if (!Val.isUsable()) {4918// Encountered something other than an expression; abort to ')'.4919T.skipToEnd();4920return true;4921}4922Exprs.push_back(Val.get());4923} while (TryConsumeToken(tok::comma));4924
4925bool Result = T.consumeClose();4926OpenLoc = T.getOpenLocation();4927CloseLoc = T.getCloseLocation();4928return Result;4929}
4930