diff options
Diffstat (limited to 'clang/lib/Parse/ParseOpenMP.cpp')
-rw-r--r-- | clang/lib/Parse/ParseOpenMP.cpp | 425 |
1 files changed, 332 insertions, 93 deletions
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index db7e967b15ae..18e43c3734ac 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -131,6 +131,7 @@ static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) { {OMPD_declare, OMPD_simd, OMPD_declare_simd}, {OMPD_declare, OMPD_target, OMPD_declare_target}, {OMPD_declare, OMPD_variant, OMPD_declare_variant}, + {OMPD_begin_declare, OMPD_target, OMPD_begin_declare_target}, {OMPD_begin_declare, OMPD_variant, OMPD_begin_declare_variant}, {OMPD_end_declare, OMPD_variant, OMPD_end_declare_variant}, {OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel}, @@ -441,9 +442,9 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) { ConsumeToken(); if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteInitializer(getCurScope(), OmpPrivParm); Actions.FinalizeDeclaration(OmpPrivParm); - cutOffParsing(); return; } @@ -1664,30 +1665,41 @@ parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) { return SimpleClauseData(Type, Loc, LOpen, TypeLoc, RLoc); } -Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() { - // OpenMP 4.5 syntax with list of entities. - Sema::NamedDeclSetType SameDirectiveDecls; - SmallVector<std::tuple<OMPDeclareTargetDeclAttr::MapTypeTy, SourceLocation, - NamedDecl *>, - 4> - DeclareTargetDecls; - OMPDeclareTargetDeclAttr::DevTypeTy DT = OMPDeclareTargetDeclAttr::DT_Any; +void Parser::ParseOMPDeclareTargetClauses( + Sema::DeclareTargetContextInfo &DTCI) { SourceLocation DeviceTypeLoc; + bool RequiresToOrLinkClause = false; + bool HasToOrLinkClause = false; while (Tok.isNot(tok::annot_pragma_openmp_end)) { OMPDeclareTargetDeclAttr::MapTypeTy MT = OMPDeclareTargetDeclAttr::MT_To; - if (Tok.is(tok::identifier)) { + bool HasIdentifier = Tok.is(tok::identifier); + if (HasIdentifier) { + // If we see any clause we need a to or link clause. + RequiresToOrLinkClause = true; IdentifierInfo *II = Tok.getIdentifierInfo(); StringRef ClauseName = II->getName(); bool IsDeviceTypeClause = getLangOpts().OpenMP >= 50 && getOpenMPClauseKind(ClauseName) == OMPC_device_type; - // Parse 'to|link|device_type' clauses. - if (!OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT) && - !IsDeviceTypeClause) { + + bool IsToOrLinkClause = + OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT); + assert((!IsDeviceTypeClause || !IsToOrLinkClause) && "Cannot be both!"); + + if (!IsDeviceTypeClause && DTCI.Kind == OMPD_begin_declare_target) { Diag(Tok, diag::err_omp_declare_target_unexpected_clause) - << ClauseName << (getLangOpts().OpenMP >= 50 ? 1 : 0); + << ClauseName << 0; break; } + if (!IsDeviceTypeClause && !IsToOrLinkClause) { + Diag(Tok, diag::err_omp_declare_target_unexpected_clause) + << ClauseName << (getLangOpts().OpenMP >= 50 ? 2 : 1); + break; + } + + if (IsToOrLinkClause) + HasToOrLinkClause = true; + // Parse 'device_type' clause and go to next clause if any. if (IsDeviceTypeClause) { Optional<SimpleClauseData> DevTypeData = @@ -1697,16 +1709,17 @@ Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() { // We already saw another device_type clause, diagnose it. Diag(DevTypeData.getValue().Loc, diag::warn_omp_more_one_device_type_clause); + break; } switch (static_cast<OpenMPDeviceType>(DevTypeData.getValue().Type)) { case OMPC_DEVICE_TYPE_any: - DT = OMPDeclareTargetDeclAttr::DT_Any; + DTCI.DT = OMPDeclareTargetDeclAttr::DT_Any; break; case OMPC_DEVICE_TYPE_host: - DT = OMPDeclareTargetDeclAttr::DT_Host; + DTCI.DT = OMPDeclareTargetDeclAttr::DT_Host; break; case OMPC_DEVICE_TYPE_nohost: - DT = OMPDeclareTargetDeclAttr::DT_NoHost; + DTCI.DT = OMPDeclareTargetDeclAttr::DT_NoHost; break; case OMPC_DEVICE_TYPE_unknown: llvm_unreachable("Unexpected device_type"); @@ -1717,37 +1730,47 @@ Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() { } ConsumeToken(); } - auto &&Callback = [this, MT, &DeclareTargetDecls, &SameDirectiveDecls]( - CXXScopeSpec &SS, DeclarationNameInfo NameInfo) { - NamedDecl *ND = Actions.lookupOpenMPDeclareTargetName( - getCurScope(), SS, NameInfo, SameDirectiveDecls); - if (ND) - DeclareTargetDecls.emplace_back(MT, NameInfo.getLoc(), ND); - }; - if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback, - /*AllowScopeSpecifier=*/true)) + + if (DTCI.Kind == OMPD_declare_target || HasIdentifier) { + auto &&Callback = [this, MT, &DTCI](CXXScopeSpec &SS, + DeclarationNameInfo NameInfo) { + NamedDecl *ND = + Actions.lookupOpenMPDeclareTargetName(getCurScope(), SS, NameInfo); + if (!ND) + return; + Sema::DeclareTargetContextInfo::MapInfo MI{MT, NameInfo.getLoc()}; + bool FirstMapping = DTCI.ExplicitlyMapped.try_emplace(ND, MI).second; + if (!FirstMapping) + Diag(NameInfo.getLoc(), diag::err_omp_declare_target_multiple) + << NameInfo.getName(); + }; + if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback, + /*AllowScopeSpecifier=*/true)) + break; + } + + if (Tok.is(tok::l_paren)) { + Diag(Tok, + diag::err_omp_begin_declare_target_unexpected_implicit_to_clause); + break; + } + if (!HasIdentifier && Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, + diag::err_omp_declare_target_unexpected_clause_after_implicit_to); break; + } // Consume optional ','. if (Tok.is(tok::comma)) ConsumeToken(); } + + // For declare target require at least 'to' or 'link' to be present. + if (DTCI.Kind == OMPD_declare_target && RequiresToOrLinkClause && + !HasToOrLinkClause) + Diag(DTCI.Loc, diag::err_omp_declare_target_missing_to_or_link_clause); + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); - ConsumeAnyToken(); - for (auto &MTLocDecl : DeclareTargetDecls) { - OMPDeclareTargetDeclAttr::MapTypeTy MT; - SourceLocation Loc; - NamedDecl *ND; - std::tie(MT, Loc, ND) = MTLocDecl; - // device_type clause is applied only to functions. - Actions.ActOnOpenMPDeclareTargetName( - ND, Loc, MT, isa<VarDecl>(ND) ? OMPDeclareTargetDeclAttr::DT_Any : DT); - } - SmallVector<Decl *, 4> Decls(SameDirectiveDecls.begin(), - SameDirectiveDecls.end()); - if (Decls.empty()) - return DeclGroupPtrTy(); - return Actions.BuildDeclaratorGroup(Decls); } void Parser::skipUntilPragmaOpenMPEnd(OpenMPDirectiveKind DKind) { @@ -1784,10 +1807,11 @@ void Parser::parseOMPEndDirective(OpenMPDirectiveKind BeginKind, SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); } -void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind, +void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind BeginDKind, + OpenMPDirectiveKind EndDKind, SourceLocation DKLoc) { - parseOMPEndDirective(OMPD_declare_target, OMPD_end_declare_target, DKind, - DKLoc, Tok.getLocation(), + parseOMPEndDirective(BeginDKind, OMPD_end_declare_target, EndDKind, DKLoc, + Tok.getLocation(), /* SkipUntilOpenMPEnd */ false); // Skip the last annot_pragma_openmp_end. if (Tok.is(tok::annot_pragma_openmp_end)) @@ -1833,7 +1857,8 @@ void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind, Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, bool Delayed, DeclSpec::TST TagType, Decl *Tag) { - assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) && + "Not an OpenMP directive!"); ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); @@ -1851,7 +1876,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( Toks.push_back(Tok); while (Cnt && Tok.isNot(tok::eof)) { (void)ConsumeAnyToken(); - if (Tok.is(tok::annot_pragma_openmp)) + if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp)) ++Cnt; else if (Tok.is(tok::annot_pragma_openmp_end)) --Cnt; @@ -2074,7 +2099,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( ConsumeAnyToken(); DeclGroupPtrTy Ptr; - if (Tok.is(tok::annot_pragma_openmp)) { + if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp)) { Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, Delayed, TagType, Tag); } else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) { @@ -2101,58 +2126,48 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( ParseOMPDeclareVariantClauses(Ptr, Toks, Loc); return Ptr; } + case OMPD_begin_declare_target: case OMPD_declare_target: { SourceLocation DTLoc = ConsumeAnyToken(); - if (Tok.isNot(tok::annot_pragma_openmp_end)) { - return ParseOMPDeclareTargetClauses(); - } + bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end); + bool HasImplicitMappings = + DKind == OMPD_begin_declare_target || !HasClauses; + Sema::DeclareTargetContextInfo DTCI(DKind, DTLoc); + if (HasClauses) + ParseOMPDeclareTargetClauses(DTCI); // Skip the last annot_pragma_openmp_end. ConsumeAnyToken(); - if (!Actions.ActOnStartOpenMPDeclareTargetDirective(DTLoc)) - return DeclGroupPtrTy(); - - ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false); - llvm::SmallVector<Decl *, 4> Decls; - DKind = parseOpenMPDirectiveKind(*this); - while (DKind != OMPD_end_declare_target && Tok.isNot(tok::eof) && - Tok.isNot(tok::r_brace)) { - DeclGroupPtrTy Ptr; - // Here we expect to see some function declaration. - if (AS == AS_none) { - assert(TagType == DeclSpec::TST_unspecified); - MaybeParseCXX11Attributes(Attrs); - ParsingDeclSpec PDS(*this); - Ptr = ParseExternalDeclaration(Attrs, &PDS); - } else { - Ptr = - ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag); - } - if (Ptr) { - DeclGroupRef Ref = Ptr.get(); - Decls.append(Ref.begin(), Ref.end()); - } - if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) { - TentativeParsingAction TPA(*this); - ConsumeAnnotationToken(); - DKind = parseOpenMPDirectiveKind(*this); - if (DKind != OMPD_end_declare_target) - TPA.Revert(); - else - TPA.Commit(); - } + if (HasImplicitMappings) { + Actions.ActOnStartOpenMPDeclareTargetContext(DTCI); + return nullptr; } - ParseOMPEndDeclareTargetDirective(DKind, DTLoc); - Actions.ActOnFinishOpenMPDeclareTargetDirective(); + Actions.ActOnFinishedOpenMPDeclareTargetContext(DTCI); + llvm::SmallVector<Decl *, 4> Decls; + for (auto &It : DTCI.ExplicitlyMapped) + Decls.push_back(It.first); return Actions.BuildDeclaratorGroup(Decls); } + case OMPD_end_declare_target: { + if (!Actions.isInOpenMPDeclareTargetContext()) { + Diag(Tok, diag::err_omp_unexpected_directive) + << 1 << getOpenMPDirectiveName(DKind); + break; + } + const Sema::DeclareTargetContextInfo &DTCI = + Actions.ActOnOpenMPEndDeclareTargetDirective(); + ParseOMPEndDeclareTargetDirective(DTCI.Kind, DKind, DTCI.Loc); + return nullptr; + } case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; case OMPD_parallel: case OMPD_simd: + case OMPD_tile: + case OMPD_unroll: case OMPD_task: case OMPD_taskyield: case OMPD_barrier: @@ -2190,7 +2205,6 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_parallel_master_taskloop: case OMPD_parallel_master_taskloop_simd: case OMPD_distribute: - case OMPD_end_declare_target: case OMPD_target_update: case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: @@ -2206,6 +2220,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: case OMPD_target_teams_distribute_simd: + case OMPD_dispatch: + case OMPD_masked: Diag(Tok, diag::err_omp_unexpected_directive) << 1 << getOpenMPDirectiveName(DKind); break; @@ -2255,12 +2271,13 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( /// simd' | 'teams distribute parallel for simd' | 'teams distribute /// parallel for' | 'target teams' | 'target teams distribute' | 'target /// teams distribute parallel for' | 'target teams distribute parallel -/// for simd' | 'target teams distribute simd' {clause} +/// for simd' | 'target teams distribute simd' | 'masked' {clause} /// annot_pragma_openmp_end /// StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { - assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) && + "Not an OpenMP directive!"); ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); SmallVector<OMPClause *, 5> Clauses; @@ -2377,6 +2394,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { case OMPD_target_enter_data: case OMPD_target_exit_data: case OMPD_target_update: + case OMPD_interop: if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == ParsedStmtContext()) { Diag(Tok, diag::err_omp_immediate_directive) @@ -2387,6 +2405,8 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { LLVM_FALLTHROUGH; case OMPD_parallel: case OMPD_simd: + case OMPD_tile: + case OMPD_unroll: case OMPD_for: case OMPD_for_simd: case OMPD_sections: @@ -2427,7 +2447,9 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { case OMPD_target_teams_distribute: case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: - case OMPD_target_teams_distribute_simd: { + case OMPD_target_teams_distribute_simd: + case OMPD_dispatch: + case OMPD_masked: { // Special processing for flush and depobj clauses. Token ImplicitTok; bool ImplicitClauseAllowed = false; @@ -2521,6 +2543,11 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { HasAssociatedStatement = false; } + if (DKind == OMPD_tile && !FirstClauses[unsigned(OMPC_sizes)].getInt()) { + Diag(Loc, diag::err_omp_required_clause) + << getOpenMPDirectiveName(OMPD_tile) << "sizes"; + } + StmtResult AssociatedStmt; if (HasAssociatedStatement) { // The body is a block scope like in Lambdas and Blocks. @@ -2529,7 +2556,15 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { // the captured region. Code elsewhere assumes that any FunctionScopeInfo // should have at least one compound statement scope within it. ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false); - AssociatedStmt = (Sema::CompoundScopeRAII(Actions), ParseStatement()); + { + Sema::CompoundScopeRAII Scope(Actions); + AssociatedStmt = ParseStatement(); + + if (AssociatedStmt.isUsable() && isOpenMPLoopDirective(DKind) && + getLangOpts().OpenMPIRBuilder) + AssociatedStmt = + Actions.ActOnOpenMPCanonicalLoop(AssociatedStmt.get()); + } AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); } else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data || DKind == OMPD_target_exit_data) { @@ -2550,6 +2585,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { } case OMPD_declare_simd: case OMPD_declare_target: + case OMPD_begin_declare_target: case OMPD_end_declare_target: case OMPD_requires: case OMPD_begin_declare_variant: @@ -2633,6 +2669,37 @@ bool Parser::ParseOpenMPSimpleVarList( return !IsCorrect; } +OMPClause *Parser::ParseOpenMPSizesClause() { + SourceLocation ClauseNameLoc = ConsumeToken(); + SmallVector<Expr *, 4> ValExprs; + + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.consumeOpen()) { + Diag(Tok, diag::err_expected) << tok::l_paren; + return nullptr; + } + + while (true) { + ExprResult Val = ParseConstantExpression(); + if (!Val.isUsable()) { + T.skipToEnd(); + return nullptr; + } + + ValExprs.push_back(Val.get()); + + if (Tok.is(tok::r_paren) || Tok.is(tok::annot_pragma_openmp_end)) + break; + + ExpectAndConsume(tok::comma); + } + + T.consumeClose(); + + return Actions.ActOnOpenMPSizesClause( + ValExprs, ClauseNameLoc, T.getOpenLocation(), T.getCloseLocation()); +} + OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) { SourceLocation Loc = Tok.getLocation(); ConsumeAnyToken(); @@ -2643,7 +2710,8 @@ OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) { return nullptr; SmallVector<Sema::UsesAllocatorsData, 4> Data; do { - ExprResult Allocator = ParseCXXIdExpression(); + ExprResult Allocator = + getLangOpts().CPlusPlus ? ParseCXXIdExpression() : ParseExpression(); if (Allocator.isInvalid()) { SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -2655,7 +2723,8 @@ OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) { BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); T.consumeOpen(); - ExprResult AllocatorTraits = ParseCXXIdExpression(); + ExprResult AllocatorTraits = + getLangOpts().CPlusPlus ? ParseCXXIdExpression() : ParseExpression(); T.consumeClose(); if (AllocatorTraits.isInvalid()) { SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, @@ -2727,6 +2796,10 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_allocator: case OMPC_depobj: case OMPC_detach: + case OMPC_novariants: + case OMPC_nocontext: + case OMPC_filter: + case OMPC_partial: // OpenMP [2.5, Restrictions] // At most one num_threads clause can appear on the directive. // OpenMP [2.8.1, simd construct, Restrictions] @@ -2749,13 +2822,17 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, // At most one allocator clause can appear on the directive. // OpenMP 5.0, 2.10.1 task Construct, Restrictions. // At most one detach clause can appear on the directive. + // OpenMP 5.1, 2.3.6 dispatch Construct, Restrictions. + // At most one novariants clause can appear on a dispatch directive. + // At most one nocontext clause can appear on a dispatch directive. if (!FirstClause) { Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0; ErrorFound = true; } - if (CKind == OMPC_ordered && PP.LookAhead(/*N=*/0).isNot(tok::l_paren)) + if ((CKind == OMPC_ordered || CKind == OMPC_partial) && + PP.LookAhead(/*N=*/0).isNot(tok::l_paren)) Clause = ParseOpenMPClause(CKind, WrongDirective); else Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective); @@ -2818,7 +2895,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_unified_shared_memory: case OMPC_reverse_offload: case OMPC_dynamic_allocators: - case OMPC_destroy: + case OMPC_full: // OpenMP [2.7.1, Restrictions, p. 9] // Only one ordered clause can appear on a loop directive. // OpenMP [2.7.1, Restrictions, C/C++, p. 4] @@ -2870,9 +2947,33 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_affinity: Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective); break; + case OMPC_sizes: + if (!FirstClause) { + Diag(Tok, diag::err_omp_more_one_clause) + << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0; + ErrorFound = true; + } + + Clause = ParseOpenMPSizesClause(); + break; case OMPC_uses_allocators: Clause = ParseOpenMPUsesAllocatorClause(DKind); break; + case OMPC_destroy: + if (DKind != OMPD_interop) { + if (!FirstClause) { + Diag(Tok, diag::err_omp_more_one_clause) + << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0; + ErrorFound = true; + } + Clause = ParseOpenMPClause(CKind, WrongDirective); + break; + } + LLVM_FALLTHROUGH; + case OMPC_init: + case OMPC_use: + Clause = ParseOpenMPInteropClause(CKind, WrongDirective); + break; case OMPC_device_type: case OMPC_unknown: skipUntilPragmaOpenMPEnd(DKind); @@ -2969,6 +3070,144 @@ OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind, return Actions.ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc, LLoc, RLoc); } +/// Parsing of OpenMP clauses that use an interop-var. +/// +/// init-clause: +/// init([interop-modifier, ]interop-type[[, interop-type] ... ]:interop-var) +/// +/// destroy-clause: +/// destroy(interop-var) +/// +/// use-clause: +/// use(interop-var) +/// +/// interop-modifier: +/// prefer_type(preference-list) +/// +/// preference-list: +/// foreign-runtime-id [, foreign-runtime-id]... +/// +/// foreign-runtime-id: +/// <string-literal> | <constant-integral-expression> +/// +/// interop-type: +/// target | targetsync +/// +OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind, + bool ParseOnly) { + SourceLocation Loc = ConsumeToken(); + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(Kind).data())) + return nullptr; + + bool IsTarget = false; + bool IsTargetSync = false; + SmallVector<Expr *, 4> Prefs; + + if (Kind == OMPC_init) { + + // Parse optional interop-modifier. + if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "prefer_type") { + ConsumeToken(); + BalancedDelimiterTracker PT(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + if (PT.expectAndConsume(diag::err_expected_lparen_after, "prefer_type")) + return nullptr; + + while (Tok.isNot(tok::r_paren)) { + SourceLocation Loc = Tok.getLocation(); + ExprResult LHS = ParseCastExpression(AnyCastExpr); + ExprResult PTExpr = Actions.CorrectDelayedTyposInExpr( + ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + PTExpr = Actions.ActOnFinishFullExpr(PTExpr.get(), Loc, + /*DiscardedValue=*/false); + if (PTExpr.isUsable()) + Prefs.push_back(PTExpr.get()); + else + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + + if (Tok.is(tok::comma)) + ConsumeToken(); + } + PT.consumeClose(); + } + + if (!Prefs.empty()) { + if (Tok.is(tok::comma)) + ConsumeToken(); + else + Diag(Tok, diag::err_omp_expected_punc_after_interop_mod); + } + + // Parse the interop-types. + bool HasError = false; + while (Tok.is(tok::identifier)) { + if (PP.getSpelling(Tok) == "target") { + // OpenMP 5.1 [2.15.1, interop Construct, Restrictions] + // Each interop-type may be specified on an action-clause at most + // once. + if (IsTarget) + Diag(Tok, diag::warn_omp_more_one_interop_type) << "target"; + IsTarget = true; + } else if (PP.getSpelling(Tok) == "targetsync") { + if (IsTargetSync) + Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync"; + IsTargetSync = true; + } else { + HasError = true; + Diag(Tok, diag::err_omp_expected_interop_type); + } + ConsumeToken(); + + if (!Tok.is(tok::comma)) + break; + ConsumeToken(); + } + if (!HasError && !IsTarget && !IsTargetSync) + Diag(Tok, diag::err_omp_expected_interop_type); + + if (Tok.is(tok::colon)) + ConsumeToken(); + else if (IsTarget || IsTargetSync) + Diag(Tok, diag::warn_pragma_expected_colon) << "interop types"; + } + + // Parse the variable. + SourceLocation VarLoc = Tok.getLocation(); + ExprResult InteropVarExpr = + Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + if (!InteropVarExpr.isUsable()) { + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } + + // Parse ')'. + SourceLocation RLoc = Tok.getLocation(); + if (!T.consumeClose()) + RLoc = T.getCloseLocation(); + + if (ParseOnly || !InteropVarExpr.isUsable() || + (Kind == OMPC_init && !IsTarget && !IsTargetSync)) + return nullptr; + + if (Kind == OMPC_init) + return Actions.ActOnOpenMPInitClause(InteropVarExpr.get(), Prefs, IsTarget, + IsTargetSync, Loc, T.getOpenLocation(), + VarLoc, RLoc); + if (Kind == OMPC_use) + return Actions.ActOnOpenMPUseClause(InteropVarExpr.get(), Loc, + T.getOpenLocation(), VarLoc, RLoc); + + if (Kind == OMPC_destroy) + return Actions.ActOnOpenMPDestroyClause(InteropVarExpr.get(), Loc, + T.getOpenLocation(), VarLoc, RLoc); + + llvm_unreachable("Unexpected interop variable clause."); +} + /// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. /// /// default-clause: |