123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819 |
- //===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===//
- //
- // The LLVM Compiler Infrastructure
- //
- // This file is distributed under the University of Illinois Open Source
- // License. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- /// \file
- /// \brief This file implements parsing of all OpenMP directives and clauses.
- ///
- //===----------------------------------------------------------------------===//
- #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"
- using namespace clang;
- //===----------------------------------------------------------------------===//
- // OpenMP declarative directives.
- //===----------------------------------------------------------------------===//
- 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_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}};
- auto Tok = P.getCurToken();
- auto DKind =
- Tok.isAnnotation()
- ? OMPD_unknown
- : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
- 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");
- } else {
- TokenMatched = DKind == F[i][0] && DKind != OMPD_unknown;
- }
- if (TokenMatched) {
- Tok = P.getPreprocessor().LookAhead(0);
- auto SDKind =
- Tok.isAnnotation()
- ? OMPD_unknown
- : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
- if (!Tok.isAnnotation() && DKind == OMPD_unknown) {
- TokenMatched =
- (i == 0) && !P.getPreprocessor().getSpelling(Tok).compare("point");
- } else {
- TokenMatched = SDKind == F[i][1] && SDKind != OMPD_unknown;
- }
- if (TokenMatched) {
- P.ConsumeToken();
- DKind = F[i][2];
- }
- }
- }
- return DKind;
- }
- /// \brief Parsing of declarative OpenMP directives.
- ///
- /// threadprivate-directive:
- /// annot_pragma_openmp 'threadprivate' simple-variable-list
- ///
- Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
- 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:
- ConsumeToken();
- if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) {
- // 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_threadprivate);
- SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
- }
- // Skip the last annot_pragma_openmp_end.
- ConsumeToken();
- 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 OMPD_taskyield:
- case OMPD_barrier:
- case OMPD_taskwait:
- case OMPD_taskgroup:
- case OMPD_flush:
- case OMPD_for:
- case OMPD_for_simd:
- case OMPD_sections:
- case OMPD_section:
- case OMPD_single:
- case OMPD_master:
- case OMPD_ordered:
- case OMPD_critical:
- case OMPD_parallel_for:
- case OMPD_parallel_for_simd:
- case OMPD_parallel_sections:
- case OMPD_atomic:
- case OMPD_target:
- case OMPD_teams:
- case OMPD_cancellation_point:
- case OMPD_cancel:
- Diag(Tok, diag::err_omp_unexpected_directive)
- << getOpenMPDirectiveName(DKind);
- break;
- }
- SkipUntil(tok::annot_pragma_openmp_end);
- return DeclGroupPtrTy();
- }
- /// \brief Parsing of declarative or executable OpenMP directives.
- ///
- /// threadprivate-directive:
- /// annot_pragma_openmp 'threadprivate' simple-variable-list
- /// 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' | 'teams' | 'taskgroup'
- /// {clause}
- /// annot_pragma_openmp_end
- ///
- 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>, OMPC_unknown + 1>
- FirstClauses(OMPC_unknown + 1);
- unsigned ScopeFlags =
- Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope;
- SourceLocation Loc = ConsumeToken(), EndLoc;
- auto DKind = ParseOpenMPDirectiveKind(*this);
- OpenMPDirectiveKind CancelRegion = OMPD_unknown;
- // Name of critical directive.
- DeclarationNameInfo DirName;
- StmtResult Directive = StmtError();
- bool HasAssociatedStatement = true;
- bool FlushHasClause = false;
- switch (DKind) {
- case OMPD_threadprivate:
- ConsumeToken();
- if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) {
- // 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_threadprivate);
- SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
- }
- DeclGroupPtrTy Res =
- Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers);
- Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
- }
- SkipUntil(tok::annot_pragma_openmp_end);
- break;
- 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:
- case OMPD_cancellation_point:
- case OMPD_cancel:
- 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_for_simd:
- case OMPD_sections:
- case OMPD_single:
- case OMPD_section:
- case OMPD_master:
- case OMPD_critical:
- case OMPD_parallel_for:
- case OMPD_parallel_for_simd:
- case OMPD_parallel_sections:
- case OMPD_task:
- case OMPD_ordered:
- case OMPD_atomic:
- case OMPD_target:
- case OMPD_teams:
- case OMPD_taskgroup: {
- 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();
- }
- } else if (DKind == OMPD_cancellation_point || DKind == OMPD_cancel) {
- CancelRegion = ParseOpenMPDirectiveKind(*this);
- if (Tok.isNot(tok::annot_pragma_openmp_end))
- ConsumeToken();
- }
- 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
- : FlushHasClause ? OMPC_flush
- : getOpenMPClauseKind(PP.getSpelling(Tok));
- Actions.StartOpenMPClause(CKind);
- FlushHasClause = false;
- OMPClause *Clause =
- ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt());
- FirstClauses[CKind].setInt(true);
- if (Clause) {
- FirstClauses[CKind].setPointer(Clause);
- Clauses.push_back(Clause);
- }
- // Skip ',' if any.
- if (Tok.is(tok::comma))
- ConsumeToken();
- Actions.EndOpenMPClause();
- }
- // End location of the directive.
- EndLoc = Tok.getLocation();
- // Consume final annot_pragma_openmp_end.
- ConsumeToken();
- StmtResult AssociatedStmt;
- bool CreateDirective = true;
- if (HasAssociatedStatement) {
- // The body is a block scope like in Lambdas and Blocks.
- Sema::CompoundScopeRAII CompoundScope(Actions);
- Actions.ActOnOpenMPRegionStart(DKind, getCurScope());
- Actions.ActOnStartOfCompoundStmt();
- // Parse statement
- AssociatedStmt = ParseStatement();
- Actions.ActOnFinishOfCompoundStmt();
- AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
- CreateDirective = AssociatedStmt.isUsable();
- }
- if (CreateDirective)
- Directive = Actions.ActOnOpenMPExecutableDirective(
- DKind, DirName, CancelRegion, 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;
- }
- 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();
- // Parse '('.
- BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
- if (T.expectAndConsume(diag::err_expected_lparen_after,
- getOpenMPDirectiveName(Kind)))
- return true;
- bool IsCorrect = true;
- bool NoIdentIsFound = true;
- // Read tokens while ')' or annot_pragma_openmp_end is not found.
- while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {
- CXXScopeSpec SS;
- SourceLocation TemplateKWLoc;
- UnqualifiedId Name;
- // Read var name.
- Token PrevTok = Tok;
- NoIdentIsFound = false;
- if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) {
- IsCorrect = false;
- SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
- StopBeforeMatch);
- } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
- TemplateKWLoc, Name)) {
- IsCorrect = false;
- SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
- StopBeforeMatch);
- } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
- Tok.isNot(tok::annot_pragma_openmp_end)) {
- IsCorrect = false;
- SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
- StopBeforeMatch);
- 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);
- if (Res.isUsable())
- VarList.push_back(Res.get());
- }
- // Consume ','.
- if (Tok.is(tok::comma)) {
- ConsumeToken();
- }
- }
- if (NoIdentIsFound) {
- Diag(Tok, diag::err_expected) << tok::identifier;
- IsCorrect = false;
- }
- // Parse ')'.
- IsCorrect = !T.consumeClose() && IsCorrect;
- return !IsCorrect && VarList.empty();
- }
- /// \brief Parsing of OpenMP clauses.
- ///
- /// 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 | read-clause | write-clause |
- /// update-clause | capture-clause | seq_cst-clause
- ///
- OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
- OpenMPClauseKind CKind, bool FirstClause) {
- 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);
- 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);
- ErrorFound = true;
- }
- Clause = ParseOpenMPSingleExprClause(CKind);
- break;
- case OMPC_default:
- 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);
- ErrorFound = true;
- }
- 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);
- ErrorFound = true;
- }
- Clause = ParseOpenMPSingleExprWithArgClause(CKind);
- break;
- case OMPC_ordered:
- case OMPC_nowait:
- case OMPC_untied:
- case OMPC_mergeable:
- case OMPC_read:
- case OMPC_write:
- case OMPC_update:
- case OMPC_capture:
- case OMPC_seq_cst:
- // 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);
- ErrorFound = true;
- }
- 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:
- case OMPC_depend:
- Clause = ParseOpenMPVarListClause(CKind);
- break;
- case OMPC_unknown:
- Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
- << getOpenMPDirectiveName(DKind);
- SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
- break;
- case OMPC_threadprivate:
- Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind)
- << getOpenMPDirectiveName(DKind);
- SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
- break;
- }
- 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' 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();
- // Parse '('.
- BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
- if (T.expectAndConsume(diag::err_expected_lparen_after,
- getOpenMPClauseName(Kind)))
- return nullptr;
- 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))
- ConsumeAnyToken();
- // Parse ')'.
- T.consumeClose();
- return Actions.ActOnOpenMPSimpleClause(Kind, Type, TypeLoc, LOpen, Loc,
- Tok.getLocation());
- }
- /// \brief Parsing of OpenMP clauses like 'ordered'.
- ///
- /// ordered-clause:
- /// 'ordered'
- ///
- /// nowait-clause:
- /// 'nowait'
- ///
- /// untied-clause:
- /// 'untied'
- ///
- /// mergeable-clause:
- /// 'mergeable'
- ///
- /// read-clause:
- /// 'read'
- ///
- 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 ')'
- /// depend-clause:
- /// 'depend' '(' in | out | inout : 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;
- OpenMPDependClauseKind DepKind = OMPC_DEPEND_unknown;
- SourceLocation DepLoc;
- // Parse '('.
- BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
- if (T.expectAndConsume(diag::err_expected_lparen_after,
- getOpenMPClauseName(Kind)))
- 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";
- }
- } 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) : ""));
- DepLoc = Tok.getLocation();
- if (DepKind == OMPC_DEPEND_unknown) {
- SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
- StopBeforeMatch);
- } else {
- ConsumeToken();
- }
- if (Tok.is(tok::colon)) {
- ColonLoc = ConsumeToken();
- } else {
- Diag(Tok, diag::warn_pragma_expected_colon) << "dependency type";
- }
- }
- SmallVector<Expr *, 5> Vars;
- bool IsComma = ((Kind != OMPC_reduction) && (Kind != OMPC_depend)) ||
- ((Kind == OMPC_reduction) && !InvalidReductionId) ||
- ((Kind == OMPC_depend) && 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))) {
- ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
- // Parse variable
- ExprResult VarExpr =
- Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
- if (VarExpr.isUsable()) {
- 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)
- ConsumeToken();
- 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)
- << ((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 =
- Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
- if (Tail.isUsable())
- TailExpr = Tail.get();
- else
- SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
- StopBeforeMatch);
- }
- // Parse ')'.
- T.consumeClose();
- if ((Kind == OMPC_depend && DepKind != OMPC_DEPEND_unknown && Vars.empty()) ||
- (Kind != OMPC_depend && Vars.empty()) || (MustHaveTail && !TailExpr) ||
- InvalidReductionId)
- return nullptr;
- return Actions.ActOnOpenMPVarListClause(
- Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(),
- ReductionIdScopeSpec,
- ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId)
- : DeclarationNameInfo(),
- DepKind, DepLoc);
- }
|