diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:44:14 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:44:14 +0000 |
commit | 2b6b257f4e5503a7a2675bdb8735693db769f75c (patch) | |
tree | e85e046ae7003fe3bcc8b5454cd0fa3f7407b470 /lib/Parse/ParseOpenMP.cpp | |
parent | b4348ed0b7e90c0831b925fbee00b5f179a99796 (diff) |
Notes
Diffstat (limited to 'lib/Parse/ParseOpenMP.cpp')
-rw-r--r-- | lib/Parse/ParseOpenMP.cpp | 1133 |
1 files changed, 921 insertions, 212 deletions
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index a08db5490fa9e..df7d9bc0d8c8c 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -26,78 +26,537 @@ using namespace clang; // OpenMP declarative directives. //===----------------------------------------------------------------------===// +namespace { +enum OpenMPDirectiveKindEx { + OMPD_cancellation = OMPD_unknown + 1, + OMPD_data, + OMPD_declare, + OMPD_end, + OMPD_end_declare, + OMPD_enter, + OMPD_exit, + OMPD_point, + OMPD_reduction, + OMPD_target_enter, + OMPD_target_exit, + OMPD_update, + OMPD_distribute_parallel +}; + +class ThreadprivateListParserHelper final { + SmallVector<Expr *, 4> Identifiers; + Parser *P; + +public: + ThreadprivateListParserHelper(Parser *P) : P(P) {} + void operator()(CXXScopeSpec &SS, DeclarationNameInfo NameInfo) { + ExprResult Res = + P->getActions().ActOnOpenMPIdExpression(P->getCurScope(), SS, NameInfo); + if (Res.isUsable()) + Identifiers.push_back(Res.get()); + } + llvm::ArrayRef<Expr *> getIdentifiers() const { return Identifiers; } +}; +} // namespace + +// Map token string to extended OMP token kind that are +// OpenMPDirectiveKind + OpenMPDirectiveKindEx. +static unsigned getOpenMPDirectiveKindEx(StringRef S) { + auto DKind = getOpenMPDirectiveKind(S); + if (DKind != OMPD_unknown) + return DKind; + + return llvm::StringSwitch<unsigned>(S) + .Case("cancellation", OMPD_cancellation) + .Case("data", OMPD_data) + .Case("declare", OMPD_declare) + .Case("end", OMPD_end) + .Case("enter", OMPD_enter) + .Case("exit", OMPD_exit) + .Case("point", OMPD_point) + .Case("reduction", OMPD_reduction) + .Case("update", OMPD_update) + .Default(OMPD_unknown); +} + static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) { // Array of foldings: F[i][0] F[i][1] ===> F[i][2]. // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd // TODO: add other combined directives in topological order. - const OpenMPDirectiveKind F[][3] = { - {OMPD_unknown /*cancellation*/, OMPD_unknown /*point*/, - OMPD_cancellation_point}, - {OMPD_target, OMPD_unknown /*data*/, OMPD_target_data}, - {OMPD_for, OMPD_simd, OMPD_for_simd}, - {OMPD_parallel, OMPD_for, OMPD_parallel_for}, - {OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd}, - {OMPD_parallel, OMPD_sections, OMPD_parallel_sections}, - {OMPD_taskloop, OMPD_simd, OMPD_taskloop_simd}}; + static const unsigned F[][3] = { + { OMPD_cancellation, OMPD_point, OMPD_cancellation_point }, + { OMPD_declare, OMPD_reduction, OMPD_declare_reduction }, + { OMPD_declare, OMPD_simd, OMPD_declare_simd }, + { OMPD_declare, OMPD_target, OMPD_declare_target }, + { OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel }, + { OMPD_distribute_parallel, OMPD_for, OMPD_distribute_parallel_for }, + { OMPD_distribute_parallel_for, OMPD_simd, + OMPD_distribute_parallel_for_simd }, + { OMPD_distribute, OMPD_simd, OMPD_distribute_simd }, + { OMPD_end, OMPD_declare, OMPD_end_declare }, + { OMPD_end_declare, OMPD_target, OMPD_end_declare_target }, + { OMPD_target, OMPD_data, OMPD_target_data }, + { OMPD_target, OMPD_enter, OMPD_target_enter }, + { OMPD_target, OMPD_exit, OMPD_target_exit }, + { OMPD_target, OMPD_update, OMPD_target_update }, + { OMPD_target_enter, OMPD_data, OMPD_target_enter_data }, + { OMPD_target_exit, OMPD_data, OMPD_target_exit_data }, + { OMPD_for, OMPD_simd, OMPD_for_simd }, + { OMPD_parallel, OMPD_for, OMPD_parallel_for }, + { OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd }, + { OMPD_parallel, OMPD_sections, OMPD_parallel_sections }, + { OMPD_taskloop, OMPD_simd, OMPD_taskloop_simd }, + { OMPD_target, OMPD_parallel, OMPD_target_parallel }, + { OMPD_target_parallel, OMPD_for, OMPD_target_parallel_for }, + { OMPD_target_parallel_for, OMPD_simd, OMPD_target_parallel_for_simd } + }; + enum { CancellationPoint = 0, DeclareReduction = 1, TargetData = 2 }; auto Tok = P.getCurToken(); - auto DKind = + unsigned DKind = Tok.isAnnotation() - ? OMPD_unknown - : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok)); + ? static_cast<unsigned>(OMPD_unknown) + : getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok)); + if (DKind == OMPD_unknown) + return OMPD_unknown; - bool TokenMatched = false; for (unsigned i = 0; i < llvm::array_lengthof(F); ++i) { - if (!Tok.isAnnotation() && DKind == OMPD_unknown) { - TokenMatched = - (i == 0) && - !P.getPreprocessor().getSpelling(Tok).compare("cancellation"); + if (DKind != F[i][0]) + continue; + + Tok = P.getPreprocessor().LookAhead(0); + unsigned SDKind = + Tok.isAnnotation() + ? static_cast<unsigned>(OMPD_unknown) + : getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok)); + if (SDKind == OMPD_unknown) + continue; + + if (SDKind == F[i][1]) { + P.ConsumeToken(); + DKind = F[i][2]; + } + } + return DKind < OMPD_unknown ? static_cast<OpenMPDirectiveKind>(DKind) + : OMPD_unknown; +} + +static DeclarationName parseOpenMPReductionId(Parser &P) { + Token Tok = P.getCurToken(); + Sema &Actions = P.getActions(); + OverloadedOperatorKind OOK = OO_None; + // Allow to use 'operator' keyword for C++ operators + bool WithOperator = false; + if (Tok.is(tok::kw_operator)) { + P.ConsumeToken(); + Tok = P.getCurToken(); + WithOperator = true; + } + switch (Tok.getKind()) { + case tok::plus: // '+' + OOK = OO_Plus; + break; + case tok::minus: // '-' + OOK = OO_Minus; + break; + case tok::star: // '*' + OOK = OO_Star; + break; + case tok::amp: // '&' + OOK = OO_Amp; + break; + case tok::pipe: // '|' + OOK = OO_Pipe; + break; + case tok::caret: // '^' + OOK = OO_Caret; + break; + case tok::ampamp: // '&&' + OOK = OO_AmpAmp; + break; + case tok::pipepipe: // '||' + OOK = OO_PipePipe; + break; + case tok::identifier: // identifier + if (!WithOperator) + break; + default: + P.Diag(Tok.getLocation(), diag::err_omp_expected_reduction_identifier); + P.SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + Parser::StopBeforeMatch); + return DeclarationName(); + } + P.ConsumeToken(); + auto &DeclNames = Actions.getASTContext().DeclarationNames; + return OOK == OO_None ? DeclNames.getIdentifier(Tok.getIdentifierInfo()) + : DeclNames.getCXXOperatorName(OOK); +} + +/// \brief Parse 'omp declare reduction' construct. +/// +/// declare-reduction-directive: +/// annot_pragma_openmp 'declare' 'reduction' +/// '(' <reduction_id> ':' <type> {',' <type>} ':' <expression> ')' +/// ['initializer' '(' ('omp_priv' '=' <expression>)|<function_call> ')'] +/// annot_pragma_openmp_end +/// <reduction_id> is either a base language identifier or one of the following +/// operators: '+', '-', '*', '&', '|', '^', '&&' and '||'. +/// +Parser::DeclGroupPtrTy +Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPDirectiveName(OMPD_declare_reduction))) { + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + return DeclGroupPtrTy(); + } + + DeclarationName Name = parseOpenMPReductionId(*this); + if (Name.isEmpty() && Tok.is(tok::annot_pragma_openmp_end)) + return DeclGroupPtrTy(); + + // Consume ':'. + bool IsCorrect = !ExpectAndConsume(tok::colon); + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return DeclGroupPtrTy(); + + IsCorrect = IsCorrect && !Name.isEmpty(); + + if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_expected_type); + IsCorrect = false; + } + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return DeclGroupPtrTy(); + + SmallVector<std::pair<QualType, SourceLocation>, 8> ReductionTypes; + // Parse list of types until ':' token. + do { + ColonProtectionRAIIObject ColonRAII(*this); + SourceRange Range; + TypeResult TR = ParseTypeName(&Range, Declarator::PrototypeContext, AS); + if (TR.isUsable()) { + auto ReductionType = + Actions.ActOnOpenMPDeclareReductionType(Range.getBegin(), TR); + if (!ReductionType.isNull()) { + ReductionTypes.push_back( + std::make_pair(ReductionType, Range.getBegin())); + } } else { - TokenMatched = DKind == F[i][0] && DKind != OMPD_unknown; + SkipUntil(tok::comma, tok::colon, tok::annot_pragma_openmp_end, + StopBeforeMatch); } - if (TokenMatched) { - Tok = P.getPreprocessor().LookAhead(0); - auto TokenIsAnnotation = Tok.isAnnotation(); - auto SDKind = - TokenIsAnnotation - ? OMPD_unknown - : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok)); - - if (!TokenIsAnnotation && SDKind == OMPD_unknown) { - TokenMatched = - ((i == 0) && - !P.getPreprocessor().getSpelling(Tok).compare("point")) || - ((i == 1) && !P.getPreprocessor().getSpelling(Tok).compare("data")); - } else { - TokenMatched = SDKind == F[i][1] && SDKind != OMPD_unknown; + if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) + break; + + // Consume ','. + if (ExpectAndConsume(tok::comma)) { + IsCorrect = false; + if (Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_expected_type); + return DeclGroupPtrTy(); } + } + } while (Tok.isNot(tok::annot_pragma_openmp_end)); - if (TokenMatched) { - P.ConsumeToken(); - DKind = F[i][2]; + if (ReductionTypes.empty()) { + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + return DeclGroupPtrTy(); + } + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return DeclGroupPtrTy(); + + // Consume ':'. + if (ExpectAndConsume(tok::colon)) + IsCorrect = false; + + if (Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_expected_expression); + return DeclGroupPtrTy(); + } + + DeclGroupPtrTy DRD = Actions.ActOnOpenMPDeclareReductionDirectiveStart( + getCurScope(), Actions.getCurLexicalContext(), Name, ReductionTypes, AS); + + // Parse <combiner> expression and then parse initializer if any for each + // correct type. + unsigned I = 0, E = ReductionTypes.size(); + for (auto *D : DRD.get()) { + TentativeParsingAction TPA(*this); + ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope | + Scope::OpenMPDirectiveScope); + // Parse <combiner> expression. + Actions.ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D); + ExprResult CombinerResult = + Actions.ActOnFinishFullExpr(ParseAssignmentExpression().get(), + D->getLocation(), /*DiscardedValue=*/true); + Actions.ActOnOpenMPDeclareReductionCombinerEnd(D, CombinerResult.get()); + + if (CombinerResult.isInvalid() && Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { + TPA.Commit(); + IsCorrect = false; + break; + } + IsCorrect = !T.consumeClose() && IsCorrect && CombinerResult.isUsable(); + ExprResult InitializerResult; + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + // Parse <initializer> expression. + if (Tok.is(tok::identifier) && + Tok.getIdentifierInfo()->isStr("initializer")) + ConsumeToken(); + else { + Diag(Tok.getLocation(), diag::err_expected) << "'initializer'"; + TPA.Commit(); + IsCorrect = false; + break; + } + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + IsCorrect = + !T.expectAndConsume(diag::err_expected_lparen_after, "initializer") && + IsCorrect; + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope | + Scope::OpenMPDirectiveScope); + // Parse expression. + Actions.ActOnOpenMPDeclareReductionInitializerStart(getCurScope(), D); + InitializerResult = Actions.ActOnFinishFullExpr( + ParseAssignmentExpression().get(), D->getLocation(), + /*DiscardedValue=*/true); + Actions.ActOnOpenMPDeclareReductionInitializerEnd( + D, InitializerResult.get()); + if (InitializerResult.isInvalid() && Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { + TPA.Commit(); + IsCorrect = false; + break; + } + IsCorrect = + !T.consumeClose() && IsCorrect && !InitializerResult.isInvalid(); } } + + ++I; + // Revert parsing if not the last type, otherwise accept it, we're done with + // parsing. + if (I != E) + TPA.Revert(); + else + TPA.Commit(); } - return DKind; + return Actions.ActOnOpenMPDeclareReductionDirectiveEnd(getCurScope(), DRD, + IsCorrect); +} + +namespace { +/// RAII that recreates function context for correct parsing of clauses of +/// 'declare simd' construct. +/// OpenMP, 2.8.2 declare simd Construct +/// The expressions appearing in the clauses of this directive are evaluated in +/// the scope of the arguments of the function declaration or definition. +class FNContextRAII final { + Parser &P; + Sema::CXXThisScopeRAII *ThisScope; + Parser::ParseScope *TempScope; + Parser::ParseScope *FnScope; + bool HasTemplateScope = false; + bool HasFunScope = false; + FNContextRAII() = delete; + FNContextRAII(const FNContextRAII &) = delete; + FNContextRAII &operator=(const FNContextRAII &) = delete; + +public: + FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr) : P(P) { + Decl *D = *Ptr.get().begin(); + NamedDecl *ND = dyn_cast<NamedDecl>(D); + RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext()); + Sema &Actions = P.getActions(); + + // Allow 'this' within late-parsed attributes. + ThisScope = new Sema::CXXThisScopeRAII(Actions, RD, /*TypeQuals=*/0, + ND && ND->isCXXInstanceMember()); + + // If the Decl is templatized, add template parameters to scope. + HasTemplateScope = D->isTemplateDecl(); + TempScope = + new Parser::ParseScope(&P, Scope::TemplateParamScope, HasTemplateScope); + if (HasTemplateScope) + Actions.ActOnReenterTemplateScope(Actions.getCurScope(), D); + + // If the Decl is on a function, add function parameters to the scope. + HasFunScope = D->isFunctionOrFunctionTemplate(); + FnScope = new Parser::ParseScope(&P, Scope::FnScope | Scope::DeclScope, + HasFunScope); + if (HasFunScope) + Actions.ActOnReenterFunctionContext(Actions.getCurScope(), D); + } + ~FNContextRAII() { + if (HasFunScope) { + P.getActions().ActOnExitFunctionContext(); + FnScope->Exit(); // Pop scope, and remove Decls from IdResolver + } + if (HasTemplateScope) + TempScope->Exit(); + delete FnScope; + delete TempScope; + delete ThisScope; + } +}; +} // namespace + +/// Parses clauses for 'declare simd' directive. +/// clause: +/// 'inbranch' | 'notinbranch' +/// 'simdlen' '(' <expr> ')' +/// { 'uniform' '(' <argument_list> ')' } +/// { 'aligned '(' <argument_list> [ ':' <alignment> ] ')' } +/// { 'linear '(' <argument_list> [ ':' <step> ] ')' } +static bool parseDeclareSimdClauses( + Parser &P, OMPDeclareSimdDeclAttr::BranchStateTy &BS, ExprResult &SimdLen, + SmallVectorImpl<Expr *> &Uniforms, SmallVectorImpl<Expr *> &Aligneds, + SmallVectorImpl<Expr *> &Alignments, SmallVectorImpl<Expr *> &Linears, + SmallVectorImpl<unsigned> &LinModifiers, SmallVectorImpl<Expr *> &Steps) { + SourceRange BSRange; + const Token &Tok = P.getCurToken(); + bool IsError = false; + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + if (Tok.isNot(tok::identifier)) + break; + OMPDeclareSimdDeclAttr::BranchStateTy Out; + IdentifierInfo *II = Tok.getIdentifierInfo(); + StringRef ClauseName = II->getName(); + // Parse 'inranch|notinbranch' clauses. + if (OMPDeclareSimdDeclAttr::ConvertStrToBranchStateTy(ClauseName, Out)) { + if (BS != OMPDeclareSimdDeclAttr::BS_Undefined && BS != Out) { + P.Diag(Tok, diag::err_omp_declare_simd_inbranch_notinbranch) + << ClauseName + << OMPDeclareSimdDeclAttr::ConvertBranchStateTyToStr(BS) << BSRange; + IsError = true; + } + BS = Out; + BSRange = SourceRange(Tok.getLocation(), Tok.getEndLoc()); + P.ConsumeToken(); + } else if (ClauseName.equals("simdlen")) { + if (SimdLen.isUsable()) { + P.Diag(Tok, diag::err_omp_more_one_clause) + << getOpenMPDirectiveName(OMPD_declare_simd) << ClauseName << 0; + IsError = true; + } + P.ConsumeToken(); + SourceLocation RLoc; + SimdLen = P.ParseOpenMPParensExpr(ClauseName, RLoc); + if (SimdLen.isInvalid()) + IsError = true; + } else { + OpenMPClauseKind CKind = getOpenMPClauseKind(ClauseName); + if (CKind == OMPC_uniform || CKind == OMPC_aligned || + CKind == OMPC_linear) { + Parser::OpenMPVarListDataTy Data; + auto *Vars = &Uniforms; + if (CKind == OMPC_aligned) + Vars = &Aligneds; + else if (CKind == OMPC_linear) + Vars = &Linears; + + P.ConsumeToken(); + if (P.ParseOpenMPVarList(OMPD_declare_simd, + getOpenMPClauseKind(ClauseName), *Vars, Data)) + IsError = true; + if (CKind == OMPC_aligned) + Alignments.append(Aligneds.size() - Alignments.size(), Data.TailExpr); + else if (CKind == OMPC_linear) { + if (P.getActions().CheckOpenMPLinearModifier(Data.LinKind, + Data.DepLinMapLoc)) + Data.LinKind = OMPC_LINEAR_val; + LinModifiers.append(Linears.size() - LinModifiers.size(), + Data.LinKind); + Steps.append(Linears.size() - Steps.size(), Data.TailExpr); + } + } else + // TODO: add parsing of other clauses. + break; + } + // Skip ',' if any. + if (Tok.is(tok::comma)) + P.ConsumeToken(); + } + return IsError; +} + +/// Parse clauses for '#pragma omp declare simd'. +Parser::DeclGroupPtrTy +Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr, + CachedTokens &Toks, SourceLocation Loc) { + PP.EnterToken(Tok); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); + // Consume the previously pushed token. + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); + + FNContextRAII FnContext(*this, Ptr); + OMPDeclareSimdDeclAttr::BranchStateTy BS = + OMPDeclareSimdDeclAttr::BS_Undefined; + ExprResult Simdlen; + SmallVector<Expr *, 4> Uniforms; + SmallVector<Expr *, 4> Aligneds; + SmallVector<Expr *, 4> Alignments; + SmallVector<Expr *, 4> Linears; + SmallVector<unsigned, 4> LinModifiers; + SmallVector<Expr *, 4> Steps; + bool IsError = + parseDeclareSimdClauses(*this, BS, Simdlen, Uniforms, Aligneds, + Alignments, Linears, LinModifiers, Steps); + // Need to check for extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_simd); + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + } + // Skip the last annot_pragma_openmp_end. + SourceLocation EndLoc = ConsumeToken(); + if (!IsError) { + return Actions.ActOnOpenMPDeclareSimdDirective( + Ptr, BS, Simdlen.get(), Uniforms, Aligneds, Alignments, Linears, + LinModifiers, Steps, SourceRange(Loc, EndLoc)); + } + return Ptr; } /// \brief Parsing of declarative OpenMP directives. /// /// threadprivate-directive: /// annot_pragma_openmp 'threadprivate' simple-variable-list +/// annot_pragma_openmp_end +/// +/// declare-reduction-directive: +/// annot_pragma_openmp 'declare' 'reduction' [...] +/// annot_pragma_openmp_end +/// +/// declare-simd-directive: +/// annot_pragma_openmp 'declare simd' {<clause> [,]} +/// annot_pragma_openmp_end +/// <function declaration/definition> /// -Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { +Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( + AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, + DeclSpec::TST TagType, Decl *Tag) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); ParenBraceBracketBalancer BalancerRAIIObj(*this); SourceLocation Loc = ConsumeToken(); - SmallVector<Expr *, 5> Identifiers; auto DKind = ParseOpenMPDirectiveKind(*this); switch (DKind) { - case OMPD_threadprivate: + case OMPD_threadprivate: { ConsumeToken(); - if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) { + ThreadprivateListParserHelper Helper(this); + if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Helper, true)) { // The last seen token is annot_pragma_openmp_end - need to check for // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { @@ -107,9 +566,140 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { } // Skip the last annot_pragma_openmp_end. ConsumeToken(); - return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers); + return Actions.ActOnOpenMPThreadprivateDirective(Loc, + Helper.getIdentifiers()); + } + break; + } + case OMPD_declare_reduction: + ConsumeToken(); + if (auto Res = ParseOpenMPDeclareReductionDirective(AS)) { + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_reduction); + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + } + // Skip the last annot_pragma_openmp_end. + ConsumeToken(); + return Res; } break; + case OMPD_declare_simd: { + // The syntax is: + // { #pragma omp declare simd } + // <function-declaration-or-definition> + // + ConsumeToken(); + CachedTokens Toks; + while(Tok.isNot(tok::annot_pragma_openmp_end)) { + Toks.push_back(Tok); + ConsumeAnyToken(); + } + Toks.push_back(Tok); + ConsumeAnyToken(); + + DeclGroupPtrTy Ptr; + if (Tok.is(tok::annot_pragma_openmp)) + Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, TagType, Tag); + else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) { + // Here we expect to see some function declaration. + if (AS == AS_none) { + assert(TagType == DeclSpec::TST_unspecified); + MaybeParseCXX11Attributes(Attrs); + MaybeParseMicrosoftAttributes(Attrs); + ParsingDeclSpec PDS(*this); + Ptr = ParseExternalDeclaration(Attrs, &PDS); + } else { + Ptr = + ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag); + } + } + if (!Ptr) { + Diag(Loc, diag::err_omp_decl_in_declare_simd); + return DeclGroupPtrTy(); + } + return ParseOMPDeclareSimdClauses(Ptr, Toks, Loc); + } + case OMPD_declare_target: { + SourceLocation DTLoc = ConsumeAnyToken(); + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + // OpenMP 4.5 syntax with list of entities. + llvm::SmallSetVector<const NamedDecl*, 16> SameDirectiveDecls; + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OMPDeclareTargetDeclAttr::MapTypeTy MT = + OMPDeclareTargetDeclAttr::MT_To; + if (Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + StringRef ClauseName = II->getName(); + // Parse 'to|link' clauses. + if (!OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, + MT)) { + Diag(Tok, diag::err_omp_declare_target_unexpected_clause) + << ClauseName; + break; + } + ConsumeToken(); + } + auto Callback = [this, MT, &SameDirectiveDecls]( + CXXScopeSpec &SS, DeclarationNameInfo NameInfo) { + Actions.ActOnOpenMPDeclareTargetName(getCurScope(), SS, NameInfo, MT, + SameDirectiveDecls); + }; + if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback, true)) + break; + + // Consume optional ','. + if (Tok.is(tok::comma)) + ConsumeToken(); + } + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + ConsumeAnyToken(); + return DeclGroupPtrTy(); + } + + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + + if (!Actions.ActOnStartOpenMPDeclareTargetDirective(DTLoc)) + return DeclGroupPtrTy(); + + DKind = ParseOpenMPDirectiveKind(*this); + while (DKind != OMPD_end_declare_target && DKind != OMPD_declare_target && + Tok.isNot(tok::eof) && Tok.isNot(tok::r_brace)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX11Attributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + ParseExternalDeclaration(attrs); + if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) { + TentativeParsingAction TPA(*this); + ConsumeToken(); + DKind = ParseOpenMPDirectiveKind(*this); + if (DKind != OMPD_end_declare_target) + TPA.Revert(); + else + TPA.Commit(); + } + } + + if (DKind == OMPD_end_declare_target) { + ConsumeAnyToken(); + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_end_declare_target); + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + } + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + } else { + Diag(Tok, diag::err_expected_end_declare_target); + Diag(DTLoc, diag::note_matching) << "'#pragma omp declare target'"; + } + Actions.ActOnFinishOpenMPDeclareTargetDirective(); + return DeclGroupPtrTy(); + } case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; @@ -138,15 +728,27 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { case OMPD_cancellation_point: case OMPD_cancel: case OMPD_target_data: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target_parallel: + case OMPD_target_parallel_for: case OMPD_taskloop: case OMPD_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: + case OMPD_distribute_simd: + case OMPD_target_parallel_for_simd: Diag(Tok, diag::err_omp_unexpected_directive) << getOpenMPDirectiveName(DKind); break; } - SkipUntil(tok::annot_pragma_openmp_end); - return DeclGroupPtrTy(); + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + ConsumeAnyToken(); + return nullptr; } /// \brief Parsing of declarative or executable OpenMP directives. @@ -155,21 +757,30 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { /// annot_pragma_openmp 'threadprivate' simple-variable-list /// annot_pragma_openmp_end /// +/// declare-reduction-directive: +/// annot_pragma_openmp 'declare' 'reduction' '(' <reduction_id> ':' +/// <type> {',' <type>} ':' <expression> ')' ['initializer' '(' +/// ('omp_priv' '=' <expression>|<function_call>) ')'] +/// annot_pragma_openmp_end +/// /// executable-directive: /// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' | /// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] | /// 'parallel for' | 'parallel sections' | 'task' | 'taskyield' | /// 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'atomic' | /// 'for simd' | 'parallel for simd' | 'target' | 'target data' | -/// 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' {clause} | -/// 'distribute' +/// 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' | +/// 'distribute' | 'target enter data' | 'target exit data' | +/// 'target parallel' | 'target parallel for' | +/// 'target update' | 'distribute parallel for' | +/// 'distribute paralle for simd' | 'distribute simd' | +/// 'target parallel for simd' {clause} /// annot_pragma_openmp_end /// StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( AllowedContsructsKind Allowed) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); ParenBraceBracketBalancer BalancerRAIIObj(*this); - SmallVector<Expr *, 5> Identifiers; SmallVector<OMPClause *, 5> Clauses; SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1> FirstClauses(OMPC_unknown + 1); @@ -185,13 +796,14 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( bool FlushHasClause = false; switch (DKind) { - case OMPD_threadprivate: + case OMPD_threadprivate: { if (Allowed != ACK_Any) { Diag(Tok, diag::err_omp_immediate_directive) << getOpenMPDirectiveName(DKind) << 0; } ConsumeToken(); - if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) { + ThreadprivateListParserHelper Helper(this); + if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Helper, false)) { // The last seen token is annot_pragma_openmp_end - need to check for // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { @@ -199,12 +811,29 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( << getOpenMPDirectiveName(OMPD_threadprivate); SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); } - DeclGroupPtrTy Res = - Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers); + DeclGroupPtrTy Res = Actions.ActOnOpenMPThreadprivateDirective( + Loc, Helper.getIdentifiers()); Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); } SkipUntil(tok::annot_pragma_openmp_end); break; + } + case OMPD_declare_reduction: + ConsumeToken(); + if (auto Res = ParseOpenMPDeclareReductionDirective(/*AS=*/AS_none)) { + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_reduction); + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + } + ConsumeAnyToken(); + Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); + } else + SkipUntil(tok::annot_pragma_openmp_end); + break; case OMPD_flush: if (PP.LookAhead(0).is(tok::l_paren)) { FlushHasClause = true; @@ -217,6 +846,9 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_cancel: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target_update: if (Allowed == ACK_StatementsOpenMPNonStandalone) { Diag(Tok, diag::err_omp_immediate_directive) << getOpenMPDirectiveName(DKind) << 0; @@ -242,9 +874,15 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( case OMPD_teams: case OMPD_taskgroup: case OMPD_target_data: + case OMPD_target_parallel: + case OMPD_target_parallel_for: case OMPD_taskloop: case OMPD_taskloop_simd: - case OMPD_distribute: { + case OMPD_distribute: + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + case OMPD_distribute_simd: + case OMPD_target_parallel_for_simd: { ConsumeToken(); // Parse directive name of the 'critical' directive if any. if (DKind == OMPD_critical) { @@ -331,6 +969,13 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( OMPDirectiveScope.Exit(); break; } + case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: + Diag(Tok, diag::err_omp_unexpected_directive) + << getOpenMPDirectiveName(DKind); + SkipUntil(tok::annot_pragma_openmp_end); + break; case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); SkipUntil(tok::annot_pragma_openmp_end); @@ -339,16 +984,15 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( return Directive; } -/// \brief Parses list of simple variables for '#pragma omp threadprivate' -/// directive. -/// -/// simple-variable-list: -/// '(' id-expression {, id-expression} ')' -/// -bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, - SmallVectorImpl<Expr *> &VarList, - bool AllowScopeSpecifier) { - VarList.clear(); +// Parses simple list: +// simple-variable-list: +// '(' id-expression {, id-expression} ')' +// +bool Parser::ParseOpenMPSimpleVarList( + OpenMPDirectiveKind Kind, + const llvm::function_ref<void(CXXScopeSpec &, DeclarationNameInfo)> & + Callback, + bool AllowScopeSpecifier) { // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, @@ -367,11 +1011,11 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, NoIdentIsFound = false; if (AllowScopeSpecifier && getLangOpts().CPlusPlus && - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) { + ParseOptionalCXXScopeSpecifier(SS, nullptr, false)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); - } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(), + } else if (ParseUnqualifiedId(SS, false, false, false, nullptr, TemplateKWLoc, Name)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, @@ -385,11 +1029,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, << tok::identifier << SourceRange(PrevTok.getLocation(), PrevTokLocation); } else { - DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name); - ExprResult Res = - Actions.ActOnOpenMPIdExpression(getCurScope(), SS, NameInfo); - if (Res.isUsable()) - VarList.push_back(Res.get()); + Callback(SS, Actions.GetNameFromUnqualifiedId(Name)); } // Consume ','. if (Tok.is(tok::comma)) { @@ -405,7 +1045,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, // Parse ')'. IsCorrect = !T.consumeClose() && IsCorrect; - return !IsCorrect && VarList.empty(); + return !IsCorrect; } /// \brief Parsing of OpenMP clauses. @@ -420,7 +1060,8 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, /// update-clause | capture-clause | seq_cst-clause | device-clause | /// simdlen-clause | threads-clause | simd-clause | num_teams-clause | /// thread_limit-clause | priority-clause | grainsize-clause | -/// nogroup-clause | num_tasks-clause | hint-clause +/// nogroup-clause | num_tasks-clause | hint-clause | to-clause | +/// from-clause | is_device_ptr-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { @@ -494,8 +1135,12 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, Clause = ParseOpenMPSimpleClause(CKind); break; case OMPC_schedule: + case OMPC_dist_schedule: + case OMPC_defaultmap: // OpenMP [2.7.1, Restrictions, p. 3] // Only one schedule clause can appear on a loop directive. + // OpenMP [2.10.4, Restrictions, p. 106] + // At most one defaultmap clause can appear on the directive. if (!FirstClause) { Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0; @@ -540,6 +1185,10 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_flush: case OMPC_depend: case OMPC_map: + case OMPC_to: + case OMPC_from: + case OMPC_use_device_ptr: + case OMPC_is_device_ptr: Clause = ParseOpenMPVarListClause(DKind, CKind); break; case OMPC_unknown: @@ -548,6 +1197,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); break; case OMPC_threadprivate: + case OMPC_uniform: Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -556,6 +1206,28 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, return ErrorFound ? nullptr : Clause; } +/// Parses simple expression in parens for single-expression clauses of OpenMP +/// constructs. +/// \param RLoc Returned location of right paren. +ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName, + SourceLocation &RLoc) { + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, ClauseName.data())) + return ExprError(); + + SourceLocation ELoc = Tok.getLocation(); + ExprResult LHS(ParseCastExpression( + /*isUnaryExpression=*/false, /*isAddressOfOperand=*/false, NotTypeCast)); + ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc); + + // Parse ')'. + T.consumeClose(); + + RLoc = T.getCloseLocation(); + return Val; +} + /// \brief Parsing of OpenMP clauses with single expressions like 'final', /// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams', /// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks' or 'hint'. @@ -589,25 +1261,15 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, /// OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) { SourceLocation Loc = ConsumeToken(); + SourceLocation LLoc = Tok.getLocation(); + SourceLocation RLoc; - BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); - if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPClauseName(Kind))) - return nullptr; - - SourceLocation ELoc = Tok.getLocation(); - ExprResult LHS(ParseCastExpression(false, false, NotTypeCast)); - ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); - Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc); - - // Parse ')'. - T.consumeClose(); + ExprResult Val = ParseOpenMPParensExpr(getOpenMPClauseName(Kind), RLoc); if (Val.isInvalid()) return nullptr; - return Actions.ActOnOpenMPSingleExprClause( - Kind, Val.get(), Loc, T.getOpenLocation(), T.getCloseLocation()); + return Actions.ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc, LLoc, RLoc); } /// \brief Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. @@ -685,6 +1347,9 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind) { /// if-clause: /// 'if' '(' [ directive-name-modifier ':' ] expression ')' /// +/// defaultmap: +/// 'defaultmap' '(' modifier ':' kind ')' +/// OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind) { SourceLocation Loc = ConsumeToken(); SourceLocation DelimLoc; @@ -744,6 +1409,35 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind) { Arg[ScheduleKind] == OMPC_SCHEDULE_guided) && Tok.is(tok::comma)) DelimLoc = ConsumeAnyToken(); + } else if (Kind == OMPC_dist_schedule) { + Arg.push_back(getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok))); + KLoc.push_back(Tok.getLocation()); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + if (Arg.back() == OMPC_DIST_SCHEDULE_static && Tok.is(tok::comma)) + DelimLoc = ConsumeAnyToken(); + } else if (Kind == OMPC_defaultmap) { + // Get a defaultmap modifier + Arg.push_back(getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok))); + KLoc.push_back(Tok.getLocation()); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + // Parse ':' + if (Tok.is(tok::colon)) + ConsumeAnyToken(); + else if (Arg.back() != OMPC_DEFAULTMAP_MODIFIER_unknown) + Diag(Tok, diag::warn_pragma_expected_colon) << "defaultmap modifier"; + // Get a defaultmap kind + Arg.push_back(getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok))); + KLoc.push_back(Tok.getLocation()); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); } else { assert(Kind == OMPC_if); KLoc.push_back(Tok.getLocation()); @@ -758,8 +1452,9 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind) { } } - bool NeedAnExpression = - (Kind == OMPC_schedule && DelimLoc.isValid()) || Kind == OMPC_if; + bool NeedAnExpression = (Kind == OMPC_schedule && DelimLoc.isValid()) || + (Kind == OMPC_dist_schedule && DelimLoc.isValid()) || + Kind == OMPC_if; if (NeedAnExpression) { SourceLocation ELoc = Tok.getLocation(); ExprResult LHS(ParseCastExpression(false, false, NotTypeCast)); @@ -820,65 +1515,24 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec, } return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false, /*AllowDestructorName*/ false, - /*AllowConstructorName*/ false, ParsedType(), + /*AllowConstructorName*/ false, nullptr, TemplateKWLoc, ReductionId); } -/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate', -/// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'. -/// -/// private-clause: -/// 'private' '(' list ')' -/// firstprivate-clause: -/// 'firstprivate' '(' list ')' -/// lastprivate-clause: -/// 'lastprivate' '(' list ')' -/// shared-clause: -/// 'shared' '(' list ')' -/// linear-clause: -/// 'linear' '(' linear-list [ ':' linear-step ] ')' -/// aligned-clause: -/// 'aligned' '(' list [ ':' alignment ] ')' -/// reduction-clause: -/// 'reduction' '(' reduction-identifier ':' list ')' -/// copyprivate-clause: -/// 'copyprivate' '(' list ')' -/// flush-clause: -/// 'flush' '(' list ')' -/// depend-clause: -/// 'depend' '(' in | out | inout : list | source ')' -/// map-clause: -/// 'map' '(' [ [ always , ] -/// to | from | tofrom | alloc | release | delete ':' ] list ')'; -/// -/// For 'linear' clause linear-list may have the following forms: -/// list -/// modifier(list) -/// where modifier is 'val' (C) or 'ref', 'val' or 'uval'(C++). -OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, - OpenMPClauseKind Kind) { - SourceLocation Loc = Tok.getLocation(); - SourceLocation LOpen = ConsumeToken(); - SourceLocation ColonLoc = SourceLocation(); - // Optional scope specifier and unqualified id for reduction identifier. - CXXScopeSpec ReductionIdScopeSpec; - UnqualifiedId ReductionId; +/// Parses clauses with list. +bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, + OpenMPClauseKind Kind, + SmallVectorImpl<Expr *> &Vars, + OpenMPVarListDataTy &Data) { + UnqualifiedId UnqualifiedReductionId; bool InvalidReductionId = false; - OpenMPDependClauseKind DepKind = OMPC_DEPEND_unknown; - // OpenMP 4.1 [2.15.3.7, linear Clause] - // If no modifier is specified it is assumed to be val. - OpenMPLinearClauseKind LinearModifier = OMPC_LINEAR_val; - OpenMPMapClauseKind MapType = OMPC_MAP_unknown; - OpenMPMapClauseKind MapTypeModifier = OMPC_MAP_unknown; bool MapTypeModifierSpecified = false; - bool UnexpectedId = false; - SourceLocation DepLinMapLoc; // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, getOpenMPClauseName(Kind))) - return nullptr; + return true; bool NeedRParenForLinear = false; BalancedDelimiterTracker LinearT(*this, tok::l_paren, @@ -886,46 +1540,46 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, // Handle reduction-identifier for reduction clause. if (Kind == OMPC_reduction) { ColonProtectionRAIIObject ColonRAII(*this); - if (getLangOpts().CPlusPlus) { - ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec, ParsedType(), false); - } - InvalidReductionId = - ParseReductionId(*this, ReductionIdScopeSpec, ReductionId); + if (getLangOpts().CPlusPlus) + ParseOptionalCXXScopeSpecifier(Data.ReductionIdScopeSpec, + /*ObjectType=*/nullptr, + /*EnteringContext=*/false); + InvalidReductionId = ParseReductionId(*this, Data.ReductionIdScopeSpec, + UnqualifiedReductionId); if (InvalidReductionId) { SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } - if (Tok.is(tok::colon)) { - ColonLoc = ConsumeToken(); - } else { + if (Tok.is(tok::colon)) + Data.ColonLoc = ConsumeToken(); + else Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier"; - } + if (!InvalidReductionId) + Data.ReductionId = + Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId); } else if (Kind == OMPC_depend) { // Handle dependency type for depend clause. ColonProtectionRAIIObject ColonRAII(*this); - DepKind = static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType( - Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); - DepLinMapLoc = Tok.getLocation(); + Data.DepKind = + static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType( + Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); + Data.DepLinMapLoc = Tok.getLocation(); - if (DepKind == OMPC_DEPEND_unknown) { + if (Data.DepKind == OMPC_DEPEND_unknown) { SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } else { ConsumeToken(); // Special processing for depend(source) clause. - if (DKind == OMPD_ordered && DepKind == OMPC_DEPEND_source) { + if (DKind == OMPD_ordered && Data.DepKind == OMPC_DEPEND_source) { // Parse ')'. T.consumeClose(); - return Actions.ActOnOpenMPVarListClause( - Kind, llvm::None, /*TailExpr=*/nullptr, Loc, LOpen, - /*ColonLoc=*/SourceLocation(), Tok.getLocation(), - ReductionIdScopeSpec, DeclarationNameInfo(), DepKind, - LinearModifier, MapTypeModifier, MapType, DepLinMapLoc); + return false; } } - if (Tok.is(tok::colon)) { - ColonLoc = ConsumeToken(); - } else { + if (Tok.is(tok::colon)) + Data.ColonLoc = ConsumeToken(); + else { Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren : diag::warn_pragma_expected_colon) << "dependency type"; @@ -933,9 +1587,9 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, } else if (Kind == OMPC_linear) { // Try to parse modifier if any. if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) { - LinearModifier = static_cast<OpenMPLinearClauseKind>( + Data.LinKind = static_cast<OpenMPLinearClauseKind>( getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok))); - DepLinMapLoc = ConsumeToken(); + Data.DepLinMapLoc = ConsumeToken(); LinearT.consumeOpen(); NeedRParenForLinear = true; } @@ -943,71 +1597,78 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, // Handle map type for map clause. ColonProtectionRAIIObject ColonRAII(*this); - // the first identifier may be a list item, a map-type or - // a map-type-modifier - MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType( - Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); - DepLinMapLoc = Tok.getLocation(); + /// The map clause modifier token can be either a identifier or the C++ + /// delete keyword. + auto &&IsMapClauseModifierToken = [](const Token &Tok) -> bool { + return Tok.isOneOf(tok::identifier, tok::kw_delete); + }; + + // The first identifier may be a list item, a map-type or a + // map-type-modifier. The map modifier can also be delete which has the same + // spelling of the C++ delete keyword. + Data.MapType = + IsMapClauseModifierToken(Tok) + ? static_cast<OpenMPMapClauseKind>( + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok))) + : OMPC_MAP_unknown; + Data.DepLinMapLoc = Tok.getLocation(); bool ColonExpected = false; - if (Tok.is(tok::identifier)) { + if (IsMapClauseModifierToken(Tok)) { if (PP.LookAhead(0).is(tok::colon)) { - MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType( - Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); - if (MapType == OMPC_MAP_unknown) { + if (Data.MapType == OMPC_MAP_unknown) Diag(Tok, diag::err_omp_unknown_map_type); - } else if (MapType == OMPC_MAP_always) { + else if (Data.MapType == OMPC_MAP_always) Diag(Tok, diag::err_omp_map_type_missing); - } ConsumeToken(); } else if (PP.LookAhead(0).is(tok::comma)) { - if (PP.LookAhead(1).is(tok::identifier) && + if (IsMapClauseModifierToken(PP.LookAhead(1)) && PP.LookAhead(2).is(tok::colon)) { - MapTypeModifier = - static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType( - Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); - if (MapTypeModifier != OMPC_MAP_always) { + Data.MapTypeModifier = Data.MapType; + if (Data.MapTypeModifier != OMPC_MAP_always) { Diag(Tok, diag::err_omp_unknown_map_type_modifier); - MapTypeModifier = OMPC_MAP_unknown; - } else { + Data.MapTypeModifier = OMPC_MAP_unknown; + } else MapTypeModifierSpecified = true; - } ConsumeToken(); ConsumeToken(); - MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType( - Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); - if (MapType == OMPC_MAP_unknown || MapType == OMPC_MAP_always) { + Data.MapType = + IsMapClauseModifierToken(Tok) + ? static_cast<OpenMPMapClauseKind>( + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok))) + : OMPC_MAP_unknown; + if (Data.MapType == OMPC_MAP_unknown || + Data.MapType == OMPC_MAP_always) Diag(Tok, diag::err_omp_unknown_map_type); - } ConsumeToken(); } else { - MapType = OMPC_MAP_tofrom; + Data.MapType = OMPC_MAP_tofrom; + Data.IsMapTypeImplicit = true; } } else { - MapType = OMPC_MAP_tofrom; + Data.MapType = OMPC_MAP_tofrom; + Data.IsMapTypeImplicit = true; } } else { - UnexpectedId = true; + Data.MapType = OMPC_MAP_tofrom; + Data.IsMapTypeImplicit = true; } - if (Tok.is(tok::colon)) { - ColonLoc = ConsumeToken(); - } else if (ColonExpected) { + if (Tok.is(tok::colon)) + Data.ColonLoc = ConsumeToken(); + else if (ColonExpected) Diag(Tok, diag::warn_pragma_expected_colon) << "map type"; - } } - SmallVector<Expr *, 5> Vars; bool IsComma = - ((Kind != OMPC_reduction) && (Kind != OMPC_depend) && - (Kind != OMPC_map)) || - ((Kind == OMPC_reduction) && !InvalidReductionId) || - ((Kind == OMPC_map) && (UnexpectedId || MapType != OMPC_MAP_unknown) && + (Kind != OMPC_reduction && Kind != OMPC_depend && Kind != OMPC_map) || + (Kind == OMPC_reduction && !InvalidReductionId) || + (Kind == OMPC_map && Data.MapType != OMPC_MAP_unknown && (!MapTypeModifierSpecified || - (MapTypeModifierSpecified && MapTypeModifier == OMPC_MAP_always))) || - ((Kind == OMPC_depend) && DepKind != OMPC_DEPEND_unknown); + Data.MapTypeModifier == OMPC_MAP_always)) || + (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown); const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned); while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) && Tok.isNot(tok::annot_pragma_openmp_end))) { @@ -1015,9 +1676,9 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, // Parse variable ExprResult VarExpr = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); - if (VarExpr.isUsable()) { + if (VarExpr.isUsable()) Vars.push_back(VarExpr.get()); - } else { + else { SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } @@ -1039,15 +1700,14 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, LinearT.consumeClose(); // Parse ':' linear-step (or ':' alignment). - Expr *TailExpr = nullptr; const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon); if (MustHaveTail) { - ColonLoc = Tok.getLocation(); + Data.ColonLoc = Tok.getLocation(); SourceLocation ELoc = ConsumeToken(); ExprResult Tail = ParseAssignmentExpression(); Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc); if (Tail.isUsable()) - TailExpr = Tail.get(); + Data.TailExpr = Tail.get(); else SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -1055,18 +1715,67 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, // Parse ')'. T.consumeClose(); - if ((Kind == OMPC_depend && DepKind != OMPC_DEPEND_unknown && Vars.empty()) || - (Kind != OMPC_depend && Vars.empty()) || (MustHaveTail && !TailExpr) || - (Kind == OMPC_map && MapType == OMPC_MAP_unknown) || - InvalidReductionId) { + if ((Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown && + Vars.empty()) || + (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) || + (MustHaveTail && !Data.TailExpr) || InvalidReductionId) + return true; + return false; +} + +/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate', +/// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'. +/// +/// private-clause: +/// 'private' '(' list ')' +/// firstprivate-clause: +/// 'firstprivate' '(' list ')' +/// lastprivate-clause: +/// 'lastprivate' '(' list ')' +/// shared-clause: +/// 'shared' '(' list ')' +/// linear-clause: +/// 'linear' '(' linear-list [ ':' linear-step ] ')' +/// aligned-clause: +/// 'aligned' '(' list [ ':' alignment ] ')' +/// reduction-clause: +/// 'reduction' '(' reduction-identifier ':' list ')' +/// copyprivate-clause: +/// 'copyprivate' '(' list ')' +/// flush-clause: +/// 'flush' '(' list ')' +/// depend-clause: +/// 'depend' '(' in | out | inout : list | source ')' +/// map-clause: +/// 'map' '(' [ [ always , ] +/// to | from | tofrom | alloc | release | delete ':' ] list ')'; +/// to-clause: +/// 'to' '(' list ')' +/// from-clause: +/// 'from' '(' list ')' +/// use_device_ptr-clause: +/// 'use_device_ptr' '(' list ')' +/// is_device_ptr-clause: +/// 'is_device_ptr' '(' list ')' +/// +/// For 'linear' clause linear-list may have the following forms: +/// list +/// modifier(list) +/// where modifier is 'val' (C) or 'ref', 'val' or 'uval'(C++). +OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, + OpenMPClauseKind Kind) { + SourceLocation Loc = Tok.getLocation(); + SourceLocation LOpen = ConsumeToken(); + SmallVector<Expr *, 4> Vars; + OpenMPVarListDataTy Data; + + if (ParseOpenMPVarList(DKind, Kind, Vars, Data)) return nullptr; - } return Actions.ActOnOpenMPVarListClause( - Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(), - ReductionIdScopeSpec, - ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId) - : DeclarationNameInfo(), - DepKind, LinearModifier, MapTypeModifier, MapType, DepLinMapLoc); + Kind, Vars, Data.TailExpr, Loc, LOpen, Data.ColonLoc, Tok.getLocation(), + Data.ReductionIdScopeSpec, Data.ReductionId, Data.DepKind, Data.LinKind, + Data.MapTypeModifier, Data.MapType, Data.IsMapTypeImplicit, + Data.DepLinMapLoc); } |