llvm-project/clang/lib/Parse/ParseOpenMP.cpp
Alexey Bataev aac108a324 [OPENMP] Do not emit references to original variables in 'private' clause.
Currently if the variable is captured in captured region, capture record for this region stores reference to this variable for future use. But we don't need to provide the reference to the original variable if it was explicitly marked as private in the 'private' clause of the OpenMP construct, this variable is replaced by private copy.
Differential Revision: http://reviews.llvm.org/D9550

llvm-svn: 240377
2015-06-23 04:51:00 +00:00

766 lines
26 KiB
C++

//===--- 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_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));
for (unsigned i = 0; i < llvm::array_lengthof(F); ++i) {
if (DKind == F[i][0]) {
Tok = P.getPreprocessor().LookAhead(0);
auto SDKind =
Tok.isAnnotation()
? OMPD_unknown
: getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
if (SDKind == F[i][1]) {
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:
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);
// 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:
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();
}
}
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, 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:
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 ')'
///
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 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 = !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 =
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 (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());
}