diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp | 513 |
1 files changed, 430 insertions, 83 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp index 89e4147..d1544e6 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp @@ -11,19 +11,43 @@ /// //===----------------------------------------------------------------------===// +#include "RAIIObjectsForParser.h" #include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/StmtOpenMP.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Sema/Scope.h" #include "llvm/ADT/PointerIntPair.h" -#include "RAIIObjectsForParser.h" using namespace clang; //===----------------------------------------------------------------------===// // OpenMP declarative directives. //===----------------------------------------------------------------------===// +static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) { + auto Tok = P.getCurToken(); + auto DKind = + Tok.isAnnotation() + ? OMPD_unknown + : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok)); + if (DKind == OMPD_parallel) { + Tok = P.getPreprocessor().LookAhead(0); + auto SDKind = + Tok.isAnnotation() + ? OMPD_unknown + : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok)); + if (SDKind == OMPD_for) { + P.ConsumeToken(); + DKind = OMPD_parallel_for; + } else if (SDKind == OMPD_sections) { + P.ConsumeToken(); + DKind = OMPD_parallel_sections; + } + } + return DKind; +} + /// \brief Parsing of declarative OpenMP directives. /// /// threadprivate-directive: @@ -35,9 +59,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { SourceLocation Loc = ConsumeToken(); SmallVector<Expr *, 5> Identifiers; - OpenMPDirectiveKind DKind = Tok.isAnnotation() ? - OMPD_unknown : - getOpenMPDirectiveKind(PP.getSpelling(Tok)); + auto DKind = ParseOpenMPDirectiveKind(*this); switch (DKind) { case OMPD_threadprivate: @@ -47,23 +69,34 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(OMPD_threadprivate); + << getOpenMPDirectiveName(OMPD_threadprivate); SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); } // Skip the last annot_pragma_openmp_end. ConsumeToken(); - return Actions.ActOnOpenMPThreadprivateDirective(Loc, - Identifiers); + return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers); } break; case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; case OMPD_parallel: + case OMPD_simd: case OMPD_task: - case NUM_OPENMP_DIRECTIVES: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_flush: + case OMPD_for: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_master: + case OMPD_critical: + case OMPD_parallel_for: + case OMPD_parallel_sections: Diag(Tok, diag::err_omp_unexpected_directive) - << getOpenMPDirectiveName(DKind); + << getOpenMPDirectiveName(DKind); break; } SkipUntil(tok::annot_pragma_openmp_end); @@ -76,25 +109,29 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { /// annot_pragma_openmp 'threadprivate' simple-variable-list /// annot_pragma_openmp_end /// -/// parallel-directive: -/// annot_pragma_openmp 'parallel' {clause} 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' {clause} annot_pragma_openmp_end /// -StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() { +StmtResult +Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) { 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>, NUM_OPENMP_CLAUSES> - FirstClauses(NUM_OPENMP_CLAUSES); - const unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | - Scope::OpenMPDirectiveScope; + SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1> + FirstClauses(OMPC_unknown + 1); + unsigned ScopeFlags = + Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope; SourceLocation Loc = ConsumeToken(), EndLoc; - OpenMPDirectiveKind DKind = Tok.isAnnotation() ? - OMPD_unknown : - getOpenMPDirectiveKind(PP.getSpelling(Tok)); + auto DKind = ParseOpenMPDirectiveKind(*this); // Name of critical directive. DeclarationNameInfo DirName; StmtResult Directive = StmtError(); + bool HasAssociatedStatement = true; + bool FlushHasClause = false; switch (DKind) { case OMPD_threadprivate: @@ -104,27 +141,75 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() { // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(OMPD_threadprivate); + << getOpenMPDirectiveName(OMPD_threadprivate); SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); } DeclGroupPtrTy Res = - Actions.ActOnOpenMPThreadprivateDirective(Loc, - Identifiers); + Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers); Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); } SkipUntil(tok::annot_pragma_openmp_end); break; - case OMPD_parallel: { + case OMPD_flush: + if (PP.LookAhead(0).is(tok::l_paren)) { + FlushHasClause = true; + // Push copy of the current token back to stream to properly parse + // pseudo-clause OMPFlushClause. + PP.EnterToken(Tok); + } + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + if (!StandAloneAllowed) { + Diag(Tok, diag::err_omp_immediate_directive) + << getOpenMPDirectiveName(DKind); + } + HasAssociatedStatement = false; + // Fall through for further analysis. + case OMPD_parallel: + case OMPD_simd: + case OMPD_for: + case OMPD_sections: + case OMPD_single: + case OMPD_section: + case OMPD_master: + case OMPD_critical: + case OMPD_parallel_for: + case OMPD_parallel_sections: + case OMPD_task: { ConsumeToken(); + // Parse directive name of the 'critical' directive if any. + if (DKind == OMPD_critical) { + BalancedDelimiterTracker T(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + if (!T.consumeOpen()) { + if (Tok.isAnyIdentifier()) { + DirName = + DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeAnyToken(); + } else { + Diag(Tok, diag::err_omp_expected_identifier_for_critical); + } + T.consumeClose(); + } + } - Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope()); + if (isOpenMPLoopDirective(DKind)) + ScopeFlags |= Scope::OpenMPLoopDirectiveScope; + if (isOpenMPSimdDirective(DKind)) + ScopeFlags |= Scope::OpenMPSimdDirectiveScope; + ParseScope OMPDirectiveScope(this, ScopeFlags); + Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc); while (Tok.isNot(tok::annot_pragma_openmp_end)) { - OpenMPClauseKind CKind = Tok.isAnnotation() ? - OMPC_unknown : - getOpenMPClauseKind(PP.getSpelling(Tok)); - OMPClause *Clause = ParseOpenMPClause(DKind, CKind, - !FirstClauses[CKind].getInt()); + OpenMPClauseKind CKind = + Tok.isAnnotation() + ? OMPC_unknown + : FlushHasClause ? OMPC_flush + : getOpenMPClauseKind(PP.getSpelling(Tok)); + FlushHasClause = false; + OMPClause *Clause = + ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt()); FirstClauses[CKind].setInt(true); if (Clause) { FirstClauses[CKind].setPointer(Clause); @@ -142,11 +227,10 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() { StmtResult AssociatedStmt; bool CreateDirective = true; - ParseScope OMPDirectiveScope(this, ScopeFlags); - { + if (HasAssociatedStatement) { // The body is a block scope like in Lambdas and Blocks. Sema::CompoundScopeRAII CompoundScope(Actions); - Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_OpenMP, 1); + Actions.ActOnOpenMPRegionStart(DKind, getCurScope()); Actions.ActOnStartOfCompoundStmt(); // Parse statement AssociatedStmt = ParseStatement(); @@ -155,30 +239,23 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() { Actions.ActOnCapturedRegionError(); CreateDirective = false; } else { - AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.take()); + AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.get()); CreateDirective = AssociatedStmt.isUsable(); } } if (CreateDirective) - Directive = Actions.ActOnOpenMPExecutableDirective(DKind, Clauses, - AssociatedStmt.take(), - Loc, EndLoc); + Directive = Actions.ActOnOpenMPExecutableDirective( + DKind, DirName, Clauses, AssociatedStmt.get(), Loc, EndLoc); // Exit scope. Actions.EndOpenMPDSABlock(Directive.get()); OMPDirectiveScope.Exit(); - } break; + } case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); SkipUntil(tok::annot_pragma_openmp_end); break; - case OMPD_task: - case NUM_OPENMP_DIRECTIVES: - Diag(Tok, diag::err_omp_unexpected_directive) - << getOpenMPDirectiveName(DKind); - SkipUntil(tok::annot_pragma_openmp_end); - break; } return Directive; } @@ -225,14 +302,15 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); - Diag(PrevTok.getLocation(), diag::err_expected_ident) - << SourceRange(PrevTok.getLocation(), PrevTokLocation); + Diag(PrevTok.getLocation(), diag::err_expected) + << tok::identifier + << SourceRange(PrevTok.getLocation(), PrevTokLocation); } else { DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name); - ExprResult Res = Actions.ActOnOpenMPIdExpression(getCurScope(), SS, - NameInfo); + ExprResult Res = + Actions.ActOnOpenMPIdExpression(getCurScope(), SS, NameInfo); if (Res.isUsable()) - VarList.push_back(Res.take()); + VarList.push_back(Res.get()); } // Consume ','. if (Tok.is(tok::comma)) { @@ -241,7 +319,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, } if (NoIdentIsFound) { - Diag(Tok, diag::err_expected_ident); + Diag(Tok, diag::err_expected) << tok::identifier; IsCorrect = false; } @@ -254,56 +332,159 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, /// \brief Parsing of OpenMP clauses. /// /// clause: -/// default-clause|private-clause|firstprivate-clause|shared-clause +/// if-clause | final-clause | num_threads-clause | safelen-clause | +/// default-clause | private-clause | firstprivate-clause | shared-clause +/// | linear-clause | aligned-clause | collapse-clause | +/// lastprivate-clause | reduction-clause | proc_bind-clause | +/// schedule-clause | copyin-clause | copyprivate-clause | untied-clause | +/// mergeable-clause | flush-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { - OMPClause *Clause = 0; + OMPClause *Clause = nullptr; bool ErrorFound = false; // Check if clause is allowed for the given directive. if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) { - Diag(Tok, diag::err_omp_unexpected_clause) - << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); + Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind) + << getOpenMPDirectiveName(DKind); ErrorFound = true; } switch (CKind) { + case OMPC_if: + case OMPC_final: + case OMPC_num_threads: + case OMPC_safelen: + case OMPC_collapse: + // OpenMP [2.5, Restrictions] + // At most one if clause can appear on the directive. + // At most one num_threads clause can appear on the directive. + // OpenMP [2.8.1, simd construct, Restrictions] + // Only one safelen clause can appear on a simd directive. + // Only one collapse clause can appear on a simd directive. + // OpenMP [2.11.1, task Construct, Restrictions] + // At most one if clause can appear on the directive. + // At most one final clause can appear on the directive. + if (!FirstClause) { + Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(CKind); + } + + Clause = ParseOpenMPSingleExprClause(CKind); + break; case OMPC_default: - // OpenMP [2.9.3.1, Restrictions] - // Only a single default clause may be specified on a parallel or task - // directive. + case OMPC_proc_bind: + // OpenMP [2.14.3.1, Restrictions] + // Only a single default clause may be specified on a parallel, task or + // teams directive. + // OpenMP [2.5, parallel Construct, Restrictions] + // At most one proc_bind clause can appear on the directive. if (!FirstClause) { - Diag(Tok, diag::err_omp_more_one_clause) - << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind); + Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(CKind); } Clause = ParseOpenMPSimpleClause(CKind); break; + case OMPC_schedule: + // OpenMP [2.7.1, Restrictions, p. 3] + // Only one schedule clause can appear on a loop directive. + if (!FirstClause) { + Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(CKind); + } + + Clause = ParseOpenMPSingleExprWithArgClause(CKind); + break; + case OMPC_ordered: + case OMPC_nowait: + case OMPC_untied: + case OMPC_mergeable: + // OpenMP [2.7.1, Restrictions, p. 9] + // Only one ordered clause can appear on a loop directive. + // OpenMP [2.7.1, Restrictions, C/C++, p. 4] + // Only one nowait clause can appear on a for directive. + if (!FirstClause) { + Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(CKind); + } + + Clause = ParseOpenMPClause(CKind); + break; case OMPC_private: case OMPC_firstprivate: + case OMPC_lastprivate: case OMPC_shared: + case OMPC_reduction: + case OMPC_linear: + case OMPC_aligned: + case OMPC_copyin: + case OMPC_copyprivate: + case OMPC_flush: Clause = ParseOpenMPVarListClause(CKind); break; case OMPC_unknown: Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(DKind); + << getOpenMPDirectiveName(DKind); SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); break; case OMPC_threadprivate: - case NUM_OPENMP_CLAUSES: - Diag(Tok, diag::err_omp_unexpected_clause) - << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); + Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind) + << getOpenMPDirectiveName(DKind); SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch); break; } - return ErrorFound ? 0 : Clause; + return ErrorFound ? nullptr : Clause; +} + +/// \brief Parsing of OpenMP clauses with single expressions like 'if', +/// 'final', 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams' or +/// 'thread_limit'. +/// +/// if-clause: +/// 'if' '(' expression ')' +/// +/// final-clause: +/// 'final' '(' expression ')' +/// +/// num_threads-clause: +/// 'num_threads' '(' expression ')' +/// +/// safelen-clause: +/// 'safelen' '(' expression ')' +/// +/// collapse-clause: +/// 'collapse' '(' expression ')' +/// +OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) { + SourceLocation Loc = ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(Kind))) + return nullptr; + + ExprResult LHS(ParseCastExpression(false, false, NotTypeCast)); + ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + + // Parse ')'. + T.consumeClose(); + + if (Val.isInvalid()) + return nullptr; + + return Actions.ActOnOpenMPSingleExprClause( + Kind, Val.get(), Loc, T.getOpenLocation(), T.getCloseLocation()); } -/// \brief Parsing of simple OpenMP clauses like 'default'. +/// \brief Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. /// /// default-clause: /// 'default' '(' 'none' | 'shared' ') /// +/// proc_bind-clause: +/// 'proc_bind' '(' 'master' | 'close' | 'spread' ') +/// OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) { SourceLocation Loc = Tok.getLocation(); SourceLocation LOpen = ConsumeToken(); @@ -311,11 +492,10 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) { BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, getOpenMPClauseName(Kind))) - return 0; + return nullptr; - unsigned Type = Tok.isAnnotation() ? - unsigned(OMPC_DEFAULT_unknown) : - getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + unsigned Type = getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok)); SourceLocation TypeLoc = Tok.getLocation(); if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && Tok.isNot(tok::annot_pragma_openmp_end)) @@ -328,54 +508,221 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) { Tok.getLocation()); } -/// \brief Parsing of OpenMP clause 'private', 'firstprivate', -/// 'shared', 'copyin', or 'reduction'. +/// \brief Parsing of OpenMP clauses like 'ordered'. +/// +/// ordered-clause: +/// 'ordered' +/// +/// nowait-clause: +/// 'nowait' +/// +/// untied-clause: +/// 'untied' +/// +/// mergeable-clause: +/// 'mergeable' +/// +OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind) { + SourceLocation Loc = Tok.getLocation(); + ConsumeAnyToken(); + + return Actions.ActOnOpenMPClause(Kind, Loc, Tok.getLocation()); +} + + +/// \brief Parsing of OpenMP clauses with single expressions and some additional +/// argument like 'schedule' or 'dist_schedule'. +/// +/// schedule-clause: +/// 'schedule' '(' kind [',' expression ] ')' +/// +OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind) { + SourceLocation Loc = ConsumeToken(); + SourceLocation CommaLoc; + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(Kind))) + return nullptr; + + ExprResult Val; + unsigned Type = getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok)); + SourceLocation KLoc = Tok.getLocation(); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + + if (Kind == OMPC_schedule && + (Type == OMPC_SCHEDULE_static || Type == OMPC_SCHEDULE_dynamic || + Type == OMPC_SCHEDULE_guided) && + Tok.is(tok::comma)) { + CommaLoc = ConsumeAnyToken(); + ExprResult LHS(ParseCastExpression(false, false, NotTypeCast)); + Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional); + if (Val.isInvalid()) + return nullptr; + } + + // Parse ')'. + T.consumeClose(); + + return Actions.ActOnOpenMPSingleExprWithArgClause( + Kind, Type, Val.get(), Loc, T.getOpenLocation(), KLoc, CommaLoc, + T.getCloseLocation()); +} + +static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec, + UnqualifiedId &ReductionId) { + SourceLocation TemplateKWLoc; + if (ReductionIdScopeSpec.isEmpty()) { + auto OOK = OO_None; + switch (P.getCurToken().getKind()) { + case tok::plus: + OOK = OO_Plus; + break; + case tok::minus: + OOK = OO_Minus; + break; + case tok::star: + OOK = OO_Star; + break; + case tok::amp: + OOK = OO_Amp; + break; + case tok::pipe: + OOK = OO_Pipe; + break; + case tok::caret: + OOK = OO_Caret; + break; + case tok::ampamp: + OOK = OO_AmpAmp; + break; + case tok::pipepipe: + OOK = OO_PipePipe; + break; + default: + break; + } + if (OOK != OO_None) { + SourceLocation OpLoc = P.ConsumeToken(); + SourceLocation SymbolLocations[] = {OpLoc, OpLoc, SourceLocation()}; + ReductionId.setOperatorFunctionId(OpLoc, OOK, SymbolLocations); + return false; + } + } + return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false, + /*AllowDestructorName*/ false, + /*AllowConstructorName*/ false, ParsedType(), + 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' '(' list [ ':' linear-step ] ')' +/// aligned-clause: +/// 'aligned' '(' list [ ':' alignment ] ')' +/// reduction-clause: +/// 'reduction' '(' reduction-identifier ':' list ')' +/// copyprivate-clause: +/// 'copyprivate' '(' list ')' +/// flush-clause: +/// 'flush' '(' list ')' /// OMPClause *Parser::ParseOpenMPVarListClause(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; + bool InvalidReductionId = false; // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, getOpenMPClauseName(Kind))) - return 0; + return nullptr; + + // 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 (InvalidReductionId) { + SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } + if (Tok.is(tok::colon)) { + ColonLoc = ConsumeToken(); + } else { + Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier"; + } + } SmallVector<Expr *, 5> Vars; - bool IsComma = true; - while (IsComma || (Tok.isNot(tok::r_paren) && + bool IsComma = !InvalidReductionId; + 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))) { + ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail); // Parse variable ExprResult VarExpr = ParseAssignmentExpression(); if (VarExpr.isUsable()) { - Vars.push_back(VarExpr.take()); + Vars.push_back(VarExpr.get()); } else { SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } // Skip ',' if any IsComma = Tok.is(tok::comma); - if (IsComma) { + if (IsComma) ConsumeToken(); - } else if (Tok.isNot(tok::r_paren) && - Tok.isNot(tok::annot_pragma_openmp_end)) { + else if (Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end) && + (!MayHaveTail || Tok.isNot(tok::colon))) Diag(Tok, diag::err_omp_expected_punc) - << 1 << getOpenMPClauseName(Kind); - } + << ((Kind == OMPC_flush) ? getOpenMPDirectiveName(OMPD_flush) + : getOpenMPClauseName(Kind)) + << (Kind == OMPC_flush); + } + + // Parse ':' linear-step (or ':' alignment). + Expr *TailExpr = nullptr; + const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon); + if (MustHaveTail) { + ColonLoc = Tok.getLocation(); + ConsumeToken(); + ExprResult Tail = ParseAssignmentExpression(); + if (Tail.isUsable()) + TailExpr = Tail.get(); + else + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); } // Parse ')'. T.consumeClose(); - if (Vars.empty()) - return 0; + if (Vars.empty() || (MustHaveTail && !TailExpr) || InvalidReductionId) + return nullptr; - return Actions.ActOnOpenMPVarListClause(Kind, Vars, Loc, LOpen, - Tok.getLocation()); + return Actions.ActOnOpenMPVarListClause( + Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(), + ReductionIdScopeSpec, + ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId) + : DeclarationNameInfo()); } |