[flang-commits] [flang] [flang][OpenMP] Convert AST node for ALLOCATORS to use Block as body (PR #148005)
Krzysztof Parzyszek via flang-commits
flang-commits at lists.llvm.org
Fri Jul 11 04:02:53 PDT 2025
https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/148005
>From 0f4462c45fd80c5417a0970919e600b08ea6e2fa Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Thu, 10 Jul 2025 07:55:32 -0500
Subject: [PATCH 1/2] [flang][OpenMP] Convert AST node for ALLOCATORS to use
Block as body
The ALLOCATORS construct is one of the few constructs that require a
special form of the associated block.
Convert the AST node to use OmpDirectiveSpecification for the directive
and the optional end directive, and to use parser::Block as the body:
the form of the block is checked in the semantic checks (with a more
meaningful message).
---
flang/examples/FeatureList/FeatureList.cpp | 1 -
flang/include/flang/Parser/dump-parse-tree.h | 1 -
flang/include/flang/Parser/parse-tree.h | 21 ++--
flang/lib/Parser/openmp-parsers.cpp | 36 +++++--
flang/lib/Parser/unparse.cpp | 24 ++---
flang/lib/Semantics/check-omp-atomic.cpp | 31 ------
flang/lib/Semantics/check-omp-structure.cpp | 46 ++++++---
flang/lib/Semantics/openmp-utils.cpp | 20 ++++
flang/lib/Semantics/openmp-utils.h | 13 +++
flang/lib/Semantics/resolve-directives.cpp | 97 +++++++++++++------
.../test/Parser/OpenMP/allocators-unparse.f90 | 80 ++++++++-------
flang/test/Semantics/OpenMP/allocators07.f90 | 27 ++++++
12 files changed, 253 insertions(+), 144 deletions(-)
create mode 100644 flang/test/Semantics/OpenMP/allocators07.f90
diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp
index a36b8719e365d..e9aeed18ab0b7 100644
--- a/flang/examples/FeatureList/FeatureList.cpp
+++ b/flang/examples/FeatureList/FeatureList.cpp
@@ -472,7 +472,6 @@ struct NodeVisitor {
READ_FEATURE(OmpIteration)
READ_FEATURE(OmpIterationOffset)
READ_FEATURE(OmpIterationVector)
- READ_FEATURE(OmpEndAllocators)
READ_FEATURE(OmpEndBlockDirective)
READ_FEATURE(OmpEndCriticalDirective)
READ_FEATURE(OmpEndLoopDirective)
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index e3eed6aed8079..73c224e3ad235 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -578,7 +578,6 @@ class ParseTreeDumper {
NODE(parser, OmpDetachClause)
NODE(parser, OmpDoacrossClause)
NODE(parser, OmpDestroyClause)
- NODE(parser, OmpEndAllocators)
NODE(parser, OmpEndBlockDirective)
NODE(parser, OmpEndCriticalDirective)
NODE(parser, OmpEndLoopDirective)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 43954ff735361..fbc39286a95bf 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4598,8 +4598,11 @@ struct OmpClauseList {
struct OmpDirectiveSpecification {
ENUM_CLASS(Flags, None, DeprecatedSyntax);
TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification);
+ const OmpDirectiveName &DirName() const {
+ return std::get<OmpDirectiveName>(t);
+ }
llvm::omp::Directive DirId() const { //
- return std::get<OmpDirectiveName>(t).v;
+ return DirName().v;
}
const OmpArgumentList &Arguments() const;
const OmpClauseList &Clauses() const;
@@ -4839,17 +4842,17 @@ struct OpenMPExecutableAllocate {
t;
};
-EMPTY_CLASS(OmpEndAllocators);
-
-// 6.7 Allocators construct [OpenMP 5.2]
-// allocators-construct -> ALLOCATORS [allocate-clause [,]]
-// allocate-stmt
-// [omp-end-allocators-construct]
+// Ref: [5.2:180-181], [6.0:315]
+//
+// allocators-construct ->
+// ALLOCATORS [allocate-clause...]
+// block
+// [END ALLOCATORS]
struct OpenMPAllocatorsConstruct {
TUPLE_CLASS_BOILERPLATE(OpenMPAllocatorsConstruct);
CharBlock source;
- std::tuple<Verbatim, OmpClauseList, Statement<AllocateStmt>,
- std::optional<OmpEndAllocators>>
+ std::tuple<OmpDirectiveSpecification, Block,
+ std::optional<OmpDirectiveSpecification>>
t;
};
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 3016ce4ccd2f8..811ca2c855a6e 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1276,6 +1276,32 @@ struct OmpEndDirectiveParser {
llvm::omp::Directive dir_;
};
+struct OmpAllocatorsConstructParser {
+ using resultType = OpenMPAllocatorsConstruct;
+
+ std::optional<resultType> Parse(ParseState &state) const {
+ auto dirSpec{Parser<OmpDirectiveSpecification>{}.Parse(state)};
+ if (!dirSpec || dirSpec->DirId() != llvm::omp::Directive::OMPD_allocators) {
+ return std::nullopt;
+ }
+
+ // This should be an allocate-stmt. That will be checked in semantics.
+ Block block;
+ if (auto stmt{attempt(Parser<ExecutionPartConstruct>{}).Parse(state)}) {
+ block.emplace_back(std::move(*stmt));
+ }
+ // Allow empty block. Check for this in semantics.
+
+ auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_allocators}};
+ return OpenMPAllocatorsConstruct{
+ std::move(*dirSpec), std::move(block), *maybe(end).Parse(state)};
+ }
+};
+
+TYPE_PARSER(sourced( //
+ construct<OpenMPAllocatorsConstruct>(
+ "ALLOCATORS"_tok >= OmpAllocatorsConstructParser{})))
+
// Parser for an arbitrary OpenMP ATOMIC construct.
//
// Depending on circumstances, an ATOMIC construct applies to one or more
@@ -1622,16 +1648,6 @@ TYPE_PARSER(
maybe(nonemptyList(Parser<OpenMPDeclarativeAllocate>{})) / endOmpLine,
statement(allocateStmt))))
-// 6.7 Allocators construct [OpenMP 5.2]
-// allocators-construct -> ALLOCATORS [allocate-clause [,]]
-// allocate-stmt
-// [omp-end-allocators-construct]
-TYPE_PARSER(sourced(construct<OpenMPAllocatorsConstruct>(
- verbatim("ALLOCATORS"_tok), Parser<OmpClauseList>{} / endOmpLine,
- statement(allocateStmt), maybe(Parser<OmpEndAllocators>{} / endOmpLine))))
-
-TYPE_PARSER(construct<OmpEndAllocators>(startOmpLine >> "END ALLOCATORS"_tok))
-
// 2.8.2 Declare Simd construct
TYPE_PARSER(sourced(construct<OpenMPDeclareSimdConstruct>(
verbatim("DECLARE SIMD"_tok) || verbatim("DECLARE_SIMD"_tok),
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index dcd1ac165adc1..4f692f3e9084f 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2571,7 +2571,7 @@ class UnparseVisitor {
Word(ToUpperCaseLetters(common::EnumToString(x)));
}
- void Unparse(const OpenMPAtomicConstruct &x) {
+ template <typename Construct> void UnparseBlockConstruct(const Construct &x) {
BeginOpenMP();
Word("!$OMP ");
Walk(std::get<OmpDirectiveSpecification>(x.t));
@@ -2587,6 +2587,10 @@ class UnparseVisitor {
}
}
+ void Unparse(const OpenMPAtomicConstruct &x) { //
+ UnparseBlockConstruct(x);
+ }
+
void Unparse(const OpenMPExecutableAllocate &x) {
const auto &fields =
std::get<std::optional<std::list<parser::OpenMPDeclarativeAllocate>>>(
@@ -2614,22 +2618,8 @@ class UnparseVisitor {
Put("\n");
EndOpenMP();
}
- void Unparse(const OmpEndAllocators &x) {
- BeginOpenMP();
- Word("!$OMP END ALLOCATE");
- Put("\n");
- EndOpenMP();
- }
- void Unparse(const OpenMPAllocatorsConstruct &x) {
- BeginOpenMP();
- Word("!$OMP ALLOCATE");
- Walk(std::get<OmpClauseList>(x.t));
- Put("\n");
- EndOpenMP();
- Walk(std::get<Statement<AllocateStmt>>(x.t));
- if (const auto &end = std::get<std::optional<OmpEndAllocators>>(x.t)) {
- Walk(*end);
- }
+ void Unparse(const OpenMPAllocatorsConstruct &x) { //
+ UnparseBlockConstruct(x);
}
void Unparse(const OmpAssumeDirective &x) {
BeginOpenMP();
diff --git a/flang/lib/Semantics/check-omp-atomic.cpp b/flang/lib/Semantics/check-omp-atomic.cpp
index 047c604693460..c5ed8796f0c34 100644
--- a/flang/lib/Semantics/check-omp-atomic.cpp
+++ b/flang/lib/Semantics/check-omp-atomic.cpp
@@ -47,43 +47,12 @@ static bool operator!=(const evaluate::Expr<T> &e, const evaluate::Expr<U> &f) {
return !(e == f);
}
-// There is no consistent way to get the source of a given ActionStmt, so
-// extract the source information from Statement<ActionStmt> when we can,
-// and keep it around for error reporting in further analyses.
-struct SourcedActionStmt {
- const parser::ActionStmt *stmt{nullptr};
- parser::CharBlock source;
-
- operator bool() const { return stmt != nullptr; }
-};
-
struct AnalyzedCondStmt {
SomeExpr cond{evaluate::NullPointer{}}; // Default ctor is deleted
parser::CharBlock source;
SourcedActionStmt ift, iff;
};
-static SourcedActionStmt GetActionStmt(
- const parser::ExecutionPartConstruct *x) {
- if (x == nullptr) {
- return SourcedActionStmt{};
- }
- if (auto *exec{std::get_if<parser::ExecutableConstruct>(&x->u)}) {
- using ActionStmt = parser::Statement<parser::ActionStmt>;
- if (auto *stmt{std::get_if<ActionStmt>(&exec->u)}) {
- return SourcedActionStmt{&stmt->statement, stmt->source};
- }
- }
- return SourcedActionStmt{};
-}
-
-static SourcedActionStmt GetActionStmt(const parser::Block &block) {
- if (block.size() == 1) {
- return GetActionStmt(&block.front());
- }
- return SourcedActionStmt{};
-}
-
// Compute the `evaluate::Assignment` from parser::ActionStmt. The assumption
// is that the ActionStmt will be either an assignment or a pointer-assignment,
// otherwise return std::nullopt.
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 89c1565bf66aa..9b89d19a91f38 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -495,6 +495,12 @@ template <typename Checker> struct DirectiveSpellingVisitor {
template <typename T> bool Pre(const T &) { return true; }
template <typename T> void Post(const T &) {}
+ template <typename... Ts>
+ static const parser::OmpDirectiveName &GetDirName(
+ const std::tuple<Ts...> &t) {
+ return std::get<parser::OmpDirectiveSpecification>(t).DirName();
+ }
+
bool Pre(const parser::OmpSectionsDirective &x) {
checker_(x.source, x.v);
return false;
@@ -520,8 +526,7 @@ template <typename Checker> struct DirectiveSpellingVisitor {
return false;
}
bool Pre(const parser::OpenMPAllocatorsConstruct &x) {
- checker_(
- std::get<parser::Verbatim>(x.t).source, Directive::OMPD_allocators);
+ checker_(GetDirName(x.t).source, Directive::OMPD_allocators);
return false;
}
bool Pre(const parser::OmpAssumeDirective &x) {
@@ -1657,26 +1662,45 @@ void OmpStructureChecker::Leave(const parser::OpenMPExecutableAllocate &x) {
void OmpStructureChecker::Enter(const parser::OpenMPAllocatorsConstruct &x) {
isPredefinedAllocator = true;
- const auto &dir{std::get<parser::Verbatim>(x.t)};
- PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_allocators);
- const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
- for (const auto &clause : clauseList.v) {
+
+ auto &dirSpec{std::get<parser::OmpDirectiveSpecification>(x.t)};
+ auto &block{std::get<parser::Block>(x.t)};
+ PushContextAndClauseSets(
+ dirSpec.DirName().source, llvm::omp::Directive::OMPD_allocators);
+
+ if (block.empty()) {
+ context_.Say(dirSpec.source,
+ "The ALLOCATORS construct should contain a single ALLOCATE statement"_err_en_US);
+ return;
+ }
+
+ omp::SourcedActionStmt action{omp::GetActionStmt(block)};
+ const auto *allocate{
+ action ? parser::Unwrap<parser::AllocateStmt>(action.stmt) : nullptr};
+
+ if (!allocate) {
+ const parser::CharBlock &source = action ? action.source : x.source;
+ context_.Say(source,
+ "The body of the ALLOCATORS construct should be an ALLOCATE statement"_err_en_US);
+ }
+
+ for (const auto &clause : dirSpec.Clauses().v) {
if (const auto *allocClause{
parser::Unwrap<parser::OmpClause::Allocate>(clause)}) {
CheckVarIsNotPartOfAnotherVar(
- dir.source, std::get<parser::OmpObjectList>(allocClause->v.t));
+ dirSpec.source, std::get<parser::OmpObjectList>(allocClause->v.t));
}
}
}
void OmpStructureChecker::Leave(const parser::OpenMPAllocatorsConstruct &x) {
- const auto &dir{std::get<parser::Verbatim>(x.t)};
- const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
- for (const auto &clause : clauseList.v) {
+ auto &dirSpec{std::get<parser::OmpDirectiveSpecification>(x.t)};
+
+ for (const auto &clause : dirSpec.Clauses().v) {
if (const auto *allocClause{
std::get_if<parser::OmpClause::Allocate>(&clause.u)}) {
CheckPredefinedAllocatorRestriction(
- dir.source, std::get<parser::OmpObjectList>(allocClause->v.t));
+ dirSpec.source, std::get<parser::OmpObjectList>(allocClause->v.t));
}
}
dirContext_.pop_back();
diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp
index fd9596a09cd52..f43d2cc75620e 100644
--- a/flang/lib/Semantics/openmp-utils.cpp
+++ b/flang/lib/Semantics/openmp-utils.cpp
@@ -38,6 +38,26 @@
namespace Fortran::semantics::omp {
+SourcedActionStmt GetActionStmt(const parser::ExecutionPartConstruct *x) {
+ if (x == nullptr) {
+ return SourcedActionStmt{};
+ }
+ if (auto *exec{std::get_if<parser::ExecutableConstruct>(&x->u)}) {
+ using ActionStmt = parser::Statement<parser::ActionStmt>;
+ if (auto *stmt{std::get_if<ActionStmt>(&exec->u)}) {
+ return SourcedActionStmt{&stmt->statement, stmt->source};
+ }
+ }
+ return SourcedActionStmt{};
+}
+
+SourcedActionStmt GetActionStmt(const parser::Block &block) {
+ if (block.size() == 1) {
+ return GetActionStmt(&block.front());
+ }
+ return SourcedActionStmt{};
+}
+
std::string ThisVersion(unsigned version) {
std::string tv{
std::to_string(version / 10) + "." + std::to_string(version % 10)};
diff --git a/flang/lib/Semantics/openmp-utils.h b/flang/lib/Semantics/openmp-utils.h
index dbb0565215357..a96c008fb26e7 100644
--- a/flang/lib/Semantics/openmp-utils.h
+++ b/flang/lib/Semantics/openmp-utils.h
@@ -29,6 +29,19 @@ class Symbol;
// Add this namespace to avoid potential conflicts
namespace omp {
+// There is no consistent way to get the source of an ActionStmt, but there
+// is "source" in Statement<T>. This structure keeps the ActionStmt with the
+// extracted source for further use.
+struct SourcedActionStmt {
+ const parser::ActionStmt *stmt{nullptr};
+ parser::CharBlock source;
+
+ operator bool() const { return stmt != nullptr; }
+};
+
+SourcedActionStmt GetActionStmt(const parser::ExecutionPartConstruct *x);
+SourcedActionStmt GetActionStmt(const parser::Block &block);
+
std::string ThisVersion(unsigned version);
std::string TryVersion(unsigned version);
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 299bb6ff876e7..bb3914ffa2b1e 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -10,6 +10,7 @@
#include "check-acc-structure.h"
#include "check-omp-structure.h"
+#include "openmp-utils.h"
#include "resolve-names-utils.h"
#include "flang/Common/idioms.h"
#include "flang/Evaluate/fold.h"
@@ -353,12 +354,6 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
return true;
}
- bool Pre(const parser::OmpDirectiveSpecification &x) {
- PushContext(x.source, x.DirId());
- return true;
- }
- void Post(const parser::OmpDirectiveSpecification &) { PopContext(); }
-
bool Pre(const parser::OmpMetadirectiveDirective &x) {
PushContext(x.source, llvm::omp::Directive::OMPD_metadirective);
return true;
@@ -372,6 +367,29 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
GetContext().withinConstruct = true;
}
+ bool Pre(const parser::OpenMPStandaloneConstruct &x) {
+ common::visit(
+ [&](auto &&s) {
+ using TypeS = llvm::remove_cvref_t<decltype(s)>;
+ // These two cases are handled individually.
+ if constexpr ( //
+ !std::is_same_v<TypeS, parser::OpenMPSimpleStandaloneConstruct> &&
+ !std::is_same_v<TypeS, parser::OmpMetadirectiveDirective>) {
+ PushContext(x.source, s.v.DirId());
+ }
+ },
+ x.u);
+ return true;
+ }
+
+ void Post(const parser::OpenMPStandaloneConstruct &x) {
+ // These two cases are handled individually.
+ if (!std::holds_alternative<parser::OpenMPSimpleStandaloneConstruct>(x.u) &&
+ !std::holds_alternative<parser::OmpMetadirectiveDirective>(x.u)) {
+ PopContext();
+ }
+ }
+
bool Pre(const parser::OpenMPSimpleStandaloneConstruct &);
void Post(const parser::OpenMPSimpleStandaloneConstruct &) { PopContext(); }
@@ -2149,9 +2167,10 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPExecutableAllocate &x) {
}
bool OmpAttributeVisitor::Pre(const parser::OpenMPAllocatorsConstruct &x) {
- PushContext(x.source, llvm::omp::Directive::OMPD_allocators);
- const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
- for (const auto &clause : clauseList.v) {
+ auto &dirSpec{std::get<parser::OmpDirectiveSpecification>(x.t)};
+ PushContext(x.source, dirSpec.DirId());
+
+ for (const auto &clause : dirSpec.Clauses().v) {
if (const auto *allocClause{
std::get_if<parser::OmpClause::Allocate>(&clause.u)}) {
ResolveOmpObjectList(std::get<parser::OmpObjectList>(allocClause->v.t),
@@ -2234,31 +2253,47 @@ void OmpAttributeVisitor::Post(const parser::OpenMPExecutableAllocate &x) {
}
void OmpAttributeVisitor::Post(const parser::OpenMPAllocatorsConstruct &x) {
- const auto &dir{std::get<parser::Verbatim>(x.t)};
- const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
- for (const auto &clause : clauseList.v) {
- if (const auto *alloc{
- std::get_if<parser::OmpClause::Allocate>(&clause.u)}) {
- CheckAllNamesInAllocateStmt(dir.source,
- std::get<parser::OmpObjectList>(alloc->v.t),
- std::get<parser::Statement<parser::AllocateStmt>>(x.t).statement);
-
- auto &modifiers{OmpGetModifiers(alloc->v)};
- bool hasAllocator{
- OmpGetUniqueModifier<parser::OmpAllocatorSimpleModifier>(modifiers) ||
- OmpGetUniqueModifier<parser::OmpAllocatorComplexModifier>(modifiers)};
-
- // TODO: As with allocate directive, exclude the case when a requires
- // directive with the dynamic_allocators clause is present in
- // the same compilation unit (OMP5.0 2.11.3).
- if (IsNestedInDirective(llvm::omp::Directive::OMPD_target) &&
- !hasAllocator) {
- context_.Say(x.source,
- "ALLOCATORS directives that appear in a TARGET region "
- "must specify an allocator"_err_en_US);
+ auto &dirSpec{std::get<parser::OmpDirectiveSpecification>(x.t)};
+ auto &block{std::get<parser::Block>(x.t)};
+
+ omp::SourcedActionStmt action{omp::GetActionStmt(block)};
+ const parser::AllocateStmt *allocate{[&]() {
+ if (action) {
+ if (auto *alloc{std::get_if<common::Indirection<parser::AllocateStmt>>(
+ &action.stmt->u)}) {
+ return &alloc->value();
+ }
+ }
+ return static_cast<const parser::AllocateStmt *>(nullptr);
+ }()};
+
+ if (allocate) {
+ for (const auto &clause : dirSpec.Clauses().v) {
+ if (auto *alloc{std::get_if<parser::OmpClause::Allocate>(&clause.u)}) {
+ CheckAllNamesInAllocateStmt(
+ x.source, std::get<parser::OmpObjectList>(alloc->v.t), *allocate);
+
+ using OmpAllocatorSimpleModifier = parser::OmpAllocatorSimpleModifier;
+ using OmpAllocatorComplexModifier = parser::OmpAllocatorComplexModifier;
+
+ auto &modifiers{OmpGetModifiers(alloc->v)};
+ bool hasAllocator{
+ OmpGetUniqueModifier<OmpAllocatorSimpleModifier>(modifiers) ||
+ OmpGetUniqueModifier<OmpAllocatorComplexModifier>(modifiers)};
+
+ // TODO: As with allocate directive, exclude the case when a requires
+ // directive with the dynamic_allocators clause is present in
+ // the same compilation unit (OMP5.0 2.11.3).
+ if (IsNestedInDirective(llvm::omp::Directive::OMPD_target) &&
+ !hasAllocator) {
+ context_.Say(x.source,
+ "ALLOCATORS directives that appear in a TARGET region "
+ "must specify an allocator"_err_en_US);
+ }
}
}
}
+
PopContext();
}
diff --git a/flang/test/Parser/OpenMP/allocators-unparse.f90 b/flang/test/Parser/OpenMP/allocators-unparse.f90
index 5cd0230471fc4..70feb7a6b527e 100644
--- a/flang/test/Parser/OpenMP/allocators-unparse.f90
+++ b/flang/test/Parser/OpenMP/allocators-unparse.f90
@@ -15,48 +15,62 @@ subroutine allocate()
!$omp allocators allocate(align(32): arr2)
allocate(arr2(5, 3))
+ !$omp end allocators
end subroutine allocate
!CHECK: INTEGER, ALLOCATABLE :: arr1(:), arr2(:,:)
-!CHECK-NEXT:!$OMP ALLOCATE ALLOCATE(omp_default_mem_alloc: arr1)
+!CHECK-NEXT:!$OMP ALLOCATORS ALLOCATE(omp_default_mem_alloc: arr1)
!CHECK-NEXT: ALLOCATE(arr1(5))
-!CHECK-NEXT:!$OMP ALLOCATE ALLOCATE(ALLOCATOR(omp_default_mem_alloc), ALIGN(32): arr1) ALL&
-!CHECK-NEXT:!$OMP&OCATE(omp_default_mem_alloc: arr2)
+!CHECK-NEXT:!$OMP ALLOCATORS ALLOCATE(ALLOCATOR(omp_default_mem_alloc), ALIGN(32): arr1) A&
+!CHECK-NEXT:!$OMP&LLOCATE(omp_default_mem_alloc: arr2)
!CHECK-NEXT: ALLOCATE(arr1(10), arr2(3,2))
-!CHECK-NEXT:!$OMP ALLOCATE ALLOCATE(ALIGN(32): arr2)
+!CHECK-NEXT:!$OMP ALLOCATORS ALLOCATE(ALIGN(32): arr2)
!CHECK-NEXT: ALLOCATE(arr2(5,3))
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPAllocatorsConstruct
-!PARSE-TREE-NEXT: Verbatim
-!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Allocate -> OmpAllocateClause
-!PARSE-TREE-NEXT: Modifier -> OmpAllocatorSimpleModifier -> Scalar -> Integer -> Expr -> Designator -> DataRef -> Name = 'omp_default_mem_alloc'
-!PARSE-TREE-NEXT: OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr1'
-!PARSE-TREE-NEXT: AllocateStmt
-!PARSE-TREE-NEXT: Allocation
-!PARSE-TREE-NEXT: AllocateObject -> Name = 'arr1'
+!PARSE-TREE-NEXT: | OmpDirectiveSpecification
+!PARSE-TREE-NEXT: | | OmpDirectiveName -> llvm::omp::Directive = allocators
+!PARSE-TREE-NEXT: | | OmpClauseList -> OmpClause -> Allocate -> OmpAllocateClause
+!PARSE-TREE-NEXT: | | | Modifier -> OmpAllocatorSimpleModifier -> Scalar -> Integer -> Expr -> Designator -> DataRef -> Name = 'omp_default_mem_alloc'
+!PARSE-TREE-NEXT: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr1'
+!PARSE-TREE-NEXT: | | Flags = None
+!PARSE-TREE-NEXT: | Block
+!PARSE-TREE-NEXT: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AllocateStmt
+!PARSE-TREE-NEXT: | | | Allocation
+!PARSE-TREE-NEXT: | | | | AllocateObject -> Name = 'arr1'
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPAllocatorsConstruct
-!PARSE-TREE-NEXT: Verbatim
-!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Allocate -> OmpAllocateClause
-!PARSE-TREE-NEXT: Modifier -> OmpAllocatorComplexModifier -> Scalar -> Integer -> Expr -> Designator -> DataRef -> Name = 'omp_default_mem_alloc'
-!PARSE-TREE-NEXT: Modifier -> OmpAlignModifier -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '32'
-!PARSE-TREE-NEXT: OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr1'
-!PARSE-TREE-NEXT: OmpClause -> Allocate -> OmpAllocateClause
-!PARSE-TREE-NEXT: Modifier -> OmpAllocatorSimpleModifier -> Scalar -> Integer -> Expr -> Designator -> DataRef -> Name = 'omp_default_mem_alloc'
-!PARSE-TREE-NEXT: OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr2'
-!PARSE-TREE-NEXT: AllocateStmt
-!PARSE-TREE-NEXT: Allocation
-!PARSE-TREE-NEXT: AllocateObject -> Name = 'arr1'
-!PARSE-TREE-NEXT: AllocateShapeSpec
-!PARSE-TREE-NEXT: Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '10'
-!PARSE-TREE-NEXT: Allocation
-!PARSE-TREE-NEXT: AllocateObject -> Name = 'arr2'
+!PARSE-TREE-NEXT: | OmpDirectiveSpecification
+!PARSE-TREE-NEXT: | | OmpDirectiveName -> llvm::omp::Directive = allocators
+!PARSE-TREE-NEXT: | | OmpClauseList -> OmpClause -> Allocate -> OmpAllocateClause
+!PARSE-TREE-NEXT: | | | Modifier -> OmpAllocatorComplexModifier -> Scalar -> Integer -> Expr -> Designator -> DataRef -> Name = 'omp_default_mem_alloc'
+!PARSE-TREE-NEXT: | | | Modifier -> OmpAlignModifier -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '32'
+!PARSE-TREE-NEXT: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr1'
+!PARSE-TREE-NEXT: | | OmpClause -> Allocate -> OmpAllocateClause
+!PARSE-TREE-NEXT: | | | Modifier -> OmpAllocatorSimpleModifier -> Scalar -> Integer -> Expr -> Designator -> DataRef -> Name = 'omp_default_mem_alloc'
+!PARSE-TREE-NEXT: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr2'
+!PARSE-TREE-NEXT: | | Flags = None
+!PARSE-TREE-NEXT: | Block
+!PARSE-TREE-NEXT: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AllocateStmt
+!PARSE-TREE-NEXT: | | | Allocation
+!PARSE-TREE-NEXT: | | | | AllocateObject -> Name = 'arr1'
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPAllocatorsConstruct
-!PARSE-TREE-NEXT: Verbatim
-!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Allocate -> OmpAllocateClause
-!PARSE-TREE-NEXT: Modifier -> OmpAlignModifier -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '32'
-!PARSE-TREE-NEXT: OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr2'
-!PARSE-TREE-NEXT: AllocateStmt
-!PARSE-TREE-NEXT: Allocation
-!PARSE-TREE-NEXT: AllocateObject -> Name = 'arr2'
+!PARSE-TREE-NEXT: | OmpDirectiveSpecification
+!PARSE-TREE-NEXT: | | OmpDirectiveName -> llvm::omp::Directive = allocators
+!PARSE-TREE-NEXT: | | OmpClauseList -> OmpClause -> Allocate -> OmpAllocateClause
+!PARSE-TREE-NEXT: | | | Modifier -> OmpAlignModifier -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '32'
+!PARSE-TREE-NEXT: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr2'
+!PARSE-TREE-NEXT: | | Flags = None
+!PARSE-TREE-NEXT: | Block
+!PARSE-TREE-NEXT: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AllocateStmt
+!PARSE-TREE-NEXT: | | | Allocation
+!PARSE-TREE-NEXT: | | | | AllocateObject -> Name = 'arr2'
+!PARSE-TREE-NEXT: | | | | AllocateShapeSpec
+!PARSE-TREE-NEXT: | | | | | Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '5'
+!PARSE-TREE-NEXT: | | | | AllocateShapeSpec
+!PARSE-TREE-NEXT: | | | | | Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '3'
+!PARSE-TREE-NEXT: | OmpDirectiveSpecification
+!PARSE-TREE-NEXT: | | OmpDirectiveName -> llvm::omp::Directive = allocators
+!PARSE-TREE-NEXT: | | OmpClauseList ->
+!PARSE-TREE-NEXT: | | Flags = None
diff --git a/flang/test/Semantics/OpenMP/allocators07.f90 b/flang/test/Semantics/OpenMP/allocators07.f90
new file mode 100644
index 0000000000000..a28f706965cb1
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/allocators07.f90
@@ -0,0 +1,27 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
+
+subroutine f00
+ implicit none
+ integer, allocatable :: a(:)
+
+ !$omp allocators allocate(a)
+!ERROR: The body of the ALLOCATORS construct should be an ALLOCATE statement
+ continue
+end
+
+subroutine f01
+ implicit none
+ integer, allocatable :: a(:)
+
+!ERROR: The ALLOCATORS construct should contain a single ALLOCATE statement
+ !$omp allocators allocate(a)
+ !$omp end allocators
+end
+
+subroutine f02
+ implicit none
+ integer, allocatable :: a(:)
+
+!ERROR: The ALLOCATORS construct should contain a single ALLOCATE statement
+ !$omp allocators allocate(a)
+end
>From 2fd6d4c21c03252db5a7211b81ef0894a7fb2d46 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Fri, 11 Jul 2025 06:02:29 -0500
Subject: [PATCH 2/2] Remove extra whitespace
---
flang/lib/Semantics/resolve-directives.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index bb3914ffa2b1e..151f4ccae634e 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -2293,7 +2293,6 @@ void OmpAttributeVisitor::Post(const parser::OpenMPAllocatorsConstruct &x) {
}
}
}
-
PopContext();
}
More information about the flang-commits
mailing list