https://github.com/kevinsala created
https://github.com/llvm/llvm-project/pull/208353
Add parsing for `dims` modifier (OpenMP 6.1) in `num_threads` clauses. Examples:
```cpp
constexpr int N = 2;
#pragma omp parallel num_threads(dims(N),strict: a, b)
{ ... }
```
>From d8ab549e3469184d66428a98d3d92c756cafc974 Mon Sep 17 00:00:00 2001
From: Kevin Sala <[email protected]>
Date: Wed, 8 Jul 2026 13:14:49 -0700
Subject: [PATCH] [Clang][OpenMP] Add parsing/sema for dims modifier in
num_threads
---
clang/include/clang/AST/OpenMPClause.h | 184 ++++++++++++++----
clang/include/clang/AST/RecursiveASTVisitor.h | 4 +-
clang/include/clang/Basic/OpenMPKinds.def | 3 +-
clang/include/clang/Sema/SemaOpenMP.h | 9 +-
clang/lib/AST/OpenMPClause.cpp | 59 +++++-
clang/lib/AST/StmtProfile.cpp | 7 +-
clang/lib/CodeGen/CGExprScalar.cpp | 1 +
clang/lib/CodeGen/CGOpenMPRuntime.cpp | 6 +-
clang/lib/CodeGen/CGStmtOpenMP.cpp | 6 +-
clang/lib/Parse/ParseOpenMP.cpp | 113 +++++++----
clang/lib/Sema/SemaOpenMP.cpp | 91 +++++----
clang/lib/Sema/TreeTransform.h | 41 ++--
clang/lib/Serialization/ASTReader.cpp | 17 +-
clang/lib/Serialization/ASTWriter.cpp | 11 +-
clang/test/OpenMP/dims_modifier_ast_print.cpp | 62 ++++++
clang/test/OpenMP/dims_modifier_messages.cpp | 54 ++++-
...bute_parallel_for_num_threads_messages.cpp | 4 +-
...parallel_for_simd_num_threads_messages.cpp | 4 +-
.../parallel_for_num_threads_messages.cpp | 4 +-
...parallel_for_simd_num_threads_messages.cpp | 4 +-
.../parallel_masked_num_threads_messages.cpp | 4 +-
.../parallel_master_num_threads_messages.cpp | 4 +-
.../OpenMP/parallel_num_threads_messages.cpp | 28 +--
...parallel_sections_num_threads_messages.cpp | 4 +-
...rget_parallel_for_num_threads_messages.cpp | 4 +-
...parallel_for_simd_num_threads_messages.cpp | 4 +-
.../target_parallel_num_threads_messages.cpp | 28 +--
...bute_parallel_for_num_threads_messages.cpp | 4 +-
...parallel_for_simd_num_threads_messages.cpp | 4 +-
...parallel_for_simd_num_threads_messages.cpp | 4 +-
clang/tools/libclang/CIndex.cpp | 4 +-
31 files changed, 578 insertions(+), 198 deletions(-)
diff --git a/clang/include/clang/AST/OpenMPClause.h
b/clang/include/clang/AST/OpenMPClause.h
index 641c03bf8ff5c..a3048709ccd8c 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -804,67 +804,175 @@ class OMPFinalClause final
return const_cast<OMPFinalClause *>(this)->used_children();
}
};
+
/// This represents 'num_threads' clause in the '#pragma omp ...'
/// directive.
///
/// \code
-/// #pragma omp parallel num_threads(6)
+/// #pragma omp parallel num_threads(n)
+/// \endcode
+/// In this example directive '#pragma omp parallel' has 'num_threads' clause
+/// requesting 'n' threads.
+///
+/// \code
+/// #pragma omp parallel num_threads(strict: n)
/// \endcode
-/// In this example directive '#pragma omp parallel' has simple 'num_threads'
-/// clause with number of threads '6'.
+/// In this example directive '#pragma omp parallel' has 'num_threads' clause
+/// requesting 'n' threads strictly with the 'strict' modifier.
+///
+/// \code
+/// #pragma omp parallel num_threads(dims(2): x, y)
+/// \endcode
+/// In this example directive '#pragma omp parallel' has clause 'num_threads'
+/// with the 'dims' modifier specifying two dimensions. The list specifies the
+/// number of threads in each dimension.
class OMPNumThreadsClause final
- : public OMPOneStmtClause<llvm::omp::OMPC_num_threads, OMPClause>,
- public OMPClauseWithPreInit {
+ : public OMPVarListClause<OMPNumThreadsClause>,
+ public OMPClauseWithPreInit,
+ private llvm::TrailingObjects<OMPNumThreadsClause, Expr *> {
+ friend class OMPVarListClause<OMPNumThreadsClause>;
+ friend TrailingObjects;
friend class OMPClauseReader;
- /// Modifiers for 'num_threads' clause.
- OpenMPNumThreadsClauseModifier Modifier = OMPC_NUMTHREADS_unknown;
+private:
+ /// Categories of modifiers for the 'num_threads' clause.
+ enum { PRESCRIPTIVENESS, DIMS, NUM_MODIFIERS };
- /// Location of the modifier.
- SourceLocation ModifierLoc;
+ /// Modifiers for the clause, indexed by category.
+ OpenMPNumThreadsClauseModifier Modifiers[NUM_MODIFIERS] = {
+ OMPC_NUMTHREADS_unknown, OMPC_NUMTHREADS_unknown};
- /// Sets modifier.
- void setModifier(OpenMPNumThreadsClauseModifier M) { Modifier = M; }
+ /// Locations of the modifiers, indexed by category.
+ SourceLocation ModifiersLoc[NUM_MODIFIERS];
- /// Sets modifier location.
- void setModifierLoc(SourceLocation Loc) { ModifierLoc = Loc; }
+ /// Build clause with number of expressions \a N.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ /// \param N Number of expressions.
+ OMPNumThreadsClause(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc,
+ unsigned N)
+ : OMPVarListClause<OMPNumThreadsClause>(llvm::omp::OMPC_num_threads,
+ StartLoc, LParenLoc, EndLoc, N),
+ OMPClauseWithPreInit(this) {}
- /// Set condition.
- void setNumThreads(Expr *NThreads) { setStmt(NThreads); }
+ /// Build an empty clause.
+ ///
+ /// \param N Number of expressions.
+ explicit OMPNumThreadsClause(unsigned N)
+ : OMPVarListClause<OMPNumThreadsClause>(
+ llvm::omp::OMPC_num_threads, SourceLocation(), SourceLocation(),
+ SourceLocation(), N),
+ OMPClauseWithPreInit(this) {}
+
+ /// Sets the dims modifier.
+ void setDimsModifier(OpenMPNumThreadsClauseModifier M) {
+ Modifiers[DIMS] = M;
+ }
+
+ /// Sets the prescriptiveness modifier.
+ void setPrescriptivenessModifier(OpenMPNumThreadsClauseModifier M) {
+ Modifiers[PRESCRIPTIVENESS] = M;
+ }
+
+ /// Sets the location of the prescriptiveness modifier.
+ void setPrescriptivenessModifierLoc(SourceLocation Loc) {
+ ModifiersLoc[PRESCRIPTIVENESS] = Loc;
+ }
+
+ /// Sets the location of the dims modifier.
+ void setDimsModifierLoc(SourceLocation Loc) { ModifiersLoc[DIMS] = Loc; }
+
+ /// Sets the dims modifier expression.
+ void setDimsModifierExpr(Expr *E) { *varlist_end() = E; }
public:
- /// Build 'num_threads' clause with condition \a NumThreads.
+ /// Creates clause with a list of variables/expressions.
///
- /// \param Modifier Clause modifier.
- /// \param NumThreads Number of threads for the construct.
- /// \param HelperNumThreads Helper Number of threads for the construct.
- /// \param CaptureRegion Innermost OpenMP region where expressions in this
- /// clause must be captured.
+ /// \param C AST context.
+ /// \param CaptureRegion The captured region for the pre-init statements.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
- /// \param ModifierLoc Modifier location.
/// \param EndLoc Ending location of the clause.
- OMPNumThreadsClause(OpenMPNumThreadsClauseModifier Modifier, Expr
*NumThreads,
- Stmt *HelperNumThreads, OpenMPDirectiveKind
CaptureRegion,
- SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation ModifierLoc, SourceLocation EndLoc)
- : OMPOneStmtClause(NumThreads, StartLoc, LParenLoc, EndLoc),
- OMPClauseWithPreInit(this), Modifier(Modifier),
- ModifierLoc(ModifierLoc) {
- setPreInitStmt(HelperNumThreads, CaptureRegion);
+ /// \param VL List of references to the expressions.
+ /// \param PrescriptivenessModifier The prescriptiveness modifier.
+ /// \param DimsModifier The dims modifier.
+ /// \param PrescriptivenessModifierLoc Location of the prescriptiveness
modifier.
+ /// \param DimsModifierLoc Location of the dims modifier.
+ /// \param DimsModifierExpr The expression of the number of dimensions.
+ /// \param PreInit
+ static OMPNumThreadsClause *
+ Create(const ASTContext &C, OpenMPDirectiveKind CaptureRegion,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, ArrayRef<Expr *> VL,
+ OpenMPNumThreadsClauseModifier PrescriptivenessModifier,
+ OpenMPNumThreadsClauseModifier DimsModifier,
+ SourceLocation PrescriptivenessModifierLoc,
+ SourceLocation DimsModifierLoc, Expr *DimsModifierExpr, Stmt
*PreInit);
+
+ /// Creates an empty clause with the place for \a N expressions.
+ ///
+ /// \param C AST context.
+ /// \param N The number of expressions.
+ static OMPNumThreadsClause *CreateEmpty(const ASTContext &C, unsigned N);
+
+ /// Return NumThreads expressions.
+ ArrayRef<Expr *> getNumThreads() { return getVarRefs(); }
+ ArrayRef<Expr *> getNumThreads() const {
+ return const_cast<OMPNumThreadsClause *>(this)->getNumThreads();
}
- /// Build an empty clause.
- OMPNumThreadsClause() : OMPOneStmtClause(), OMPClauseWithPreInit(this) {}
+ /// Returns the prescriptiveness modifier.
+ OpenMPNumThreadsClauseModifier getPrescriptivenessModifier() const {
+ return Modifiers[PRESCRIPTIVENESS];
+ }
+ /// Returns the location of the prescriptiveness modifier.
+ SourceLocation getPrescriptivenessModifierLoc() const {
+ return ModifiersLoc[PRESCRIPTIVENESS];
+ }
- /// Gets modifier.
- OpenMPNumThreadsClauseModifier getModifier() const { return Modifier; }
+ /// Returns the dims modifier.
+ OpenMPNumThreadsClauseModifier getDimsModifier() const {
+ return Modifiers[DIMS];
+ }
+ /// Returns the location of the dims modifier.
+ SourceLocation getDimsModifierLoc() const { return ModifiersLoc[DIMS]; }
- /// Gets modifier location.
- SourceLocation getModifierLoc() const { return ModifierLoc; }
+ /// Checks if the clause has the dims modifier.
+ bool hasDimsModifier() const {
+ return Modifiers[DIMS] == OMPC_NUMTHREADS_dims;
+ }
- /// Returns number of threads.
- Expr *getNumThreads() const { return getStmtAs<Expr>(); }
+ /// Returns the dims modifier expression if present.
+ Expr *getDimsModifierExpr() {
+ return hasDimsModifier() ? *varlist_end() : nullptr;
+ }
+ /// Returns the dims modifier expression if present.
+ const Expr *getDimsModifierExpr() const {
+ return const_cast<OMPNumThreadsClause *>(this)->getDimsModifierExpr();
+ }
+
+ child_range children() {
+ return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end()) + 1);
+ }
+ const_child_range children() const {
+ return const_cast<OMPNumThreadsClause *>(this)->children();
+ }
+
+ child_range used_children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+ const_child_range used_children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == llvm::omp::OMPC_num_threads;
+ }
};
/// This represents 'safelen' clause in the '#pragma omp ...'
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h
b/clang/include/clang/AST/RecursiveASTVisitor.h
index 84aaac71746ed..1c0c182241064 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3501,8 +3501,10 @@ bool
RecursiveASTVisitor<Derived>::VisitOMPFinalClause(OMPFinalClause *C) {
template <typename Derived>
bool
RecursiveASTVisitor<Derived>::VisitOMPNumThreadsClause(OMPNumThreadsClause *C)
{
+ if (auto *E = C->getDimsModifierExpr())
+ TRY_TO(VisitStmt(E));
+ TRY_TO(VisitOMPClauseList(C));
TRY_TO(VisitOMPClauseWithPreInit(C));
- TRY_TO(TraverseStmt(C->getNumThreads()));
return true;
}
diff --git a/clang/include/clang/Basic/OpenMPKinds.def
b/clang/include/clang/Basic/OpenMPKinds.def
index 5c396a5d2d4b3..5b5222a2ab446 100644
--- a/clang/include/clang/Basic/OpenMPKinds.def
+++ b/clang/include/clang/Basic/OpenMPKinds.def
@@ -278,8 +278,9 @@ OPENMP_NUMTASKS_MODIFIER(strict)
OPENMP_NUMTEAMS_MODIFIER(lower_bound)
OPENMP_NUMTEAMS_MODIFIER(dims)
-// Modifiers for the 'num_tasks' clause.
+// Modifiers for the 'num_threads' clause.
OPENMP_NUMTHREADS_MODIFIER(strict)
+OPENMP_NUMTHREADS_MODIFIER(dims)
// Modifiers for the 'thread_limit' clause.
OPENMP_THREADLIMIT_MODIFIER(dims)
diff --git a/clang/include/clang/Sema/SemaOpenMP.h
b/clang/include/clang/Sema/SemaOpenMP.h
index 9ef388a744db8..93f8bd7f85958 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -898,9 +898,12 @@ class SemaOpenMP : public SemaBase {
SourceLocation EndLoc);
/// Called on well-formed 'num_threads' clause.
OMPClause *ActOnOpenMPNumThreadsClause(
- OpenMPNumThreadsClauseModifier Modifier, Expr *NumThreads,
- SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation ModifierLoc, SourceLocation EndLoc);
+ ArrayRef<Expr *> VarList,
+ OpenMPNumThreadsClauseModifier PrescriptivenessModifier,
+ SourceLocation PrescriptivenessModifierLoc,
+ OpenMPNumThreadsClauseModifier DimsModifier, Expr *DimsModifierExpr,
+ SourceLocation DimsModifierLoc, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc);
/// Called on well-formed 'align' clause.
OMPClause *ActOnOpenMPAlignClause(Expr *Alignment, SourceLocation StartLoc,
SourceLocation LParenLoc,
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index d451255bf5845..2860a96d4e3e4 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -1999,6 +1999,35 @@ OMPThreadLimitClause
*OMPThreadLimitClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPThreadLimitClause(N);
}
+OMPNumThreadsClause *OMPNumThreadsClause::Create(
+ const ASTContext &C, OpenMPDirectiveKind CaptureRegion,
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc,
+ ArrayRef<Expr *> VL,
+ OpenMPNumThreadsClauseModifier PrescriptivenessModifier,
+ OpenMPNumThreadsClauseModifier DimsModifier,
+ SourceLocation PrescriptivenessModifierLoc, SourceLocation DimsModifierLoc,
+ Expr *DimsModifierExpr, Stmt *PreInit) {
+ // Reserve space for an extra modifier expression.
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size() + 1));
+ OMPNumThreadsClause *Clause =
+ new (Mem) OMPNumThreadsClause(C, StartLoc, LParenLoc, EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ Clause->setPrescriptivenessModifier(PrescriptivenessModifier);
+ Clause->setPrescriptivenessModifierLoc(PrescriptivenessModifierLoc);
+ Clause->setDimsModifier(DimsModifier);
+ Clause->setDimsModifierExpr(DimsModifierExpr);
+ Clause->setDimsModifierLoc(DimsModifierLoc);
+ Clause->setPreInitStmt(PreInit, CaptureRegion);
+ return Clause;
+}
+
+OMPNumThreadsClause *OMPNumThreadsClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ // Reserve space for an extra modifier expression.
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N + 1));
+ return new (Mem) OMPNumThreadsClause(N);
+}
+
//===----------------------------------------------------------------------===//
// OpenMP clauses printing methods
//===----------------------------------------------------------------------===//
@@ -2018,14 +2047,30 @@ void
OMPClausePrinter::VisitOMPFinalClause(OMPFinalClause *Node) {
}
void OMPClausePrinter::VisitOMPNumThreadsClause(OMPNumThreadsClause *Node) {
- OS << "num_threads(";
- OpenMPNumThreadsClauseModifier Modifier = Node->getModifier();
- if (Modifier != OMPC_NUMTHREADS_unknown) {
- OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(), Modifier)
- << ": ";
+ if (!Node->varlist_empty()) {
+ OS << "num_threads";
+ bool HasPrescriptiveness =
+ Node->getPrescriptivenessModifier() != OMPC_NUMTHREADS_unknown;
+ bool HasDims = Node->getDimsModifier() != OMPC_NUMTHREADS_unknown;
+ if (HasPrescriptiveness || HasDims) {
+ OS << "(";
+ if (HasPrescriptiveness)
+ OS << getOpenMPSimpleClauseTypeName(
+ Node->getClauseKind(), Node->getPrescriptivenessModifier());
+ if (HasPrescriptiveness && HasDims)
+ OS << ",";
+ if (HasDims) {
+ OS << "dims(";
+ Node->getDimsModifierExpr()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+ }
+ OS << ":";
+ VisitOMPClauseList(Node, ' ');
+ } else {
+ VisitOMPClauseList(Node, '(');
+ }
+ OS << ")";
}
- Node->getNumThreads()->printPretty(OS, nullptr, Policy, 0);
- OS << ")";
}
void OMPClausePrinter::VisitOMPAlignClause(OMPAlignClause *Node) {
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 291c72385518e..0751783483bf6 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -475,9 +475,12 @@ void OMPClauseProfiler::VisitOMPFinalClause(const
OMPFinalClause *C) {
}
void OMPClauseProfiler::VisitOMPNumThreadsClause(const OMPNumThreadsClause *C)
{
+ Profiler->VisitInteger(C->getPrescriptivenessModifier());
+ Profiler->VisitInteger(C->getDimsModifier());
+ if (const Expr *Modifier = C->getDimsModifierExpr())
+ Profiler->VisitStmt(Modifier);
+ VisitOMPClauseList(C);
VisitOMPClauseWithPreInit(C);
- if (C->getNumThreads())
- Profiler->VisitStmt(C->getNumThreads());
}
void OMPClauseProfiler::VisitOMPAlignClause(const OMPAlignClause *C) {
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp
b/clang/lib/CodeGen/CGExprScalar.cpp
index 18ed6570730f4..f957eb4d859c9 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -6201,6 +6201,7 @@ Value *ScalarExprEmitter::VisitAtomicExpr(AtomicExpr *E) {
/// Emit the computation of the specified expression of scalar type, ignoring
/// the result.
Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign)
{
+ assert(E && "Invalid expression to emit");
assert(E && hasScalarEvaluationKind(E->getType()) &&
"Invalid scalar expression to emit");
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index eb2f92cdbf972..67d575d9d5e0d 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -6701,7 +6701,7 @@ static void getNumThreads(CodeGenFunction &CGF, const
CapturedStmt *CS,
CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
const auto *NumThreadsClause =
Dir->getSingleClause<OMPNumThreadsClause>();
- const Expr *NTExpr = NumThreadsClause->getNumThreads();
+ const Expr *NTExpr = NumThreadsClause->getNumThreads().front();
if (NTExpr->isIntegerConstantExpr(CGF.getContext()))
if (auto Constant = NTExpr->getIntegerConstantExpr(CGF.getContext()))
UpperBound =
@@ -6887,8 +6887,8 @@ const Expr
*CGOpenMPRuntime::getNumThreadsExprForTargetDirective(
if (D.hasClausesOfKind<OMPNumThreadsClause>()) {
CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
const auto *NumThreadsClause = D.getSingleClause<OMPNumThreadsClause>();
- CheckForConstExpr(NumThreadsClause->getNumThreads(), nullptr);
- return NumThreadsClause->getNumThreads();
+ CheckForConstExpr(NumThreadsClause->getNumThreads().front(), nullptr);
+ return NumThreadsClause->getNumThreads().front();
}
return NT;
}
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp
b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 88f698f38cce0..9174f6c63a751 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -1913,9 +1913,9 @@ static void emitCommonOMPParallelDirective(
if (const auto *NumThreadsClause = S.getSingleClause<OMPNumThreadsClause>())
{
CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
- NumThreads = CGF.EmitScalarExpr(NumThreadsClause->getNumThreads(),
+ NumThreads = CGF.EmitScalarExpr(NumThreadsClause->getNumThreads().front(),
/*IgnoreResultAssign=*/true);
- Modifier = NumThreadsClause->getModifier();
+ Modifier = NumThreadsClause->getPrescriptivenessModifier();
if (const auto *MessageClause = S.getSingleClause<OMPMessageClause>()) {
Message = MessageClause->getMessageString();
MessageLoc = MessageClause->getBeginLoc();
@@ -2113,7 +2113,7 @@ void CodeGenFunction::EmitOMPParallelDirective(const
OMPParallelDirective &S) {
llvm::Value *NumThreads = nullptr;
if (const auto *NumThreadsClause =
S.getSingleClause<OMPNumThreadsClause>())
- NumThreads = EmitScalarExpr(NumThreadsClause->getNumThreads(),
+ NumThreads = EmitScalarExpr(NumThreadsClause->getNumThreads().front(),
/*IgnoreResultAssign=*/true);
ProcBindKind ProcBind = OMP_PROC_BIND_default;
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 7ef1e4211a1ef..4e19082f8f814 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -3231,7 +3231,6 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind
DKind,
switch (CKind) {
case OMPC_final:
- case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_collapse:
@@ -3297,7 +3296,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind
DKind,
PP.LookAhead(/*N=*/0).isNot(tok::l_paren))
Clause = ParseOpenMPClause(CKind, WrongDirective);
else if (CKind == OMPC_grainsize || CKind == OMPC_num_tasks ||
- CKind == OMPC_num_threads || CKind == OMPC_dyn_groupprivate)
+ CKind == OMPC_dyn_groupprivate)
Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind,
WrongDirective);
else
Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective);
@@ -3428,6 +3427,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind
DKind,
break;
case OMPC_num_teams:
case OMPC_thread_limit:
+ case OMPC_num_threads:
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(DKind, OMPVersion)
@@ -4331,33 +4331,6 @@ OMPClause
*Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind,
Arg.push_back(OMPC_NUMTASKS_unknown);
KLoc.emplace_back();
}
- } else if (Kind == OMPC_num_threads) {
- // Parse optional <num_threads modifier> ':'
- OpenMPNumThreadsClauseModifier Modifier =
- static_cast<OpenMPNumThreadsClauseModifier>(getOpenMPSimpleClauseType(
- Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok),
- getLangOpts()));
- if (getLangOpts().OpenMP >= 60) {
- if (NextToken().is(tok::colon)) {
- Arg.push_back(Modifier);
- KLoc.push_back(Tok.getLocation());
- // Parse modifier
- ConsumeAnyToken();
- // Parse ':'
- ConsumeAnyToken();
- } else {
- if (Modifier == OMPC_NUMTHREADS_strict) {
- Diag(Tok, diag::err_modifier_expected_colon) << "strict";
- // Parse modifier
- ConsumeAnyToken();
- }
- Arg.push_back(OMPC_NUMTHREADS_unknown);
- KLoc.emplace_back();
- }
- } else {
- Arg.push_back(OMPC_NUMTHREADS_unknown);
- KLoc.emplace_back();
- }
} else {
assert(Kind == OMPC_if);
KLoc.push_back(Tok.getLocation());
@@ -4378,11 +4351,11 @@ OMPClause
*Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind,
}
}
- bool NeedAnExpression =
- (Kind == OMPC_schedule && DelimLoc.isValid()) ||
- (Kind == OMPC_dist_schedule && DelimLoc.isValid()) || Kind == OMPC_if ||
- Kind == OMPC_device || Kind == OMPC_grainsize || Kind == OMPC_num_tasks
||
- Kind == OMPC_num_threads || Kind == OMPC_dyn_groupprivate;
+ bool NeedAnExpression = (Kind == OMPC_schedule && DelimLoc.isValid()) ||
+ (Kind == OMPC_dist_schedule && DelimLoc.isValid()) ||
+ Kind == OMPC_if || Kind == OMPC_device ||
+ Kind == OMPC_grainsize || Kind == OMPC_num_tasks ||
+ Kind == OMPC_dyn_groupprivate;
if (NeedAnExpression) {
SourceLocation ELoc = Tok.getLocation();
ExprResult LHS(
@@ -5355,6 +5328,78 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind
DKind,
TPA.Revert();
}
}
+ } else if (Kind == OMPC_num_threads) {
+ Data.ExtraModifierArray[0] = static_cast<int>(OMPC_NUMTHREADS_unknown);
+ Data.ExtraModifierArray[1] = static_cast<int>(OMPC_NUMTHREADS_unknown);
+
+ bool HasModifier = false;
+ while (true) {
+ if (Tok.is(tok::identifier) && Tok.getIdentifierInfo()->isStr("dims") &&
+ NextToken().is(tok::l_paren)) {
+
+ SourceLocation TLoc = Tok.getLocation();
+ ConsumeToken();
+ SourceLocation RLoc;
+
+ ExprResult ExprR =
+ ParseOpenMPParensExpr(getOpenMPClauseName(Kind), RLoc);
+
+ if (Data.ExtraModifierArray[1] != OMPC_NUMTHREADS_unknown) {
+ Diag(TLoc, diag::err_omp_duplicate_modifier)
+ << getOpenMPSimpleClauseTypeName(Kind, OMPC_NUMTHREADS_dims)
+ << getOpenMPClauseName(Kind);
+ } else if (ExprR.isUsable()) {
+ Data.ExtraModifierArray[1] = static_cast<int>(OMPC_NUMTHREADS_dims);
+ Data.ExtraModifierExprArray[1] = ExprR.get();
+ Data.ExtraModifierLocArray[1] = TLoc;
+ }
+ HasModifier = true;
+ } else {
+ StringRef ModName = Tok.isAnnotation() ? "" : PP.getSpelling(Tok);
+ OpenMPNumThreadsClauseModifier Modifier =
+ static_cast<OpenMPNumThreadsClauseModifier>(
+ getOpenMPSimpleClauseType(Kind, ModName, getLangOpts()));
+
+ // The dims modifier is a complex modifier. It must be parsed above.
+ if (Modifier == OMPC_NUMTHREADS_dims)
+ Modifier = OMPC_NUMTHREADS_unknown;
+
+ if (Modifier != OMPC_NUMTHREADS_unknown) {
+ if (Data.ExtraModifierArray[0] != OMPC_NUMTHREADS_unknown) {
+ Diag(Tok, diag::err_omp_duplicate_modifier)
+ << getOpenMPSimpleClauseTypeName(Kind, OMPC_NUMTHREADS_strict)
+ << getOpenMPClauseName(Kind);
+ } else {
+ Data.ExtraModifierArray[0] = Modifier;
+ Data.ExtraModifierLocArray[0] = Tok.getLocation();
+ }
+ ConsumeAnyToken();
+ HasModifier = true;
+ } else {
+ break;
+ }
+ }
+
+ if (Tok.is(tok::comma)) {
+ ConsumeToken();
+ } else {
+ break;
+ }
+ }
+
+ if (HasModifier) {
+ if (Tok.is(tok::colon)) {
+ ConsumeToken();
+ } else {
+ Diag(Tok, diag::err_modifier_expected_colon)
+ << getOpenMPClauseName(Kind);
+ SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);
+ Data.RLoc = Tok.getLocation();
+ if (!T.consumeClose())
+ Data.RLoc = T.getCloseLocation();
+ return true;
+ }
+ }
}
bool IsComma =
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index f961c2887d9ed..1ba8644765ec8 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -17341,43 +17341,62 @@ static std::string
getListOfPossibleValues(OpenMPClauseKind K, unsigned First,
}
OMPClause *SemaOpenMP::ActOnOpenMPNumThreadsClause(
- OpenMPNumThreadsClauseModifier Modifier, Expr *NumThreads,
- SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation ModifierLoc, SourceLocation EndLoc) {
- assert((ModifierLoc.isInvalid() || getLangOpts().OpenMP >= 60) &&
- "Unexpected num_threads modifier in OpenMP < 60.");
-
- if (ModifierLoc.isValid() && Modifier == OMPC_NUMTHREADS_unknown) {
- std::string Values = getListOfPossibleValues(OMPC_num_threads, /*First=*/0,
- OMPC_NUMTHREADS_unknown);
- Diag(ModifierLoc, diag::err_omp_unexpected_clause_value)
- << Values << getOpenMPClauseNameForDiag(OMPC_num_threads);
- return nullptr;
+ ArrayRef<Expr *> VarList,
+ OpenMPNumThreadsClauseModifier PrescriptivenessModifier,
+ SourceLocation PrescriptivenessModifierLoc,
+ OpenMPNumThreadsClauseModifier DimsModifier, Expr *DimsModifierExpr,
+ SourceLocation DimsModifierLoc, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc) {
+ SmallVector<Expr *, 3> Vars(VarList.begin(), VarList.end());
+ for (Expr *&ValExpr : Vars) {
+ // OpenMP [2.5, Restrictions]
+ // The num_threads expression must evaluate to a positive integer value.
+ if (!isNonNegativeIntegerValue(ValExpr, SemaRef, OMPC_num_threads,
+ /*StrictlyPositive=*/true))
+ return nullptr;
}
- Expr *ValExpr = NumThreads;
- Stmt *HelperValStmt = nullptr;
+ if (DimsModifier == OMPC_NUMTHREADS_dims) {
+ ExprResult Res = ActOnOpenMPDimsModifier(OMPC_num_threads, DimsModifier,
+ DimsModifierExpr, DimsModifierLoc,
+ Vars, EndLoc);
+ if (Res.isInvalid())
+ return nullptr;
+ DimsModifierExpr = Res.get();
- // OpenMP [2.5, Restrictions]
- // The num_threads expression must evaluate to a positive integer value.
- if (!isNonNegativeIntegerValue(ValExpr, SemaRef, OMPC_num_threads,
- /*StrictlyPositive=*/true))
+ if (validateMultidimClauseExprs(*this, OMPC_num_threads, StartLoc, Vars,
+ DimsModifierExpr))
+ return nullptr;
+ }
+ if (PrescriptivenessModifier == OMPC_NUMTHREADS_strict &&
+ getLangOpts().OpenMP < 60) {
+ Diag(PrescriptivenessModifierLoc, diag::err_omp_modifier_requires_version)
+ << getOpenMPSimpleClauseTypeName(llvm::omp::OMPC_num_threads,
+ PrescriptivenessModifier)
+ << getOpenMPClauseName(llvm::omp::OMPC_num_threads) << "6.0";
return nullptr;
+ }
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
DKind, OMPC_num_threads, getLangOpts().OpenMP);
- if (CaptureRegion != OMPD_unknown &&
- !SemaRef.CurContext->isDependentContext()) {
+ if (CaptureRegion == OMPD_unknown ||
SemaRef.CurContext->isDependentContext())
+ return OMPNumThreadsClause::Create(
+ getASTContext(), CaptureRegion, StartLoc, LParenLoc, EndLoc, Vars,
+ PrescriptivenessModifier, DimsModifier, PrescriptivenessModifierLoc,
+ DimsModifierLoc, DimsModifierExpr, /*PreInit=*/nullptr);
+
+ llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
+ for (Expr *&ValExpr : Vars) {
ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
- HelperValStmt = buildPreInits(getASTContext(), Captures);
}
+ Stmt *PreInit = buildPreInits(getASTContext(), Captures);
- return new (getASTContext())
- OMPNumThreadsClause(Modifier, ValExpr, HelperValStmt, CaptureRegion,
- StartLoc, LParenLoc, ModifierLoc, EndLoc);
+ return OMPNumThreadsClause::Create(
+ getASTContext(), CaptureRegion, StartLoc, LParenLoc, EndLoc, Vars,
+ PrescriptivenessModifier, DimsModifier, PrescriptivenessModifierLoc,
+ DimsModifierLoc, DimsModifierExpr, PreInit);
}
ExprResult SemaOpenMP::VerifyPositiveIntegerConstantInClause(
@@ -18398,13 +18417,6 @@ OMPClause
*SemaOpenMP::ActOnOpenMPSingleExprWithArgClause(
ArgumentLoc[Modifier2], EndLoc);
break;
}
- case OMPC_num_threads:
- assert(Argument.size() == 1 && ArgumentLoc.size() == 1 &&
- "Modifier for num_threads clause and its location are expected.");
- Res = ActOnOpenMPNumThreadsClause(
- static_cast<OpenMPNumThreadsClauseModifier>(Argument.back()), Expr,
- StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc);
- break;
case OMPC_final:
case OMPC_safelen:
case OMPC_simdlen:
@@ -19387,10 +19399,23 @@ OMPClause
*SemaOpenMP::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
VarList, static_cast<OpenMPThreadLimitClauseModifier>(ExtraModifier),
ExtraModifierExpr, ExtraModifierLoc, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_num_threads:
+ assert(0 <= Data.ExtraModifierArray[0] &&
+ Data.ExtraModifierArray[0] <= OMPC_NUMTHREADS_unknown &&
+ 0 <= Data.ExtraModifierArray[1] &&
+ Data.ExtraModifierArray[1] <= OMPC_NUMTHREADS_unknown &&
+ "Unexpected num_threads modifier.");
+ Res = ActOnOpenMPNumThreadsClause(
+ VarList,
+
static_cast<OpenMPNumThreadsClauseModifier>(Data.ExtraModifierArray[0]),
+ Data.ExtraModifierLocArray[0],
+
static_cast<OpenMPNumThreadsClauseModifier>(Data.ExtraModifierArray[1]),
+ Data.ExtraModifierExprArray[1], Data.ExtraModifierLocArray[1],
StartLoc,
+ LParenLoc, EndLoc);
+ break;
case OMPC_if:
case OMPC_depobj:
case OMPC_final:
- case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_sizes:
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 92df2e622a37c..775d591787e5b 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1730,14 +1730,17 @@ class TreeTransform {
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPNumThreadsClause(OpenMPNumThreadsClauseModifier
Modifier,
- Expr *NumThreads,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation ModifierLoc,
- SourceLocation EndLoc) {
+ OMPClause *RebuildOMPNumThreadsClause(
+ ArrayRef<Expr *> VarList,
+ OpenMPNumThreadsClauseModifier PrescriptivenessModifier,
+ SourceLocation PrescriptivenessModifierLoc,
+ OpenMPNumThreadsClauseModifier DimsModifier, Expr *DimsModifierExpr,
+ SourceLocation DimsModifierLoc, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc) {
return getSema().OpenMP().ActOnOpenMPNumThreadsClause(
- Modifier, NumThreads, StartLoc, LParenLoc, ModifierLoc, EndLoc);
+ VarList, PrescriptivenessModifier, PrescriptivenessModifierLoc,
+ DimsModifier, DimsModifierExpr, DimsModifierLoc, StartLoc, LParenLoc,
+ EndLoc);
}
/// Build a new OpenMP 'safelen' clause.
@@ -10586,12 +10589,26 @@ OMPClause
*TreeTransform<Derived>::TransformOMPFinalClause(OMPFinalClause *C) {
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPNumThreadsClause(OMPNumThreadsClause *C) {
- ExprResult NumThreads = getDerived().TransformExpr(C->getNumThreads());
- if (NumThreads.isInvalid())
- return nullptr;
+ llvm::SmallVector<Expr *, 3> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlist()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ Expr *DimsModifierExpr = C->getDimsModifierExpr();
+ if (DimsModifierExpr) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(DimsModifierExpr));
+ if (EVar.isInvalid())
+ return nullptr;
+ DimsModifierExpr = EVar.get();
+ }
return getDerived().RebuildOMPNumThreadsClause(
- C->getModifier(), NumThreads.get(), C->getBeginLoc(), C->getLParenLoc(),
- C->getModifierLoc(), C->getEndLoc());
+ Vars, C->getPrescriptivenessModifier(),
+ C->getPrescriptivenessModifierLoc(), C->getDimsModifier(),
+ DimsModifierExpr, C->getDimsModifierLoc(), C->getBeginLoc(),
+ C->getLParenLoc(), C->getEndLoc());
}
template <typename Derived>
diff --git a/clang/lib/Serialization/ASTReader.cpp
b/clang/lib/Serialization/ASTReader.cpp
index 3189bf3431c1e..6a2118511abf6 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -11466,7 +11466,7 @@ OMPClause *OMPClauseReader::readClause() {
C = new (Context) OMPFinalClause();
break;
case llvm::omp::OMPC_num_threads:
- C = new (Context) OMPNumThreadsClause();
+ C = OMPNumThreadsClause::CreateEmpty(Context, Record.readInt());
break;
case llvm::omp::OMPC_safelen:
C = new (Context) OMPSafelenClause();
@@ -11878,11 +11878,20 @@ void
OMPClauseReader::VisitOMPFinalClause(OMPFinalClause *C) {
}
void OMPClauseReader::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
+ C->setPrescriptivenessModifier(
+ Record.readEnum<OpenMPNumThreadsClauseModifier>());
+ C->setPrescriptivenessModifierLoc(Record.readSourceLocation());
+ C->setDimsModifier(Record.readEnum<OpenMPNumThreadsClauseModifier>());
+ C->setDimsModifierLoc(Record.readSourceLocation());
+ C->setDimsModifierExpr(Record.readSubExpr());
VisitOMPClauseWithPreInit(C);
- C->setModifier(Record.readEnum<OpenMPNumThreadsClauseModifier>());
- C->setNumThreads(Record.readSubExpr());
- C->setModifierLoc(Record.readSourceLocation());
C->setLParenLoc(Record.readSourceLocation());
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Record.readSubExpr());
+ C->setVarRefs(Vars);
}
void OMPClauseReader::VisitOMPSafelenClause(OMPSafelenClause *C) {
diff --git a/clang/lib/Serialization/ASTWriter.cpp
b/clang/lib/Serialization/ASTWriter.cpp
index a305e92b6a602..9fcf4d269e9ea 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -8057,11 +8057,16 @@ void
OMPClauseWriter::VisitOMPFinalClause(OMPFinalClause *C) {
}
void OMPClauseWriter::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
+ Record.push_back(C->varlist_size());
+ Record.writeEnum(C->getPrescriptivenessModifier());
+ Record.AddSourceLocation(C->getPrescriptivenessModifierLoc());
+ Record.writeEnum(C->getDimsModifier());
+ Record.AddSourceLocation(C->getDimsModifierLoc());
+ Record.AddStmt(C->getDimsModifierExpr());
VisitOMPClauseWithPreInit(C);
- Record.writeEnum(C->getModifier());
- Record.AddStmt(C->getNumThreads());
- Record.AddSourceLocation(C->getModifierLoc());
Record.AddSourceLocation(C->getLParenLoc());
+ for (auto *VE : C->varlist())
+ Record.AddStmt(VE);
}
void OMPClauseWriter::VisitOMPSafelenClause(OMPSafelenClause *C) {
diff --git a/clang/test/OpenMP/dims_modifier_ast_print.cpp
b/clang/test/OpenMP/dims_modifier_ast_print.cpp
index d47e8353abcad..57801f305218f 100644
--- a/clang/test/OpenMP/dims_modifier_ast_print.cpp
+++ b/clang/test/OpenMP/dims_modifier_ast_print.cpp
@@ -21,6 +21,46 @@ void test_ast_print() {
// CHECK: #pragma omp target teams num_teams(dims(1):N)
thread_limit(dims(1):M)
#pragma omp target teams num_teams(dims(1): N) thread_limit(dims(1): M)
{}
+
+ // CHECK: #pragma omp parallel num_threads(dims(3): 1,2,3)
+ #pragma omp parallel num_threads(dims(3): 1, 2, 3)
+ {}
+
+ // CHECK: #pragma omp parallel num_threads(strict: 10)
+ #pragma omp parallel num_threads(strict: 10)
+ {}
+
+ // CHECK: #pragma omp parallel num_threads(strict,dims(2): N + 1,N)
+ #pragma omp parallel num_threads(strict, dims(2): N + 1, N)
+ {}
+
+ // CHECK: #pragma omp parallel num_threads(strict,dims(2): 10,20)
+ #pragma omp parallel num_threads(dims(2), strict: 10, 20)
+ {}
+
+ // CHECK: #pragma omp parallel num_threads(strict,dims(2): N,N + 1)
+ #pragma omp parallel num_threads(strict, dims(2): N, N + 1)
+ {}
+
+ // CHECK: #pragma omp target parallel thread_limit(dims(2):10,20)
num_threads(dims(2): N,N + 1)
+ #pragma omp target parallel thread_limit(dims(2): 10, 20)
num_threads(dims(2): N, N + 1)
+ {}
+
+ // CHECK: #pragma omp target teams num_teams(dims(3):1,2,3)
thread_limit(dims(2):10,20)
+ // CHECK-NEXT: #pragma omp parallel num_threads(dims(2): N,N + 1)
+ #pragma omp target teams num_teams(dims(3): 1, 2, 3) thread_limit(dims(2):
10, 20)
+ #pragma omp parallel num_threads(dims(2): N, N + 1)
+ {}
+
+ // CHECK: #pragma omp target parallel thread_limit(dims(1):M)
num_threads(strict,dims(2): 10,20)
+ #pragma omp target parallel thread_limit(dims(1): M) num_threads(dims(2),
strict: 10, 20)
+ {}
+
+ // CHECK: #pragma omp target teams num_teams(dims(1):N)
thread_limit(dims(1):M)
+ // CHECK-NEXT: #pragma omp parallel num_threads(strict,dims(2): 10,20)
+ #pragma omp target teams num_teams(dims(1): N) thread_limit(dims(1): M)
+ #pragma omp parallel num_threads(dims(2), strict: 10, 20)
+ {}
}
template <int D>
@@ -33,6 +73,28 @@ void template_test() {
// CHECK: #pragma omp target teams num_teams(dims(3):arr[0],arr[1],arr[2])
thread_limit(dims(2):3,arr[0])
#pragma omp target teams num_teams(dims(D): arr[0], arr[1], arr[2])
thread_limit(dims(2): D, arr[0])
{}
+
+ // CHECK: #pragma omp parallel num_threads(dims(3): arr[0],arr[1],arr[2])
+ #pragma omp parallel num_threads(dims(3): arr[0], arr[1], arr[2])
+ {}
+
+ // CHECK: #pragma omp parallel num_threads(strict,dims(2): 3,arr[0])
+ #pragma omp parallel num_threads(strict, dims(2): D, arr[0])
+ {}
+
+ // CHECK: #pragma omp parallel num_threads(strict,dims(2): 3,arr[0])
+ #pragma omp parallel num_threads(dims(2), strict: D, arr[0])
+ {}
+
+ // CHECK: #pragma omp target parallel thread_limit(dims(1):3)
num_threads(strict,dims(2): 3,arr[0])
+ #pragma omp target parallel thread_limit(dims(1): D) num_threads(dims(2),
strict: D, arr[0])
+ {}
+
+ // CHECK: #pragma omp target teams num_teams(dims(3):arr[0],arr[1],arr[2])
thread_limit(dims(1):3)
+ // CHECK-NEXT: #pragma omp parallel num_threads(strict,dims(2): 3,arr[0])
+ #pragma omp target teams num_teams(dims(3): arr[0], arr[1], arr[2])
thread_limit(dims(1): D)
+ #pragma omp parallel num_threads(dims(2), strict: D, arr[0])
+ {}
}
void call_templates() {
diff --git a/clang/test/OpenMP/dims_modifier_messages.cpp
b/clang/test/OpenMP/dims_modifier_messages.cpp
index ce0dd7eb79c52..e7e74e900cf1d 100644
--- a/clang/test/OpenMP/dims_modifier_messages.cpp
+++ b/clang/test/OpenMP/dims_modifier_messages.cpp
@@ -8,17 +8,25 @@ void foo() {
}
#ifndef VERSION52
-void bar(int N) { // expected-note {{declared here}}
+void bar(int N) { // expected-note 2 {{declared here}}
// 1. Invalid syntax of the dims modifier.
#pragma omp target teams num_teams(dims 2: 4) // expected-error {{use of
undeclared identifier 'dims'}}
foo();
+#pragma omp parallel num_threads(dims 2: 4) // expected-error {{use of
undeclared identifier 'dims'}}
+ foo();
+
#pragma omp target thread_limit(dim(2) 4, 5)
// expected-error@-1 {{use of undeclared identifier 'dim'}}
// expected-error@-2 {{expected ',' or ')' in 'thread_limit' clause}}
foo();
+#pragma omp parallel num_threads(dim(2) 4, 5)
+ // expected-error@-1 {{use of undeclared identifier 'dim'}}
+ // expected-error@-2 {{expected ',' or ')' in 'num_threads' clause}}
+ foo();
+
#pragma omp target thread_limit(dims((2): 4, 5)
// expected-error@-1 {{expected ')'}}
// expected-error@-2 {{expected ')'}}
@@ -27,17 +35,36 @@ void bar(int N) { // expected-note {{declared here}}
// expected-error@-5 {{missing ':' after thread_limit modifier}}
foo();
+#pragma omp parallel num_threads(dims((2): 4, 5)
+ // expected-error@-1 {{expected ')'}}
+ // expected-error@-2 {{expected ')'}}
+ // expected-note@-3 {{to match this '('}}
+ // expected-note@-4 {{to match this '('}}
+ // expected-error@-5 {{missing ':' after num_threads modifier}}
+ foo();
+
#pragma omp target thread_limit(dims(2)): 4, 5)
// expected-error@-1 {{missing ':' after thread_limit modifier}}
// expected-warning@-2 {{extra tokens at the end of '#pragma omp target' are
ignored}}
foo();
+#pragma omp parallel num_threads(dims(2)): 4, 5)
+ // expected-error@-1 {{missing ':' after num_threads modifier}}
+ // expected-warning@-2 {{extra tokens at the end of '#pragma omp parallel'
are ignored}}
+ foo();
+
#pragma omp target thread_limit(dims(2) 4, 5) // expected-error {{missing ':'
after thread_limit modifier}}
foo();
+#pragma omp parallel num_threads(dims(2) 4, 5) // expected-error {{missing ':'
after num_threads modifier}}
+ foo();
+
#pragma omp target teams distribute num_teams(dims(): 4) // expected-error
{{expected expression}}
for (int i = 0; i < 10; ++i) {}
+#pragma omp parallel num_threads(dims(): 4) // expected-error {{expected
expression}}
+ foo();
+
// 3. Incompatible modifiers.
#pragma omp target teams num_teams(dims(1),10:20) // expected-error
{{'lower_bound' modifier cannot be specified with 'dims' modifier in
'num_teams' clause}}
@@ -51,6 +78,9 @@ void bar(int N) { // expected-note {{declared here}}
#pragma omp target thread_limit(dims(1): 4, 5) // expected-error {{unexpected
number of expressions in 'thread_limit' clause}}
foo();
+#pragma omp parallel num_threads(dims(2): 4) // expected-error {{unexpected
number of expressions in 'num_threads' clause}}
+ foo();
+
#pragma omp target teams distribute num_teams(dims(3): 4, 5) // expected-error
{{unexpected number of expressions in 'num_teams' clause}}
for (int i = 0; i < 10; ++i) {}
@@ -62,6 +92,9 @@ void bar(int N) { // expected-note {{declared here}}
#pragma omp target thread_limit(dims(2): 1, 2, 3, 4) // expected-error
{{unexpected number of expressions in 'thread_limit' clause}}
foo();
+#pragma omp parallel num_threads(dims(4): 1, 2, 3, 4) // expected-error
{{maximum three expressions are supported in 'num_threads' clause}}
+ foo();
+
#pragma omp target teams distribute thread_limit(dims(4): 1, 2, 3, 4) //
expected-error {{maximum three expressions are supported in 'thread_limit'
clause}}
for (int i = 0; i < 10; ++i) {}
@@ -80,14 +113,25 @@ void bar(int N) { // expected-note {{declared here}}
// expected-note@-2 {{function parameter 'N' with unknown value cannot be
used in a constant expression}}
foo();
+#pragma omp parallel num_threads(dims(N): 1, 2)
+ // expected-error@-1 {{expression is not an integral constant expression}}
+ // expected-note@-2 {{function parameter 'N' with unknown value cannot be
used in a constant expression}}
+ foo();
+
#pragma omp target thread_limit(dims(2.5): 1, 2) // expected-error {{integral
constant expression must have integral or unscoped enumeration type, not
'double'}}
foo();
+#pragma omp parallel num_threads(dims(2.5): 1, 2) // expected-error {{integral
constant expression must have integral or unscoped enumeration type, not
'double'}}
+ foo();
+
#pragma omp target teams distribute num_teams(dims(0): 4) // expected-error
{{argument to 'num_teams' clause must be a strictly positive integer value}}
for (int i = 0; i < 10; ++i) {}
#pragma omp target teams thread_limit(dims(-1): 4) // expected-error
{{argument to 'thread_limit' clause must be a strictly positive integer value}}
foo();
+
+#pragma omp parallel num_threads(dims(0): 4) // expected-error {{argument to
'num_threads' clause must be a strictly positive integer value}}
+ foo();
}
template <int D>
@@ -104,6 +148,11 @@ void template_test() {
// expected-error@-2 {{argument to 'thread_limit' clause must be a strictly
positive integer value}}
foo();
+#pragma omp parallel num_threads(dims(D): 4)
+ // expected-error@-1 {{unexpected number of expressions in 'num_threads'
clause}}
+ // expected-error@-2 {{argument to 'num_threads' clause must be a strictly
positive integer value}}
+ foo();
+
#pragma omp target teams distribute num_teams(dims(D): 4, 5)
// expected-error@-1 {{unexpected number of expressions in 'num_teams'
clause}}
// expected-error@-2 {{argument to 'num_teams' clause must be a strictly
positive integer value}}
@@ -125,5 +174,8 @@ void version() {
#pragma omp target thread_limit(dims(1): 4) // expected-error {{'dims'
modifier in 'thread_limit' clause requires OpenMP 6.1 or later}}
foo();
+
+#pragma omp target parallel num_threads(dims(1): 4) // expected-error {{'dims'
modifier in 'num_threads' clause requires OpenMP 6.1 or later}}
+ foo();
}
#endif
diff --git a/clang/test/OpenMP/distribute_parallel_for_num_threads_messages.cpp
b/clang/test/OpenMP/distribute_parallel_for_num_threads_messages.cpp
index ab301cc517207..296d0865d14e3 100644
--- a/clang/test/OpenMP/distribute_parallel_for_num_threads_messages.cpp
+++ b/clang/test/OpenMP/distribute_parallel_for_num_threads_messages.cpp
@@ -48,7 +48,7 @@ T tmain(T argc, S **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams
-#pragma omp distribute parallel for num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error 2
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+#pragma omp distribute parallel for num_threads (argv[1]=2) // expected-error
2 {{incompatible integer to pointer conversion assigning to 'char *' from
'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams
@@ -98,7 +98,7 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams
-#pragma omp distribute parallel for num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+#pragma omp distribute parallel for num_threads (argv[1]=2) // expected-error
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams
diff --git
a/clang/test/OpenMP/distribute_parallel_for_simd_num_threads_messages.cpp
b/clang/test/OpenMP/distribute_parallel_for_simd_num_threads_messages.cpp
index 9f9de197aca0d..d405246cd5a56 100644
--- a/clang/test/OpenMP/distribute_parallel_for_simd_num_threads_messages.cpp
+++ b/clang/test/OpenMP/distribute_parallel_for_simd_num_threads_messages.cpp
@@ -48,7 +48,7 @@ T tmain(T argc, S **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams
-#pragma omp distribute parallel for simd num_threads (argv[1]=2) //
expected-error {{expected ')'}} expected-note {{to match this '('}}
expected-error 2 {{expression must have integral or unscoped enumeration type,
not 'char *'}}
+#pragma omp distribute parallel for simd num_threads (argv[1]=2) //
expected-error 2 {{incompatible integer to pointer conversion assigning to
'char *' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams
@@ -98,7 +98,7 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams
-#pragma omp distribute parallel for simd num_threads (argv[1]=2) //
expected-error {{expected ')'}} expected-note {{to match this '('}}
expected-error {{expression must have integral or unscoped enumeration type,
not 'char *'}}
+#pragma omp distribute parallel for simd num_threads (argv[1]=2) //
expected-error {{incompatible integer to pointer conversion assigning to 'char
*' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams
diff --git a/clang/test/OpenMP/parallel_for_num_threads_messages.cpp
b/clang/test/OpenMP/parallel_for_num_threads_messages.cpp
index e689df8fc7d85..4979e7df7e1a0 100644
--- a/clang/test/OpenMP/parallel_for_num_threads_messages.cpp
+++ b/clang/test/OpenMP/parallel_for_num_threads_messages.cpp
@@ -30,7 +30,7 @@ T tmain(T argc, S **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for num_threads (S) // expected-error {{'S' does not
refer to a value}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp parallel for num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error 2
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel for num_threads (argv[1]=2) // expected-error 2
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for num_threads (argc+z)
for (i = 0; i < argc; ++i) foo();
@@ -58,7 +58,7 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for num_threads (S1) // expected-error {{'S1' does not
refer to a value}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp parallel for num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel for num_threads (argv[1]=2) // expected-error
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for num_threads (num_threads(tmain<int, char, -1>(argc,
argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this
'('}} expected-note {{in instantiation of function template specialization
'tmain<int, char, -1>' requested here}}
for (i = 0; i < argc; ++i) foo();
diff --git a/clang/test/OpenMP/parallel_for_simd_num_threads_messages.cpp
b/clang/test/OpenMP/parallel_for_simd_num_threads_messages.cpp
index f79ec4f68f4bb..f7457697bc227 100644
--- a/clang/test/OpenMP/parallel_for_simd_num_threads_messages.cpp
+++ b/clang/test/OpenMP/parallel_for_simd_num_threads_messages.cpp
@@ -30,7 +30,7 @@ T tmain(T argc, S **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for simd num_threads (S) // expected-error {{'S' does
not refer to a value}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp parallel for simd num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error 2
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel for simd num_threads (argv[1]=2) // expected-error 2
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for simd num_threads (argc + z)
for (i = 0; i < argc; ++i) foo();
@@ -58,7 +58,7 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for simd num_threads (S1) // expected-error {{'S1' does
not refer to a value}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp parallel for simd num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel for simd num_threads (argv[1]=2) // expected-error
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp parallel for simd num_threads (num_threads(tmain<int, char,
-1>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match
this '('}} expected-note {{in instantiation of function template specialization
'tmain<int, char, -1>' requested here}}
for (i = 0; i < argc; ++i) foo();
diff --git a/clang/test/OpenMP/parallel_masked_num_threads_messages.cpp
b/clang/test/OpenMP/parallel_masked_num_threads_messages.cpp
index 928c07c5610e1..46dc4035cc9d6 100644
--- a/clang/test/OpenMP/parallel_masked_num_threads_messages.cpp
+++ b/clang/test/OpenMP/parallel_masked_num_threads_messages.cpp
@@ -30,7 +30,7 @@ T tmain(T argc, S **argv) {
{foo();}
#pragma omp parallel masked num_threads (S) // expected-error {{'S' does not
refer to a value}}
{foo();}
- #pragma omp parallel masked num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error 2
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel masked num_threads (argv[1]=2) // expected-error 2
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
{foo();}
#pragma omp parallel masked num_threads (argc + z)
{foo();}
@@ -58,7 +58,7 @@ int main(int argc, char **argv) {
{foo();}
#pragma omp parallel masked num_threads (S1) // expected-error {{'S1' does
not refer to a value}}
{foo();}
- #pragma omp parallel masked num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel masked num_threads (argv[1]=2) // expected-error
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
{foo();}
#pragma omp parallel masked num_threads (num_threads(tmain<int, char,
-1>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match
this '('}} expected-note {{in instantiation of function template specialization
'tmain<int, char, -1>' requested here}}
{foo();}
diff --git a/clang/test/OpenMP/parallel_master_num_threads_messages.cpp
b/clang/test/OpenMP/parallel_master_num_threads_messages.cpp
index 601164f1e5328..d951abccb12c0 100644
--- a/clang/test/OpenMP/parallel_master_num_threads_messages.cpp
+++ b/clang/test/OpenMP/parallel_master_num_threads_messages.cpp
@@ -30,7 +30,7 @@ T tmain(T argc, S **argv) {
{foo();}
#pragma omp parallel master num_threads (S) // expected-error {{'S' does not
refer to a value}}
{foo();}
- #pragma omp parallel master num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error 2
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel master num_threads (argv[1]=2) // expected-error 2
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
{foo();}
#pragma omp parallel master num_threads (argc + z)
{foo();}
@@ -58,7 +58,7 @@ int main(int argc, char **argv) {
{foo();}
#pragma omp parallel master num_threads (S1) // expected-error {{'S1' does
not refer to a value}}
{foo();}
- #pragma omp parallel master num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel master num_threads (argv[1]=2) // expected-error
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
{foo();}
#pragma omp parallel master num_threads (num_threads(tmain<int, char,
-1>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match
this '('}} expected-note {{in instantiation of function template specialization
'tmain<int, char, -1>' requested here}}
{foo();}
diff --git a/clang/test/OpenMP/parallel_num_threads_messages.cpp
b/clang/test/OpenMP/parallel_num_threads_messages.cpp
index 02c1cb6e69d99..fbffa06c29d6d 100644
--- a/clang/test/OpenMP/parallel_num_threads_messages.cpp
+++ b/clang/test/OpenMP/parallel_num_threads_messages.cpp
@@ -26,7 +26,7 @@ T tmain(T argc, S **argv) {
#pragma omp parallel num_threads ((argc > 0) ? argv[1] : argv[2]) //
expected-error 2 {{expression must have integral or unscoped enumeration type,
not 'char *'}}
#pragma omp parallel num_threads (foobool(argc)), num_threads (true),
num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel' cannot
contain more than one 'num_threads' clause}} expected-error {{argument to
'num_threads' clause must be a strictly positive integer value}}
#pragma omp parallel num_threads (S) // expected-error {{'S' does not refer
to a value}}
- #pragma omp parallel num_threads (argv[1]=2) // expected-error {{expected
')'}} expected-note {{to match this '('}} expected-error 2 {{expression must
have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel num_threads (argv[1]=2) // expected-error 2
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
#pragma omp parallel num_threads (argc+z)
#pragma omp parallel num_threads (N) // expected-error {{argument to
'num_threads' clause must be a strictly positive integer value}}
#pragma omp parallel redef_num_threads (argc, argc)
@@ -42,23 +42,23 @@ T tmain(T argc, S **argv) {
#pragma omp parallel num_threads(strict: // omp60-error {{expected
expression}} omp60-error {{expected ')'}} omp60-note {{to match this '('}}
// Invalid: unknown/missing modifier
- #pragma omp parallel num_threads(foo: 4) // omp60-error {{expected 'strict'
in OpenMP clause 'num_threads'}}
- #pragma omp parallel num_threads(: 4) // omp60-error {{expected expression}}
omp60-error {{expected ')'}} omp60-note {{to match this '('}}
- #pragma omp parallel num_threads(:)// omp60-error {{expected expression}}
omp60-error {{expected ')'}} omp60-note {{to match this '('}}
+ #pragma omp parallel num_threads(foo: 4) // omp60-error {{expected ',' or
')' in 'num_threads' clause}} omp60-error {{expected ')'}} omp60-note {{to
match this '('}} omp60-error 3 {{expression must have integral or unscoped
enumeration type, not 'void ()'}}
+ #pragma omp parallel num_threads(: 4) // omp60-error {{expected expression}}
+ #pragma omp parallel num_threads(:)// omp60-error {{expected expression}}
// Invalid: missing colon after modifier
- #pragma omp parallel num_threads(strict 4) // omp60-error {{missing ':'
after strict modifier}}
+ #pragma omp parallel num_threads(strict 4) // omp60-error {{missing ':'
after num_threads modifier}}
// Invalid: negative, zero, or non-integral
#pragma omp parallel num_threads(strict: -1) // omp60-error {{argument to
'num_threads' clause must be a strictly positive integer value}}
#pragma omp parallel num_threads(strict: 0) // omp60-error {{argument to
'num_threads' clause must be a strictly positive integer value}}
#pragma omp parallel num_threads(strict: (argc > 0) ? argv[1] : argv[2]) //
omp60-error 2 {{expression must have integral or unscoped enumeration type, not
'char *'}}
#pragma omp parallel num_threads(strict: S) // omp60-error {{'S' does not
refer to a value}}
- #pragma omp parallel num_threads(strict: argv[1]=2) // omp60-error
{{expected ')'}} omp60-note {{to match this '('}} omp60-error 2 {{expression
must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel num_threads(strict: argv[1]=2) // omp60-error 2
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
#pragma omp parallel num_threads(strict: N) // omp60-error {{argument to
'num_threads' clause must be a strictly positive integer value}}
// Invalid: multiple strict modifiers or mixed with non-strict
- #pragma omp parallel num_threads(strict: 4, strict: 5) // omp60-error
{{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel num_threads(strict: 4, strict: 5) // omp60-error {{use
of undeclared identifier 'strict'}}
#pragma omp parallel num_threads(strict: 4), num_threads(5) // omp60-error
{{directive '#pragma omp parallel' cannot contain more than one 'num_threads'
clause}}
#pragma omp parallel num_threads(4), num_threads(strict: 5) // omp60-error
{{directive '#pragma omp parallel' cannot contain more than one 'num_threads'
clause}}
#endif // OMP60
@@ -78,7 +78,7 @@ int z;
#pragma omp parallel num_threads (argc > 0 ? argv[1] : argv[2]) //
expected-error {{integral }}
#pragma omp parallel num_threads (foobool(argc)), num_threads (true),
num_threads (-5) // expected-error 2 {{directive '#pragma omp parallel' cannot
contain more than one 'num_threads' clause}} expected-error {{argument to
'num_threads' clause must be a strictly positive integer value}}
#pragma omp parallel num_threads (S1) // expected-error {{'S1' does not
refer to a value}}
- #pragma omp parallel num_threads (argv[1]=2) // expected-error {{expected
')'}} expected-note {{to match this '('}} expected-error {{expression must have
integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel num_threads (argv[1]=2) // expected-error
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
#pragma omp parallel num_threads (num_threads(tmain<int, char, -1>(argc,
argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this
'('}} expected-note {{in instantiation of function template specialization
'tmain<int, char, -1>' requested here}}
#pragma omp parallel redef_num_threads (argc, argc)
@@ -93,22 +93,22 @@ int z;
#pragma omp parallel num_threads(strict: // omp60-error {{expected
expression}} omp60-error {{expected ')'}} omp60-note {{to match this '('}}
// Invalid: unknown/missing modifier
- #pragma omp parallel num_threads(foo: 4) // omp60-error {{expected 'strict'
in OpenMP clause 'num_threads'}}
- #pragma omp parallel num_threads(: 4) // omp60-error {{expected expression}}
omp60-error {{expected ')'}} omp60-note {{to match this '('}}
- #pragma omp parallel num_threads(:) // omp60-error {{expected expression}}
omp60-error {{expected ')'}} omp60-note {{to match this '('}}
+ #pragma omp parallel num_threads(foo: 4) // omp60-error {{expected ',' or
')' in 'num_threads' clause}} omp60-error {{expected ')'}} omp60-note {{to
match this '('}} omp60-error {{expression must have integral or unscoped
enumeration type, not 'void ()'}}
+ #pragma omp parallel num_threads(: 4) // omp60-error {{expected expression}}
+ #pragma omp parallel num_threads(:) // omp60-error {{expected expression}}
// Invalid: missing colon after modifier
- #pragma omp parallel num_threads(strict 4) // omp60-error {{missing ':'
after strict modifier}}
+ #pragma omp parallel num_threads(strict 4) // omp60-error {{missing ':'
after num_threads modifier}}
// Invalid: negative, zero, or non-integral
#pragma omp parallel num_threads(strict: -1) // omp60-error {{argument to
'num_threads' clause must be a strictly positive integer value}}
#pragma omp parallel num_threads(strict: 0) // omp60-error {{argument to
'num_threads' clause must be a strictly positive integer value}}
#pragma omp parallel num_threads(strict: (argc > 0) ? argv[1] : argv[2]) //
omp60-error {{expression must have integral or unscoped enumeration type, not
'char *'}}
#pragma omp parallel num_threads(strict: S1) // omp60-error {{'S1' does not
refer to a value}}
- #pragma omp parallel num_threads(strict: argv[1]=2) // omp60-error
{{expected ')'}} omp60-note {{to match this '('}} omp60-error {{expression must
have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel num_threads(strict: argv[1]=2) // omp60-error
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
// Invalid: multiple strict modifiers or mixed with non-strict
- #pragma omp parallel num_threads(strict: 4, strict: 5) // omp60-error
{{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp parallel num_threads(strict: 4, strict: 5) // omp60-error {{use
of undeclared identifier 'strict'}}
#pragma omp parallel num_threads(strict: 4), num_threads(5) // omp60-error
{{directive '#pragma omp parallel' cannot contain more than one 'num_threads'
clause}}
#pragma omp parallel num_threads(4), num_threads(strict: 5) // omp60-error
{{directive '#pragma omp parallel' cannot contain more than one 'num_threads'
clause}}
#endif // OMP60
diff --git a/clang/test/OpenMP/parallel_sections_num_threads_messages.cpp
b/clang/test/OpenMP/parallel_sections_num_threads_messages.cpp
index 31434e4757ab2..f396eb41e983e 100644
--- a/clang/test/OpenMP/parallel_sections_num_threads_messages.cpp
+++ b/clang/test/OpenMP/parallel_sections_num_threads_messages.cpp
@@ -30,7 +30,7 @@ T tmain(T argc, S **argv) {
{foo();}
#pragma omp parallel sections num_threads (S) // expected-error {{'S' does
not refer to a value}}
{foo();}
- #pragma omp parallel sections num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error 2
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel sections num_threads (argv[1]=2) // expected-error 2
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
{foo();}
#pragma omp parallel sections num_threads (argc + z)
{foo();}
@@ -58,7 +58,7 @@ int main(int argc, char **argv) {
{foo();}
#pragma omp parallel sections num_threads (S1) // expected-error {{'S1' does
not refer to a value}}
{foo();}
- #pragma omp parallel sections num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp parallel sections num_threads (argv[1]=2) // expected-error
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
{foo();}
#pragma omp parallel sections num_threads (num_threads(tmain<int, char,
-1>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match
this '('}} expected-note {{in instantiation of function template specialization
'tmain<int, char, -1>' requested here}}
{foo();}
diff --git a/clang/test/OpenMP/target_parallel_for_num_threads_messages.cpp
b/clang/test/OpenMP/target_parallel_for_num_threads_messages.cpp
index 11f0c90780471..fddf0f8b05ef2 100644
--- a/clang/test/OpenMP/target_parallel_for_num_threads_messages.cpp
+++ b/clang/test/OpenMP/target_parallel_for_num_threads_messages.cpp
@@ -30,7 +30,7 @@ T tmain(T argc, S **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for num_threads (S) // expected-error {{'S' does
not refer to a value}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error 2
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp target parallel for num_threads (argv[1]=2) // expected-error 2
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for num_threads (argc)
for (i = 0; i < argc; ++i) foo();
@@ -58,7 +58,7 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for num_threads (S1) // expected-error {{'S1'
does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp target parallel for num_threads (argv[1]=2) // expected-error
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for num_threads (num_threads(tmain<int, char,
-1>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match
this '('}} expected-note {{in instantiation of function template specialization
'tmain<int, char, -1>' requested here}}
for (i = 0; i < argc; ++i) foo();
diff --git
a/clang/test/OpenMP/target_parallel_for_simd_num_threads_messages.cpp
b/clang/test/OpenMP/target_parallel_for_simd_num_threads_messages.cpp
index f7979057ae2b4..39b75ce91de8f 100644
--- a/clang/test/OpenMP/target_parallel_for_simd_num_threads_messages.cpp
+++ b/clang/test/OpenMP/target_parallel_for_simd_num_threads_messages.cpp
@@ -30,7 +30,7 @@ T tmain(T argc, S **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd num_threads (S) // expected-error {{'S'
does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for simd num_threads (argv[1]=2) //
expected-error {{expected ')'}} expected-note {{to match this '('}}
expected-error 2 {{expression must have integral or unscoped enumeration type,
not 'char *'}}
+ #pragma omp target parallel for simd num_threads (argv[1]=2) //
expected-error 2 {{incompatible integer to pointer conversion assigning to
'char *' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd num_threads (argc)
for (i = 0; i < argc; ++i) foo();
@@ -58,7 +58,7 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd num_threads (S1) // expected-error
{{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for simd num_threads (argv[1]=2) //
expected-error {{expected ')'}} expected-note {{to match this '('}}
expected-error {{expression must have integral or unscoped enumeration type,
not 'char *'}}
+ #pragma omp target parallel for simd num_threads (argv[1]=2) //
expected-error {{incompatible integer to pointer conversion assigning to 'char
*' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd num_threads (num_threads(tmain<int,
char, -1>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to
match this '('}} expected-note {{in instantiation of function template
specialization 'tmain<int, char, -1>' requested here}}
for (i = 0; i < argc; ++i) foo();
diff --git a/clang/test/OpenMP/target_parallel_num_threads_messages.cpp
b/clang/test/OpenMP/target_parallel_num_threads_messages.cpp
index 64e9929d68101..19d40a3448cef 100644
--- a/clang/test/OpenMP/target_parallel_num_threads_messages.cpp
+++ b/clang/test/OpenMP/target_parallel_num_threads_messages.cpp
@@ -34,7 +34,7 @@ T tmain(T argc, S **argv) {
foo();
#pragma omp target parallel num_threads (S) // expected-error {{'S' does not
refer to a value}}
foo();
- #pragma omp target parallel num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error 2
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp target parallel num_threads (argv[1]=2) // expected-error 2
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
foo();
#pragma omp target parallel num_threads (argc + z)
foo();
@@ -59,15 +59,15 @@ T tmain(T argc, S **argv) {
foo();
// Invalid: unknown/missing modifier
- #pragma omp target parallel num_threads(foo: 4) // omp60-error {{expected
'strict' in OpenMP clause 'num_threads'}}
+ #pragma omp target parallel num_threads(foo: 4) // omp60-error {{expected
',' or ')' in 'num_threads' clause}} omp60-error {{expected ')'}} omp60-note
{{to match this '('}} omp60-error 3 {{expression must have integral or unscoped
enumeration type, not 'void ()'}}
foo();
- #pragma omp target parallel num_threads(: 4) // omp60-error {{expected
expression}} omp60-error {{expected ')'}} omp60-note {{to match this '('}}
+ #pragma omp target parallel num_threads(: 4) // omp60-error {{expected
expression}}
foo();
- #pragma omp target parallel num_threads(:)// omp60-error {{expected
expression}} omp60-error {{expected ')'}} omp60-note {{to match this '('}}
+ #pragma omp target parallel num_threads(:)// omp60-error {{expected
expression}}
foo();
// Invalid: missing colon after modifier
- #pragma omp target parallel num_threads(strict 4) // omp60-error {{missing
':' after strict modifier}}
+ #pragma omp target parallel num_threads(strict 4) // omp60-error {{missing
':' after num_threads modifier}}
foo();
// Invalid: negative, zero, or non-integral
@@ -79,13 +79,13 @@ T tmain(T argc, S **argv) {
foo();
#pragma omp target parallel num_threads(strict: S) // omp60-error {{'S' does
not refer to a value}}
foo();
- #pragma omp target parallel num_threads(strict: argv[1]=2) // omp60-error
{{expected ')'}} omp60-note {{to match this '('}} omp60-error 2 {{expression
must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp target parallel num_threads(strict: argv[1]=2) // omp60-error 2
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
foo();
#pragma omp target parallel num_threads(strict: N) // omp60-error {{argument
to 'num_threads' clause must be a strictly positive integer value}}
foo();
// Invalid: multiple strict modifiers or mixed with non-strict
- #pragma omp target parallel num_threads(strict: 4, strict: 5) // omp60-error
{{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp target parallel num_threads(strict: 4, strict: 5) // omp60-error
{{use of undeclared identifier 'strict'}}
foo();
#pragma omp target parallel num_threads(strict: 4), num_threads(5) //
omp60-error {{directive '#pragma omp target parallel' cannot contain more than
one 'num_threads' clause}}
foo();
@@ -114,7 +114,7 @@ int main(int argc, char **argv) {
foo();
#pragma omp target parallel num_threads (S1) // expected-error {{'S1' does
not refer to a value}}
foo();
- #pragma omp target parallel num_threads (argv[1]=2) // expected-error
{{expected ')'}} expected-note {{to match this '('}} expected-error
{{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp target parallel num_threads (argv[1]=2) // expected-error
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
foo();
#pragma omp target parallel num_threads (num_threads(tmain<int, char,
-1>(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match
this '('}} expected-note {{in instantiation of function template specialization
'tmain<int, char, -1>' requested here}}
foo();
@@ -137,15 +137,15 @@ int main(int argc, char **argv) {
foo();
// Invalid: unknown/missing modifier
- #pragma omp target parallel num_threads(foo: 4) // omp60-error {{expected
'strict' in OpenMP clause 'num_threads'}}
+ #pragma omp target parallel num_threads(foo: 4) // omp60-error {{expected
',' or ')' in 'num_threads' clause}} omp60-error {{expected ')'}} omp60-note
{{to match this '('}} omp60-error {{expression must have integral or unscoped
enumeration type, not 'void ()'}}
foo();
- #pragma omp target parallel num_threads(: 4) // omp60-error {{expected
expression}} omp60-error {{expected ')'}} omp60-note {{to match this '('}}
+ #pragma omp target parallel num_threads(: 4) // omp60-error {{expected
expression}}
foo();
- #pragma omp target parallel num_threads(:) // omp60-error {{expected
expression}} omp60-error {{expected ')'}} omp60-note {{to match this '('}}
+ #pragma omp target parallel num_threads(:) // omp60-error {{expected
expression}}
foo();
// Invalid: missing colon after modifier
- #pragma omp target parallel num_threads(strict 4) // omp60-error {{missing
':' after strict modifier}}
+ #pragma omp target parallel num_threads(strict 4) // omp60-error {{missing
':' after num_threads modifier}}
foo();
// Invalid: negative, zero, or non-integral
@@ -157,11 +157,11 @@ int main(int argc, char **argv) {
foo();
#pragma omp target parallel num_threads(strict: S1) // omp60-error {{'S1'
does not refer to a value}}
foo();
- #pragma omp target parallel num_threads(strict: argv[1]=2) // omp60-error
{{expected ')'}} omp60-note {{to match this '('}} omp60-error {{expression must
have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp target parallel num_threads(strict: argv[1]=2) // omp60-error
{{incompatible integer to pointer conversion assigning to 'char *' from 'int'}}
foo();
// Invalid: multiple strict modifiers or mixed with non-strict
- #pragma omp target parallel num_threads(strict: 4, strict: 5) // omp60-error
{{expected ')'}} expected-note {{to match this '('}}
+ #pragma omp target parallel num_threads(strict: 4, strict: 5) // omp60-error
{{use of undeclared identifier 'strict'}}
foo();
#pragma omp target parallel num_threads(strict: 4), num_threads(5) //
omp60-error {{directive '#pragma omp target parallel' cannot contain more than
one 'num_threads' clause}}
foo();
diff --git
a/clang/test/OpenMP/target_teams_distribute_parallel_for_num_threads_messages.cpp
b/clang/test/OpenMP/target_teams_distribute_parallel_for_num_threads_messages.cpp
index d4b0c02c4393e..61690f0f052d6 100644
---
a/clang/test/OpenMP/target_teams_distribute_parallel_for_num_threads_messages.cpp
+++
b/clang/test/OpenMP/target_teams_distribute_parallel_for_num_threads_messages.cpp
@@ -30,7 +30,7 @@ T tmain(T argc, S **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for num_threads (S) //
expected-error {{'S' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for num_threads (argv[1]=2) //
expected-error {{expected ')'}} expected-note {{to match this '('}}
expected-error 2 {{expression must have integral or unscoped enumeration type,
not 'char *'}}
+#pragma omp target teams distribute parallel for num_threads (argv[1]=2) //
expected-error 2 {{incompatible integer to pointer conversion assigning to
'char *' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for num_threads (argc)
for (i = 0; i < argc; ++i) foo();
@@ -58,7 +58,7 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for num_threads (S1) //
expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for num_threads (argv[1]=2) //
expected-error {{expected ')'}} expected-note {{to match this '('}}
expected-error {{expression must have integral or unscoped enumeration type,
not 'char *'}}
+#pragma omp target teams distribute parallel for num_threads (argv[1]=2) //
expected-error {{incompatible integer to pointer conversion assigning to 'char
*' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for num_threads
(num_threads(tmain<int, char, -1>(argc, argv) // expected-error 2 {{expected
')'}} expected-note 2 {{to match this '('}} expected-note {{in instantiation of
function template specialization 'tmain<int, char, -1>' requested here}}
for (i = 0; i < argc; ++i) foo();
diff --git
a/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_num_threads_messages.cpp
b/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_num_threads_messages.cpp
index 397c83d199e9e..017cdff2f28d9 100644
---
a/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_num_threads_messages.cpp
+++
b/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_num_threads_messages.cpp
@@ -30,7 +30,7 @@ T tmain(T argc, S **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd num_threads (S) //
expected-error {{'S' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for simd num_threads (argv[1]=2)
// expected-error {{expected ')'}} expected-note {{to match this '('}}
expected-error 2 {{expression must have integral or unscoped enumeration type,
not 'char *'}}
+#pragma omp target teams distribute parallel for simd num_threads (argv[1]=2)
// expected-error 2 {{incompatible integer to pointer conversion assigning to
'char *' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd num_threads (argc + k)
for (i = 0; i < argc; ++i) foo();
@@ -58,7 +58,7 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd num_threads (S1) //
expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for simd num_threads (argv[1]=2)
// expected-error {{expected ')'}} expected-note {{to match this '('}}
expected-error {{expression must have integral or unscoped enumeration type,
not 'char *'}}
+#pragma omp target teams distribute parallel for simd num_threads (argv[1]=2)
// expected-error {{incompatible integer to pointer conversion assigning to
'char *' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd num_threads
(num_threads(tmain<int, char, -1>(argc, argv) // expected-error 2 {{expected
')'}} expected-note 2 {{to match this '('}} expected-note {{in instantiation of
function template specialization 'tmain<int, char, -1>' requested here}}
for (i = 0; i < argc; ++i) foo();
diff --git
a/clang/test/OpenMP/teams_distribute_parallel_for_simd_num_threads_messages.cpp
b/clang/test/OpenMP/teams_distribute_parallel_for_simd_num_threads_messages.cpp
index 6ff5db319a985..4f24e7bd09356 100644
---
a/clang/test/OpenMP/teams_distribute_parallel_for_simd_num_threads_messages.cpp
+++
b/clang/test/OpenMP/teams_distribute_parallel_for_simd_num_threads_messages.cpp
@@ -39,7 +39,7 @@ T tmain(T argc, S **argv) {
#pragma omp teams distribute parallel for simd num_threads (S) //
expected-error {{'S' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target
-#pragma omp teams distribute parallel for simd num_threads (argv[1]=2) //
expected-error {{expected ')'}} expected-note {{to match this '('}}
expected-error 2 {{expression must have integral or unscoped enumeration type,
not 'char *'}}
+#pragma omp teams distribute parallel for simd num_threads (argv[1]=2) //
expected-error 2 {{incompatible integer to pointer conversion assigning to
'char *' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams distribute parallel for simd num_threads (argc)
@@ -78,7 +78,7 @@ int main(int argc, char **argv) {
#pragma omp teams distribute parallel for simd num_threads (S1) //
expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target
-#pragma omp teams distribute parallel for simd num_threads (argv[1]=2) //
expected-error {{expected ')'}} expected-note {{to match this '('}}
expected-error {{expression must have integral or unscoped enumeration type,
not 'char *'}}
+#pragma omp teams distribute parallel for simd num_threads (argv[1]=2) //
expected-error {{incompatible integer to pointer conversion assigning to 'char
*' from 'int'}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams distribute parallel for simd num_threads
(num_threads(tmain<int, char, -1>(argc, argv) // expected-error 2 {{expected
')'}} expected-note 2 {{to match this '('}} expected-note {{in instantiation of
function template specialization 'tmain<int, char, -1>' requested here}}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index af9dc02656597..7a8f49e620ea9 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -2339,8 +2339,10 @@ void OMPClauseEnqueue::VisitOMPFinalClause(const
OMPFinalClause *C) {
}
void OMPClauseEnqueue::VisitOMPNumThreadsClause(const OMPNumThreadsClause *C) {
+ if (const Expr *Modifier = C->getDimsModifierExpr())
+ Visitor->AddStmt(Modifier);
+ VisitOMPClauseList(C);
VisitOMPClauseWithPreInit(C);
- Visitor->AddStmt(C->getNumThreads());
}
void OMPClauseEnqueue::VisitOMPSafelenClause(const OMPSafelenClause *C) {
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits