[clang] [Clang][OpenMP] Add parsing/sema for dims modifier in num_threads (PR #208353)
Kevin Sala Penades via cfe-commits
cfe-commits at lists.llvm.org
Sun Aug 23 23:09:47 PDT 2026
https://github.com/kevinsala updated https://github.com/llvm/llvm-project/pull/208353
>From 568d34d7a76a209d44eaf534d8a8e884f752cf4c Mon Sep 17 00:00:00 2001
From: Kevin Sala <salapenades1 at llnl.gov>
Date: Wed, 8 Jul 2026 13:14:49 -0700
Subject: [PATCH 1/3] [Clang][OpenMP] Add parsing/sema for dims modifier in
num_threads
---
clang/docs/OpenMPSupport.md | 2 +-
clang/docs/ReleaseNotes.md | 4 +-
clang/include/clang/AST/OpenMPClause.h | 185 ++++++++++++++----
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 | 114 +++++++----
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 +-
33 files changed, 583 insertions(+), 201 deletions(-)
diff --git a/clang/docs/OpenMPSupport.md b/clang/docs/OpenMPSupport.md
index 840cc5ef0fecd..47440be886c8e 100644
--- a/clang/docs/OpenMPSupport.md
+++ b/clang/docs/OpenMPSupport.md
@@ -389,7 +389,7 @@ implementation.
| attach map-type modifier | {part}`In Progress` | {none}`unclaimed` | C/C++: @abhinavgaba; RT: @abhinavgaba ([PR149036][PR149036], [PR158370][PR158370], [PR210213][PR210213]) |
| need_device_ptr modifier for adjust_args clause | {part}`partial` | {none}`unclaimed` | Clang Parsing/Sema: [PR168905][PR168905] [PR169558][PR169558] |
| fallback modifier for use_device_ptr clause | {good}`done` | {none}`unclaimed` | Clang: @abhinavgaba ([PR170578][PR170578], [PR173931][PR173931]) RT: @abhinavgaba ([PR169603][PR169603]) |
-| dims modifier for num_teams, thread_limit, and num_threads clauses | {part}`partial` | {part}`In Progress` | C/C++: @kevinsala ([PR206412]); Fortran: @skc7, @kparzysz, @mjklemm |
+| dims modifier for num_teams, thread_limit, and num_threads clauses | {part}`partial` | {part}`In Progress` | C/C++: @kevinsala ([PR206412][PR208353]); Fortran: @skc7, @kparzysz, @mjklemm |
## OpenMP Extensions
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 8c9467ca7b742..aad00692a83ad 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -678,8 +678,8 @@ features cannot lower the translation-unit ABI level;
### OpenMP Support
-- Added parsing and semantic support for `dims` modifier in `num_teams` and
- `thread_limit` clauses for OpenMP 6.1 or later.
+- Added parsing and semantic support for `dims` modifier in `num_teams`,
+ `thread_limit` and `num_threads` clauses for OpenMP 6.1 or later.
- Map-type-modifying modifiers applied to a list item with a user-defined mapper
are now propagated onto the maps the mapper expands to.
- Mapping of expressions with base-pointers through a user-defined mapper (e.g.
diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h
index 9e9295e1a0c54..db490ff9951b8 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -804,67 +804,176 @@ 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 1f7c8d762e1b5..02925500bd467 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3530,8 +3530,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 361473140e236..edb72931955d0 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 cac701994def8..2061d5395ac65 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -1989,6 +1989,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
//===----------------------------------------------------------------------===//
@@ -2008,14 +2037,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 dca2c49ac45d5..93b5190002707 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -486,9 +486,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 173931213ce68..5d73575e3fe53 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -6211,6 +6211,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 5f85c2d97ad50..4b8b1de973407 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -6708,7 +6708,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 =
@@ -6894,8 +6894,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 122e5db698548..86727e3db5bcc 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -1914,9 +1914,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();
@@ -2114,7 +2114,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 30b6c64e69f4c..0e64f6f8bd8ba 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -3255,7 +3255,6 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
switch (CKind) {
case OMPC_final:
- case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_collapse:
@@ -3322,7 +3321,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);
@@ -3460,6 +3459,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)
@@ -4370,33 +4370,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());
@@ -4417,11 +4390,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(
@@ -5400,6 +5373,79 @@ 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 {
+ OpenMPNumThreadsClauseModifier Modifier =
+ static_cast<OpenMPNumThreadsClauseModifier>(
+ getOpenMPSimpleClauseType(
+ Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok),
+ 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 b39dd853ab378..2798ba5a9dc7e 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -17446,43 +17446,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(
@@ -18507,13 +18526,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:
@@ -19460,10 +19472,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 6aae98b3df7b5..a01d3d910ea5b 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1732,14 +1732,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.
@@ -10830,12 +10833,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 167cb58eb131e..b3bc01c52a353 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -11469,7 +11469,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();
@@ -11884,11 +11884,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 4e9af7c721d2f..3061adf2dd3ca 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -8075,11 +8075,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 7c0df17e6a96b..c20dd5a3f8b09 100644
--- a/clang/test/OpenMP/dims_modifier_messages.cpp
+++ b/clang/test/OpenMP/dims_modifier_messages.cpp
@@ -8,18 +8,26 @@ 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 at -1 {{use of undeclared identifier 'dim'}}
// expected-error at -2 {{expected ',' or ')' in 'thread_limit' clause}}
// expected-error at -3 {{unexpected number of expressions in 'thread_limit' clause (expected 1, have 3)}}
foo();
+#pragma omp parallel num_threads(dim(2) 4, 5)
+ // expected-error at -1 {{use of undeclared identifier 'dim'}}
+ // expected-error at -2 {{expected ',' or ')' in 'num_threads' clause}}
+ foo();
+
#pragma omp target thread_limit(dims((2): 4, 5)
// expected-error at -1 {{expected ')'}}
// expected-error at -2 {{expected ')'}}
@@ -28,17 +36,36 @@ void bar(int N) { // expected-note {{declared here}}
// expected-error at -5 {{missing ':' after thread_limit modifier}}
foo();
+#pragma omp parallel num_threads(dims((2): 4, 5)
+ // expected-error at -1 {{expected ')'}}
+ // expected-error at -2 {{expected ')'}}
+ // expected-note at -3 {{to match this '('}}
+ // expected-note at -4 {{to match this '('}}
+ // expected-error at -5 {{missing ':' after num_threads modifier}}
+ foo();
+
#pragma omp target thread_limit(dims(2)): 4, 5)
// expected-error at -1 {{missing ':' after thread_limit modifier}}
// expected-warning at -2 {{extra tokens at the end of '#pragma omp target' are ignored}}
foo();
+#pragma omp parallel num_threads(dims(2)): 4, 5)
+ // expected-error at -1 {{missing ':' after num_threads modifier}}
+ // expected-warning at -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}}
@@ -52,6 +79,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 (expected 1, have 2)}}
foo();
+#pragma omp parallel num_threads(dims(2): 4) // expected-error {{unexpected number of expressions in 'num_threads' clause (expected 2, have 1)}}
+ foo();
+
#pragma omp target teams distribute num_teams(dims(3): 4, 5) // expected-error {{unexpected number of expressions in 'num_teams' clause (expected 3, have 2)}}
for (int i = 0; i < 10; ++i) {}
@@ -63,6 +93,9 @@ void bar(int N) { // expected-note {{declared here}}
#pragma omp target thread_limit(dims(4): 1, 2, 3, 4) // expected-error {{maximum three expressions are supported 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) {}
@@ -81,15 +114,26 @@ void bar(int N) { // expected-note {{declared here}}
// expected-note at -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 at -1 {{expression is not an integral constant expression}}
+ // expected-note at -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();
+
// 6. Coverage of directives.
#pragma omp target teams num_teams(dims(2): 4) // expected-error {{unexpected number of expressions in 'num_teams' clause (expected 2, have 1)}}
@@ -197,6 +241,11 @@ void template_test() {
// expected-error at -2 {{argument to 'thread_limit' clause must be a strictly positive integer value}}
foo();
+#pragma omp parallel num_threads(dims(D): 4)
+ // expected-error at -1 {{unexpected number of expressions in 'num_threads' clause}}
+ // expected-error at -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 at -1 {{unexpected number of expressions in 'num_teams' clause}}
// expected-error at -2 {{argument to 'num_teams' clause must be a strictly positive integer value}}
@@ -218,5 +267,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 47d6d2cb51efd..8aed1be034189 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -2356,8 +2356,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) {
>From 3d25d7d358f8091e7f496af4ca155f66da664056 Mon Sep 17 00:00:00 2001
From: Kevin Sala <salapenades1 at llnl.gov>
Date: Thu, 9 Jul 2026 15:45:07 -0700
Subject: [PATCH 2/3] Fix review comments
---
clang/lib/CodeGen/CGExprScalar.cpp | 1 -
clang/lib/Parse/ParseOpenMP.cpp | 16 ++++++++++------
clang/lib/Sema/SemaOpenMP.cpp | 17 +++++++++++++++++
3 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 5d73575e3fe53..173931213ce68 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -6211,7 +6211,6 @@ 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/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 0e64f6f8bd8ba..d302c5f895c4a 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -5381,7 +5381,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
while (true) {
if (Tok.is(tok::identifier) && Tok.getIdentifierInfo()->isStr("dims") &&
NextToken().is(tok::l_paren)) {
-
+ // Parse the dims modifier.
SourceLocation TLoc = Tok.getLocation();
ConsumeToken();
SourceLocation RLoc;
@@ -5400,20 +5400,22 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
}
HasModifier = true;
} else {
+ // Parse any modifier other than dims.
OpenMPNumThreadsClauseModifier Modifier =
static_cast<OpenMPNumThreadsClauseModifier>(
getOpenMPSimpleClauseType(
Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok),
getLangOpts()));
- // The dims modifier is a complex modifier. It must be parsed above.
+ // The dims modifier is a complex modifier that must be parsed above.
if (Modifier == OMPC_NUMTHREADS_dims)
Modifier = OMPC_NUMTHREADS_unknown;
if (Modifier != OMPC_NUMTHREADS_unknown) {
+ // Only prescriptiveness modifiers should enter this part.
if (Data.ExtraModifierArray[0] != OMPC_NUMTHREADS_unknown) {
Diag(Tok, diag::err_omp_duplicate_modifier)
- << getOpenMPSimpleClauseTypeName(Kind, OMPC_NUMTHREADS_strict)
+ << getOpenMPSimpleClauseTypeName(Kind, Modifier)
<< getOpenMPClauseName(Kind);
} else {
Data.ExtraModifierArray[0] = Modifier;
@@ -5422,17 +5424,19 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
ConsumeAnyToken();
HasModifier = true;
} else {
+ // Not a recognized modifier.
break;
}
}
- if (Tok.is(tok::comma)) {
+ // If a comma is present, continue parsing modifiers, and stop otherwise.
+ if (Tok.is(tok::comma))
ConsumeToken();
- } else {
+ else
break;
- }
}
+ // If any modifier was parsed, the next token must be a colon.
if (HasModifier) {
if (Tok.is(tok::colon)) {
ConsumeToken();
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 2798ba5a9dc7e..de6373ca90da9 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -17452,6 +17452,18 @@ OMPClause *SemaOpenMP::ActOnOpenMPNumThreadsClause(
OpenMPNumThreadsClauseModifier DimsModifier, Expr *DimsModifierExpr,
SourceLocation DimsModifierLoc, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc) {
+ assert((PrescriptivenessModifier == (PrescriptivenessModifierLoc.isValid()
+ ? OMPC_NUMTHREADS_strict
+ : OMPC_NUMTHREADS_unknown)) &&
+ "Unexpected num_threads prescriptiveness modifier.");
+ assert(
+ (DimsModifier == (DimsModifierLoc.isValid() ? OMPC_NUMTHREADS_dims
+ : OMPC_NUMTHREADS_unknown)) &&
+ "Unexpected num_threads dims modifier.");
+
+ if (VarList.empty())
+ return nullptr;
+
SmallVector<Expr *, 3> Vars(VarList.begin(), VarList.end());
for (Expr *&ValExpr : Vars) {
// OpenMP [2.5, Restrictions]
@@ -17496,6 +17508,11 @@ OMPClause *SemaOpenMP::ActOnOpenMPNumThreadsClause(
ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
}
+ if (DimsModifierExpr) {
+ DimsModifierExpr = SemaRef.MakeFullExpr(DimsModifierExpr).get();
+ DimsModifierExpr =
+ tryBuildCapture(SemaRef, DimsModifierExpr, Captures).get();
+ }
Stmt *PreInit = buildPreInits(getASTContext(), Captures);
return OMPNumThreadsClause::Create(
>From 45f81bca595e0ba5e4db2eb5eb782da774ef6a10 Mon Sep 17 00:00:00 2001
From: Kevin Sala <salapenades1 at llnl.gov>
Date: Sun, 23 Aug 2026 22:43:24 -0700
Subject: [PATCH 3/3] Improve sema for num_threads
---
.../clang/Basic/DiagnosticParseKinds.td | 2 +
.../clang/Basic/DiagnosticSemaKinds.td | 3 +-
clang/include/clang/Sema/SemaOpenMP.h | 9 +--
clang/lib/Parse/ParseOpenMP.cpp | 39 +++++-----
clang/lib/Sema/SemaOpenMP.cpp | 76 +++++++++++--------
clang/test/OpenMP/dims_modifier_messages.cpp | 9 ++-
6 files changed, 74 insertions(+), 64 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 6a48d74079f4e..165ca43b35929 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1752,6 +1752,8 @@ def warn_omp_invalid_attribute_for_ompx_attributes : Warning<"'ompx_attribute' c
"%0 is ignored">, InGroup<OpenMPExtensions>;
def err_omp_duplicate_modifier : Error<"duplicate modifier '%0' in '%1' clause">;
def err_omp_expected_modifier : Error<"expected modifier in '%0' clause">;
+def err_omp_incompatible_modifiers
+ : Error<"'%0' modifier cannot be specified with '%1' modifier in '%2' clause">;
def err_omp_unknown_need_device_ptr_kind
: Error<
"invalid argument for 'need_device_ptr' kind in 'adjust_args' clause; "
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 3a910c9c3f2b9..053eb5d28dadf 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12840,8 +12840,7 @@ def err_omp_modifier_requires_version : Error<
"'%0' modifier in '%1' clause requires OpenMP %2 or later">;
def err_omp_unexpected_num_exprs
: Error<"unexpected number of expressions in '%0' clause (expected %1, have %2)">;
-def err_omp_incompatible_modifiers
- : Error<"'%0' modifier cannot be specified with '%1' modifier in '%2' clause">;
+def err_omp_malformed_complex_modifier : Error<"malformed '%0' complex modifier in '%1' clause">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h
index edb72931955d0..a5f357c15f5c4 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -898,11 +898,10 @@ class SemaOpenMP : public SemaBase {
SourceLocation EndLoc);
/// Called on well-formed 'num_threads' clause.
OMPClause *ActOnOpenMPNumThreadsClause(
- ArrayRef<Expr *> VarList,
- OpenMPNumThreadsClauseModifier PrescriptivenessModifier,
- SourceLocation PrescriptivenessModifierLoc,
- OpenMPNumThreadsClauseModifier DimsModifier, Expr *DimsModifierExpr,
- SourceLocation DimsModifierLoc, SourceLocation StartLoc,
+ ArrayRef<Expr *> VarList, OpenMPNumThreadsClauseModifier SimpleModifier,
+ SourceLocation SimpleModifierLoc,
+ OpenMPNumThreadsClauseModifier ComplexModifier, Expr *ComplexModifierExpr,
+ SourceLocation ComplexModifierLoc, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc);
/// Called on well-formed 'align' clause.
OMPClause *ActOnOpenMPAlignClause(Expr *Alignment, SourceLocation StartLoc,
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index d302c5f895c4a..5c73b6d430d77 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -5389,38 +5389,34 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
ExprResult ExprR =
ParseOpenMPParensExpr(getOpenMPClauseName(Kind), RLoc);
- if (Data.ExtraModifierArray[1] != OMPC_NUMTHREADS_unknown) {
- Diag(TLoc, diag::err_omp_duplicate_modifier)
+ if (Data.ExtraModifierArray[1] != OMPC_NUMTHREADS_unknown)
+ Diag(TLoc, diag::err_omp_incompatible_modifiers)
<< getOpenMPSimpleClauseTypeName(Kind, OMPC_NUMTHREADS_dims)
+ << getOpenMPSimpleClauseTypeName(Kind, Data.ExtraModifierArray[1])
<< getOpenMPClauseName(Kind);
- } else if (ExprR.isUsable()) {
- Data.ExtraModifierArray[1] = static_cast<int>(OMPC_NUMTHREADS_dims);
- Data.ExtraModifierExprArray[1] = ExprR.get();
- Data.ExtraModifierLocArray[1] = TLoc;
- }
+
+ Data.ExtraModifierArray[1] = static_cast<int>(OMPC_NUMTHREADS_dims);
+ Data.ExtraModifierExprArray[1] =
+ (ExprR.isUsable()) ? ExprR.get() : nullptr;
+ Data.ExtraModifierLocArray[1] = TLoc;
HasModifier = true;
} else {
- // Parse any modifier other than dims.
+ // Parse any other modifier.
OpenMPNumThreadsClauseModifier Modifier =
static_cast<OpenMPNumThreadsClauseModifier>(
getOpenMPSimpleClauseType(
Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok),
getLangOpts()));
- // The dims modifier is a complex modifier that must be parsed above.
- if (Modifier == OMPC_NUMTHREADS_dims)
- Modifier = OMPC_NUMTHREADS_unknown;
-
if (Modifier != OMPC_NUMTHREADS_unknown) {
- // Only prescriptiveness modifiers should enter this part.
- if (Data.ExtraModifierArray[0] != OMPC_NUMTHREADS_unknown) {
- Diag(Tok, diag::err_omp_duplicate_modifier)
+ if (Data.ExtraModifierArray[0] != OMPC_NUMTHREADS_unknown)
+ Diag(Tok, diag::err_omp_incompatible_modifiers)
<< getOpenMPSimpleClauseTypeName(Kind, Modifier)
+ << getOpenMPSimpleClauseTypeName(Kind,
+ Data.ExtraModifierArray[0])
<< getOpenMPClauseName(Kind);
- } else {
- Data.ExtraModifierArray[0] = Modifier;
- Data.ExtraModifierLocArray[0] = Tok.getLocation();
- }
+ Data.ExtraModifierArray[0] = Modifier;
+ Data.ExtraModifierLocArray[0] = Tok.getLocation();
ConsumeAnyToken();
HasModifier = true;
} else {
@@ -5438,9 +5434,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
// If any modifier was parsed, the next token must be a colon.
if (HasModifier) {
- if (Tok.is(tok::colon)) {
- ConsumeToken();
- } else {
+ if (!Tok.is(tok::colon)) {
Diag(Tok, diag::err_modifier_expected_colon)
<< getOpenMPClauseName(Kind);
SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);
@@ -5449,6 +5443,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
Data.RLoc = T.getCloseLocation();
return true;
}
+ ConsumeToken();
}
}
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index de6373ca90da9..7ddda157dad9d 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -17446,20 +17446,32 @@ static std::string getListOfPossibleValues(OpenMPClauseKind K, unsigned First,
}
OMPClause *SemaOpenMP::ActOnOpenMPNumThreadsClause(
- ArrayRef<Expr *> VarList,
- OpenMPNumThreadsClauseModifier PrescriptivenessModifier,
- SourceLocation PrescriptivenessModifierLoc,
- OpenMPNumThreadsClauseModifier DimsModifier, Expr *DimsModifierExpr,
- SourceLocation DimsModifierLoc, SourceLocation StartLoc,
+ ArrayRef<Expr *> VarList, OpenMPNumThreadsClauseModifier SimpleModifier,
+ SourceLocation SimpleModifierLoc,
+ OpenMPNumThreadsClauseModifier ComplexModifier, Expr *ComplexModifierExpr,
+ SourceLocation ComplexModifierLoc, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc) {
- assert((PrescriptivenessModifier == (PrescriptivenessModifierLoc.isValid()
- ? OMPC_NUMTHREADS_strict
- : OMPC_NUMTHREADS_unknown)) &&
- "Unexpected num_threads prescriptiveness modifier.");
- assert(
- (DimsModifier == (DimsModifierLoc.isValid() ? OMPC_NUMTHREADS_dims
- : OMPC_NUMTHREADS_unknown)) &&
- "Unexpected num_threads dims modifier.");
+ // Check that modifiers were correctly specified.
+ if (ComplexModifierLoc.isValid() &&
+ (ComplexModifier != OMPC_NUMTHREADS_dims || !ComplexModifierExpr)) {
+ Diag(ComplexModifierLoc, diag::err_omp_malformed_complex_modifier)
+ << getOpenMPSimpleClauseTypeName(OMPC_num_threads, OMPC_NUMTHREADS_dims)
+ << getOpenMPClauseName(OMPC_num_threads);
+ return nullptr;
+ }
+ if (SimpleModifierLoc.isValid() && SimpleModifier == OMPC_NUMTHREADS_dims) {
+ Diag(SimpleModifierLoc, diag::err_omp_malformed_complex_modifier)
+ << getOpenMPSimpleClauseTypeName(OMPC_num_threads, OMPC_NUMTHREADS_dims)
+ << getOpenMPClauseName(OMPC_num_threads);
+ return nullptr;
+ }
+ if (SimpleModifierLoc.isValid() && SimpleModifier != OMPC_NUMTHREADS_strict) {
+ Diag(SimpleModifierLoc, diag::err_omp_unexpected_clause_value)
+ << getOpenMPSimpleClauseTypeName(OMPC_num_threads,
+ OMPC_NUMTHREADS_strict)
+ << getOpenMPClauseName(OMPC_num_threads);
+ return nullptr;
+ }
if (VarList.empty())
return nullptr;
@@ -17473,24 +17485,22 @@ OMPClause *SemaOpenMP::ActOnOpenMPNumThreadsClause(
return nullptr;
}
- if (DimsModifier == OMPC_NUMTHREADS_dims) {
- ExprResult Res = ActOnOpenMPDimsModifier(OMPC_num_threads, DimsModifier,
- DimsModifierExpr, DimsModifierLoc,
- Vars, EndLoc);
+ if (ComplexModifier == OMPC_NUMTHREADS_dims) {
+ ExprResult Res = ActOnOpenMPDimsModifier(OMPC_num_threads, ComplexModifier,
+ ComplexModifierExpr,
+ ComplexModifierLoc, Vars, EndLoc);
if (Res.isInvalid())
return nullptr;
- DimsModifierExpr = Res.get();
+ ComplexModifierExpr = Res.get();
if (validateMultidimClauseExprs(*this, OMPC_num_threads, StartLoc, Vars,
- DimsModifierExpr))
+ ComplexModifierExpr))
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";
+ if (SimpleModifier == OMPC_NUMTHREADS_strict && getLangOpts().OpenMP < 60) {
+ Diag(SimpleModifierLoc, diag::err_omp_modifier_requires_version)
+ << getOpenMPSimpleClauseTypeName(OMPC_num_threads, SimpleModifier)
+ << getOpenMPClauseName(OMPC_num_threads) << "6.0";
return nullptr;
}
@@ -17500,25 +17510,25 @@ OMPClause *SemaOpenMP::ActOnOpenMPNumThreadsClause(
if (CaptureRegion == OMPD_unknown || SemaRef.CurContext->isDependentContext())
return OMPNumThreadsClause::Create(
getASTContext(), CaptureRegion, StartLoc, LParenLoc, EndLoc, Vars,
- PrescriptivenessModifier, DimsModifier, PrescriptivenessModifierLoc,
- DimsModifierLoc, DimsModifierExpr, /*PreInit=*/nullptr);
+ SimpleModifier, ComplexModifier, SimpleModifierLoc, ComplexModifierLoc,
+ ComplexModifierExpr, /*PreInit=*/nullptr);
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
for (Expr *&ValExpr : Vars) {
ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
}
- if (DimsModifierExpr) {
- DimsModifierExpr = SemaRef.MakeFullExpr(DimsModifierExpr).get();
- DimsModifierExpr =
- tryBuildCapture(SemaRef, DimsModifierExpr, Captures).get();
+ if (ComplexModifierExpr) {
+ ComplexModifierExpr = SemaRef.MakeFullExpr(ComplexModifierExpr).get();
+ ComplexModifierExpr =
+ tryBuildCapture(SemaRef, ComplexModifierExpr, Captures).get();
}
Stmt *PreInit = buildPreInits(getASTContext(), Captures);
return OMPNumThreadsClause::Create(
getASTContext(), CaptureRegion, StartLoc, LParenLoc, EndLoc, Vars,
- PrescriptivenessModifier, DimsModifier, PrescriptivenessModifierLoc,
- DimsModifierLoc, DimsModifierExpr, PreInit);
+ SimpleModifier, ComplexModifier, SimpleModifierLoc, ComplexModifierLoc,
+ ComplexModifierExpr, PreInit);
}
ExprResult SemaOpenMP::VerifyPositiveIntegerConstantInClause(
diff --git a/clang/test/OpenMP/dims_modifier_messages.cpp b/clang/test/OpenMP/dims_modifier_messages.cpp
index c20dd5a3f8b09..235cf288dcb80 100644
--- a/clang/test/OpenMP/dims_modifier_messages.cpp
+++ b/clang/test/OpenMP/dims_modifier_messages.cpp
@@ -14,7 +14,7 @@ void bar(int N) { // expected-note 2 {{declared here}}
#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'}}
+#pragma omp parallel num_threads(dims 2: 4) // expected-error {{missing ':' after num_threads modifier}}
foo();
#pragma omp target thread_limit(dim(2) 4, 5)
@@ -63,7 +63,12 @@ void bar(int N) { // expected-note 2 {{declared here}}
#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}}
+#pragma omp parallel num_threads(dims(): 4)
+ // expected-error at -1 {{expected expression}}
+ // expected-error at -2 {{malformed 'dims' complex modifier in 'num_threads' clause}}
+ foo();
+
+#pragma omp parallel num_threads(dims: 4) // expected-error {{malformed 'dims' complex modifier in 'num_threads' clause}}
foo();
// 3. Incompatible modifiers.
More information about the cfe-commits
mailing list