[flang-commits] [flang] 2fce8c9 - [flang][OpenMP] Frontend support for BEGIN/END METADIRECTIVE (#194402)
via flang-commits
flang-commits at lists.llvm.org
Tue Apr 28 13:55:22 PDT 2026
Author: Krzysztof Parzyszek
Date: 2026-04-28T15:55:16-05:00
New Revision: 2fce8c9d9e90d9697cb54907347396eebc1b5d61
URL: https://github.com/llvm/llvm-project/commit/2fce8c9d9e90d9697cb54907347396eebc1b5d61
DIFF: https://github.com/llvm/llvm-project/commit/2fce8c9d9e90d9697cb54907347396eebc1b5d61.diff
LOG: [flang][OpenMP] Frontend support for BEGIN/END METADIRECTIVE (#194402)
This implements parsing of BEGIN/END METADIRECTIVE, plus a minimal
semantic check for the association of a directive in a WHEN/OTHERWISE
clauses.
The same semantic checks for the context selectors apply here as in the
case of a standalone METADIRECTIVE.
Added:
flang/test/Lower/OpenMP/Todo/begin-metadirective.f90
flang/test/Parser/OpenMP/begin-metadirective.f90
flang/test/Semantics/OpenMP/begin-metadirective.f90
Modified:
flang/include/flang/Parser/dump-parse-tree.h
flang/include/flang/Parser/parse-tree.h
flang/lib/Lower/OpenMP/OpenMP.cpp
flang/lib/Parser/openmp-parsers.cpp
flang/lib/Parser/unparse.cpp
flang/lib/Semantics/check-omp-metadirective.cpp
flang/lib/Semantics/check-omp-structure.cpp
flang/lib/Semantics/check-omp-structure.h
flang/lib/Semantics/resolve-directives.cpp
Removed:
################################################################################
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 4bfeccfbe5c67..4c49f3e6e2417 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -586,6 +586,7 @@ class ParseTreeDumper {
NODE_ENUM(OmpDefaultmapClause, ImplicitBehavior)
NODE(parser, OmpDeleteModifier)
NODE_ENUM(OmpDeleteModifier, Value)
+ NODE(parser, OmpDelimitedMetadirectiveDirective)
NODE(parser, OmpDependClause)
NODE(OmpDependClause, TaskDep)
NODE(OmpDependClause::TaskDep, Modifier)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index a07e47bf92bd1..28a565d7e27f8 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -5082,7 +5082,7 @@ struct OmpClauseList {
// --- Directives and constructs
struct OmpDirectiveSpecification {
- ENUM_CLASS(Flag, DeprecatedSyntax, CrossesLabelDo)
+ ENUM_CLASS(Flag, DeprecatedSyntax, CrossesLabelDo, ExplicitBegin)
using Flags = common::EnumSet<Flag, Flag_enumSize>;
TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification);
@@ -5133,6 +5133,11 @@ struct OmpMetadirectiveDirective {
OmpMetadirectiveDirective, OmpDirectiveSpecification);
};
+struct OmpDelimitedMetadirectiveDirective : public OmpBlockConstruct {
+ INHERITED_TUPLE_CLASS_BOILERPLATE(
+ OmpDelimitedMetadirectiveDirective, OmpBlockConstruct);
+};
+
// Ref: [5.1:89-90], [5.2:216]
//
// nothing-directive ->
@@ -5468,7 +5473,7 @@ struct OpenMPConstruct {
OpenMPSectionConstruct, OpenMPLoopConstruct, OmpBlockConstruct,
OpenMPAtomicConstruct, OmpAllocateDirective, OpenMPDispatchConstruct,
OpenMPUtilityConstruct, OpenMPAllocatorsConstruct, OpenMPAssumeConstruct,
- OpenMPCriticalConstruct>
+ OpenMPCriticalConstruct, OmpDelimitedMetadirectiveDirective>
u;
};
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 3a2c5a3862bd1..6859f5b291342 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -4544,6 +4544,14 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
lowerAtomic(converter, symTable, semaCtx, eval, construct);
}
+static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
+ semantics::SemanticsContext &semaCtx,
+ lower::pft::Evaluation &eval,
+ const parser::OmpDelimitedMetadirectiveDirective &meta) {
+ TODO(converter.getCurrentLocation(),
+ "OpenMP BEGIN/END METADIRECTIVE lowering");
+}
+
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 153d7ad4717c8..f8ee77a275344 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1924,16 +1924,15 @@ TYPE_PARSER(construct<OmpMetadirectiveDirective>(
IsDirective(llvm::omp::Directive::OMPD_metadirective)) >=
OmpDirectiveSpecificationParser{}))
-struct OmpBeginDirectiveParser {
+struct OmpDirectiveParser {
using resultType = OmpDirectiveSpecification;
- constexpr OmpBeginDirectiveParser(DirectiveSet dirs) : dirs_(dirs) {}
- constexpr OmpBeginDirectiveParser(llvm::omp::Directive dir) {
- dirs_.set(llvm::to_underlying(dir));
- }
+ constexpr OmpDirectiveParser(DirectiveSet dirs) : dirs_(dirs) {}
+ constexpr OmpDirectiveParser(llvm::omp::Directive dir)
+ : dirs_({static_cast<unsigned>(llvm::to_underlying(dir))}) {}
std::optional<resultType> Parse(ParseState &state) const {
- auto &&p{predicated(Parser<OmpDirectiveName>{}, IsMemberOf(dirs_)) >=
+ auto p{predicated(Parser<OmpDirectiveName>{}, IsMemberOf(dirs_)) >=
OmpDirectiveSpecificationParser{}};
return p.Parse(state);
}
@@ -1942,18 +1941,61 @@ struct OmpBeginDirectiveParser {
DirectiveSet dirs_;
};
-struct OmpEndDirectiveParser {
+// Parse the directive that begins a construct. In some cases the directive
+// has to be preceded with an explicit "BEGIN", in other cases the begin is
+// assumed to be implicit. This parser is invoked after the OpenMP sentinel
+// has been consumed.
+// Note: Even if OMPD_begin_somename exists, the directive(s) to parse should
+// use the non-begin id, i.e. OMPD_somename.
+struct OmpBeginDirectiveParser {
using resultType = OmpDirectiveSpecification;
- constexpr OmpEndDirectiveParser(DirectiveSet dirs) : dirs_(dirs) {}
- constexpr OmpEndDirectiveParser(llvm::omp::Directive dir) {
- dirs_.set(llvm::to_underlying(dir));
+ constexpr OmpBeginDirectiveParser(DirectiveSet dirs, bool implicit = true)
+ : dparser_(dirs), implicit_(implicit) {}
+ constexpr OmpBeginDirectiveParser(
+ llvm::omp::Directive dir, bool implicit = true)
+ : dparser_(dir), implicit_(implicit) {}
+
+ std::optional<resultType> Parse(ParseState &state) const {
+ if (implicit_) {
+ return dparser_.Parse(state);
+ }
+
+ if (auto &&beginToken{verbatim("BEGIN"_sptok).Parse(state)}) {
+ if (auto &&dirSpec{dparser_.Parse(state)}) {
+ // Extend the "source" on both the OmpDirectiveName and the
+ // OmpDirectiveNameSpecification.
+ CharBlock &nameSource{std::get<OmpDirectiveName>(dirSpec->t).source};
+ nameSource.ExtendToCover(beginToken->source);
+ dirSpec->source.ExtendToCover(beginToken->source);
+ std::get<OmpDirectiveSpecification::Flags>(dirSpec->t)
+ .set(OmpDirectiveSpecification::Flag::ExplicitBegin);
+ return std::move(*dirSpec);
+ }
+ }
+ return std::nullopt;
}
+private:
+ OmpDirectiveParser dparser_;
+ bool implicit_;
+};
+
+// Parse the directive that end a construct. In all cases the directive
+// must be preceded with an explicit "END". This parser is invoked directly
+// from other construct parsers, so it must handle the OpenMP sentinel.
+// Note: Even if OMPD_end_somename exists, the directive(s) to parse should
+// use the non-end id, i.e. OMPD_somename.
+struct OmpEndDirectiveParser {
+ using resultType = OmpDirectiveSpecification;
+
+ constexpr OmpEndDirectiveParser(DirectiveSet dirs) : dparser_(dirs) {}
+ constexpr OmpEndDirectiveParser(llvm::omp::Directive dir) : dparser_(dir) {}
+
std::optional<resultType> Parse(ParseState &state) const {
if (startOmpLine.Parse(state)) {
if (auto endToken{verbatim("END"_sptok).Parse(state)}) {
- if (auto &&spec{OmpBeginDirectiveParser(dirs_).Parse(state)}) {
+ if (auto &&spec{dparser_.Parse(state)}) {
// Extend the "source" on both the OmpDirectiveName and the
// OmpDirectiveNameSpecification.
CharBlock &nameSource{std::get<OmpDirectiveName>(spec->t).source};
@@ -1967,16 +2009,18 @@ struct OmpEndDirectiveParser {
}
private:
- DirectiveSet dirs_;
+ OmpDirectiveParser dparser_;
};
struct OmpStatementConstructParser {
using resultType = OmpBlockConstruct;
- constexpr OmpStatementConstructParser(llvm::omp::Directive dir) : dir_(dir) {}
+ constexpr OmpStatementConstructParser(
+ llvm::omp::Directive dir, bool implicit = true)
+ : dir_(dir), implicit_(implicit) {}
std::optional<resultType> Parse(ParseState &state) const {
- if (auto begin{OmpBeginDirectiveParser(dir_).Parse(state)}) {
+ if (auto begin{OmpBeginDirectiveParser(dir_, implicit_).Parse(state)}) {
Block body;
if (auto stmt{attempt(validEPC).Parse(state)}) {
body.emplace_back(std::move(*stmt));
@@ -1994,15 +2038,18 @@ struct OmpStatementConstructParser {
private:
llvm::omp::Directive dir_;
+ bool implicit_;
};
struct OmpBlockConstructParser {
using resultType = OmpBlockConstruct;
- constexpr OmpBlockConstructParser(llvm::omp::Directive dir) : dir_(dir) {}
+ constexpr OmpBlockConstructParser(
+ llvm::omp::Directive dir, bool implicit = true)
+ : dir_(dir), implicit_(implicit) {}
std::optional<resultType> Parse(ParseState &state) const {
- if (auto &&begin{OmpBeginDirectiveParser(dir_).Parse(state)}) {
+ if (auto &&begin{OmpBeginDirectiveParser(dir_, implicit_).Parse(state)}) {
if (IsStandaloneOrdered(*begin)) {
return std::nullopt;
}
@@ -2030,19 +2077,21 @@ struct OmpBlockConstructParser {
private:
llvm::omp::Directive dir_;
+ bool implicit_;
};
struct OmpLoopConstructParser {
using resultType = OpenMPLoopConstruct;
- constexpr OmpLoopConstructParser(DirectiveSet dirs) : dirs_(dirs) {}
+ constexpr OmpLoopConstructParser(DirectiveSet dirs, bool implicit = true)
+ : dirs_(dirs), implicit_(implicit) {}
std::optional<resultType> Parse(ParseState &state) const {
auto ompLoopConstruct{asBlock(predicated(executionPartConstruct,
[](auto &epc) { return Unwrap<OpenMPLoopConstruct>(epc); }))};
auto loopItem{LoopNestParser{} || ompLoopConstruct};
- if (auto &&begin{OmpBeginDirectiveParser(dirs_).Parse(state)}) {
+ if (auto &&begin{OmpBeginDirectiveParser(dirs_, implicit_).Parse(state)}) {
auto loopDir{begin->DirId()};
auto assoc{llvm::omp::getDirectiveAssociation(loopDir)};
if (assoc == llvm::omp::Association::LoopNest) {
@@ -2078,6 +2127,7 @@ struct OmpLoopConstructParser {
private:
DirectiveSet dirs_;
+ bool implicit_;
};
struct OmpDeclarativeAllocateParser {
@@ -2457,6 +2507,10 @@ TYPE_PARSER( //
MakeBlockConstruct(llvm::omp::Directive::OMPD_workdistribute))
#undef MakeBlockConstruct
+TYPE_PARSER(sourced(
+ construct<OmpDelimitedMetadirectiveDirective>(OmpBlockConstructParser{
+ llvm::omp::Directive::OMPD_metadirective, /*implicit=*/false})))
+
// OMP SECTIONS Directive
static constexpr DirectiveSet GetSectionsDirectives() {
using Directive = llvm::omp::Directive;
@@ -2493,8 +2547,12 @@ static bool IsExecutionPart(const OmpDirectiveName &name) {
return name.IsExecutionPart();
}
-TYPE_PARSER(construct<OpenMPExecDirective>(
- startOmpLine >> predicated(Parser<OmpDirectiveName>{}, IsExecutionPart)))
+TYPE_PARSER(construct<OpenMPExecDirective>(startOmpLine >>
+ first( //
+ predicated(Parser<OmpDirectiveName>{}, IsExecutionPart),
+ // begin/end metadirective
+ predicated("BEGIN"_sptok >> Parser<OmpDirectiveName>{},
+ IsDirective(llvm::omp::Directive::OMPD_metadirective)))))
TYPE_CONTEXT_PARSER("OpenMP construct"_en_US,
startOmpLine >>
@@ -2512,7 +2570,9 @@ TYPE_CONTEXT_PARSER("OpenMP construct"_en_US,
construct<OpenMPConstruct>(Parser<OpenMPDispatchConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPAllocatorsConstruct>{}),
construct<OpenMPConstruct>(Parser<OpenMPAssumeConstruct>{}),
- construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{}))))
+ construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{}),
+ construct<OpenMPConstruct>(
+ Parser<OmpDelimitedMetadirectiveDirective>{}))))
static constexpr DirectiveSet GetLoopDirectives() {
using Directive = llvm::omp::Directive;
@@ -2571,7 +2631,7 @@ static constexpr DirectiveSet GetAllDirectives() { //
TYPE_PARSER(construct<OpenMPMisplacedEndDirective>(
OmpEndDirectiveParser{GetAllDirectives()}))
-TYPE_PARSER( //
- startOmpLine >> sourced(construct<OpenMPInvalidDirective>(
- !OmpDirectiveNameParser{} >> SkipTo<'\n'>{})))
+TYPE_PARSER(startOmpLine >>
+ sourced(construct<OpenMPInvalidDirective>(
+ maybe("BEGIN"_sptok) >> !OmpDirectiveNameParser{} >> SkipTo<'\n'>{})))
} // namespace Fortran::parser
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index b980a51d3f249..ab0951821d321 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2201,6 +2201,10 @@ class UnparseVisitor {
void Unparse(const OmpBeginDirective &x) {
BeginOpenMP();
Word("!$OMP ");
+ auto flags{std::get<OmpDirectiveSpecification::Flags>(x.t)};
+ if (flags.test(OmpDirectiveSpecification::Flag::ExplicitBegin)) {
+ Word("BEGIN ");
+ }
Walk(static_cast<const OmpDirectiveSpecification &>(x));
Put("\n");
EndOpenMP();
diff --git a/flang/lib/Semantics/check-omp-metadirective.cpp b/flang/lib/Semantics/check-omp-metadirective.cpp
index 499fb8452a154..c8c19e4ac7dac 100644
--- a/flang/lib/Semantics/check-omp-metadirective.cpp
+++ b/flang/lib/Semantics/check-omp-metadirective.cpp
@@ -534,6 +534,45 @@ void OmpStructureChecker::CheckTraitSimd(
}
}
+void OmpStructureChecker::Enter(const parser::OmpDirectiveSpecification &x) {
+ // OmpDirectiveSpecification exists on its own only in clauses on
+ // METADIRECTIVE.
+ // In other cases it's a part of other constructs that handle directive
+ // context stack by themselves.
+ if (!GetDirectiveNest(MetadirectiveNest)) {
+ return;
+ }
+
+ llvm::omp::Directive dirId{x.DirId()};
+ if (const parser::OpenMPConstruct *meta{GetCurrentConstruct()}) {
+ if (parser::Unwrap<parser::OmpDelimitedMetadirectiveDirective>(meta->u)) {
+ unsigned version{context_.langOptions().OpenMPVersion};
+ switch (llvm::omp::getDirectiveAssociation(dirId)) {
+ case llvm::omp::Association::Block:
+ case llvm::omp::Association::LoopNest:
+ case llvm::omp::Association::LoopSeq:
+ break;
+ default:
+ if (dirId != llvm::omp::Directive::OMPD_nothing) {
+ context_.Say(x.DirName().source,
+ "A directive in BEGIN %s should have a corresponding end-directive"_err_en_US,
+ parser::omp::GetUpperName(
+ llvm::omp::Directive::OMPD_metadirective, version));
+ }
+ }
+ }
+ }
+
+ PushContextAndClauseSets(
+ std::get<parser::OmpDirectiveName>(x.t).source, dirId);
+}
+
+void OmpStructureChecker::Leave(const parser::OmpDirectiveSpecification &x) {
+ if (GetDirectiveNest(MetadirectiveNest)) {
+ dirContext_.pop_back();
+ }
+}
+
void OmpStructureChecker::Enter(const parser::OmpMetadirectiveDirective &x) {
EnterDirectiveNest(MetadirectiveNest);
PushContextAndClauseSets(
@@ -545,4 +584,14 @@ void OmpStructureChecker::Leave(const parser::OmpMetadirectiveDirective &) {
dirContext_.pop_back();
}
+void OmpStructureChecker::Enter(
+ const parser::OmpDelimitedMetadirectiveDirective &x) {
+ PushContextAndClauseSets(x.source, llvm::omp::Directive::OMPD_metadirective);
+}
+
+void OmpStructureChecker::Leave(
+ const parser::OmpDelimitedMetadirectiveDirective &) {
+ dirContext_.pop_back();
+}
+
} // namespace Fortran::semantics
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 114a098da15f6..7bff7de2f8fbf 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -864,22 +864,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::DynGroupprivate &x) {
OmpVerifyModifiers(x.v, llvm::omp::OMPC_dyn_groupprivate, source, context_);
}
-void OmpStructureChecker::Enter(const parser::OmpDirectiveSpecification &x) {
- // OmpDirectiveSpecification exists on its own only in METADIRECTIVE.
- // In other cases it's a part of other constructs that handle directive
- // context stack by themselves.
- if (GetDirectiveNest(MetadirectiveNest)) {
- PushContextAndClauseSets(
- std::get<parser::OmpDirectiveName>(x.t).source, x.DirId());
- }
-}
-
-void OmpStructureChecker::Leave(const parser::OmpDirectiveSpecification &) {
- if (GetDirectiveNest(MetadirectiveNest)) {
- dirContext_.pop_back();
- }
-}
-
template <typename Checker> struct DirectiveSpellingVisitor {
using Directive = llvm::omp::Directive;
@@ -1396,12 +1380,27 @@ void OmpStructureChecker::ChecksOnOrderedAsBlock() {
}
}
-void OmpStructureChecker::Leave(const parser::OmpBeginDirective &) {
- switch (GetContext().directive) {
+void OmpStructureChecker::Enter(const parser::OmpBeginDirective &x) {
+ switch (x.DirId()) {
+ case llvm::omp::Directive::OMPD_metadirective:
+ // Delimited METADIRECTIVE
+ EnterDirectiveNest(MetadirectiveNest);
+ break;
+ default:
+ break;
+ }
+}
+
+void OmpStructureChecker::Leave(const parser::OmpBeginDirective &x) {
+ switch (x.DirId()) {
case llvm::omp::Directive::OMPD_ordered:
// [5.1] 2.19.9 Ordered Construct Restriction
ChecksOnOrderedAsBlock();
break;
+ case llvm::omp::Directive::OMPD_metadirective:
+ // Delimited METADIRECTIVE
+ ExitDirectiveNest(MetadirectiveNest);
+ break;
default:
break;
}
@@ -3433,7 +3432,7 @@ void OmpStructureChecker::Leave(const parser::OmpEndDirective &x) {
// 2. Checks on clauses which fall under 'struct OmpClause' from parse-tree.h.
// 3. Checks on clauses which are not in 'struct OmpClause' from parse-tree.h.
-void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
+void OmpStructureChecker::Leave(const parser::OmpClauseList &x) {
unsigned version{context_.langOptions().OpenMPVersion};
// 2.7.1 Loop Construct Restriction
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 5bccf3576923e..e75bb5da847a9 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -113,6 +113,7 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
void Leave(const parser::OpenMPInteropConstruct &);
void Enter(const parser::OmpBlockConstruct &);
void Leave(const parser::OmpBlockConstruct &);
+ void Enter(const parser::OmpBeginDirective &);
void Leave(const parser::OmpBeginDirective &);
void Enter(const parser::OmpEndDirective &);
void Leave(const parser::OmpEndDirective &);
@@ -175,6 +176,8 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
void Enter(const parser::OmpMetadirectiveDirective &);
void Leave(const parser::OmpMetadirectiveDirective &);
+ void Enter(const parser::OmpDelimitedMetadirectiveDirective &);
+ void Leave(const parser::OmpDelimitedMetadirectiveDirective &);
void Enter(const parser::OmpContextSelector &);
void Leave(const parser::OmpContextSelector &);
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index abfde0dafc29a..8712c361965cb 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -469,8 +469,19 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
}
template <typename A> void Walk(const A &x) { parser::Walk(x, *this); }
- template <typename A> bool Pre(const A &) { return true; }
- template <typename A> void Post(const A &) {}
+ // Normally the catch-all Pre/Post functions are templates taking
+ // "const T &". For a class D derived from B, and an explicit overload
+ // of Pre(const B &), a call to Pre(D) will select the template instead
+ // of the base clase overload.
+ // Force user-defined conversion from any const-reference, to make sure
+ // that the Pre(AbsorbAnyReference) and Post(AbsorbAnyReference) overloads
+ // will be worse than derived-to-base conversions. This will, for example,
+ // invoke Pre(const OmpBlockConstruct &) for directives derived from it.
+ struct AbsorbAnyReference {
+ template <typename T> AbsorbAnyReference(const T &) {}
+ };
+ bool Pre(AbsorbAnyReference) { return true; }
+ void Post(AbsorbAnyReference) {}
bool Pre(const parser::SpecificationPart &) {
partStack_.push_back(PartKind::SpecificationPart);
diff --git a/flang/test/Lower/OpenMP/Todo/begin-metadirective.f90 b/flang/test/Lower/OpenMP/Todo/begin-metadirective.f90
new file mode 100644
index 0000000000000..ccc06ebc3007f
--- /dev/null
+++ b/flang/test/Lower/OpenMP/Todo/begin-metadirective.f90
@@ -0,0 +1,12 @@
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s 2>&1 | FileCheck %s
+
+! CHECK: not yet implemented: OpenMP BEGIN/END METADIRECTIVE lowering
+subroutine test_begin_metadirective
+ integer :: x
+ x = 0
+ !$omp begin metadirective &
+ !$omp & when(implementation={vendor(llvm)}: parallel) &
+ !$omp & otherwise(nothing)
+ x = 1
+ !$omp end metadirective
+end subroutine
diff --git a/flang/test/Parser/OpenMP/begin-metadirective.f90 b/flang/test/Parser/OpenMP/begin-metadirective.f90
new file mode 100644
index 0000000000000..73b3678be4b10
--- /dev/null
+++ b/flang/test/Parser/OpenMP/begin-metadirective.f90
@@ -0,0 +1,80 @@
+!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=52 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
+!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=52 %s | FileCheck --check-prefix="PARSE-TREE" %s
+
+subroutine f00
+ !$omp begin metadirective
+ continue
+ !$omp end metadirective
+end
+
+!UNPARSE: SUBROUTINE f00
+!UNPARSE: !$OMP BEGIN METADIRECTIVE
+!UNPARSE: CONTINUE
+!UNPARSE: !$OMP END METADIRECTIVE
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OmpDelimitedMetadirectiveDirective
+!PARSE-TREE: | OmpBeginDirective
+!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = metadirective
+!PARSE-TREE: | | OmpClauseList ->
+!PARSE-TREE: | | Flags = {ExplicitBegin}
+!PARSE-TREE: | Block
+!PARSE-TREE: | OmpEndDirective
+!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = metadirective
+!PARSE-TREE: | | OmpClauseList ->
+!PARSE-TREE: | | Flags = {}
+
+subroutine f01(s)
+ integer :: i
+ integer :: s
+ s = 0
+ !$omp begin metadirective &
+ !$omp & when(user={condition(.true.)}: parallel do reduction(+: s)) &
+ !$omp & otherwise(do)
+ do i = 1, 10
+ s = s + i
+ end do
+ !$omp end metadirective
+end
+
+!UNPARSE: SUBROUTINE f01 (s)
+!UNPARSE: INTEGER i
+!UNPARSE: INTEGER s
+!UNPARSE: s=0_4
+!UNPARSE: !$OMP BEGIN METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: PARALLEL DO REDUCTION(+: s)&
+!UNPARSE: !$OMP&) OTHERWISE(DO)
+!UNPARSE: DO i=1_4,10_4
+!UNPARSE: s=s+i
+!UNPARSE: END DO
+!UNPARSE: !$OMP END METADIRECTIVE
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OmpDelimitedMetadirectiveDirective
+!PARSE-TREE: | OmpBeginDirective
+!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = metadirective
+!PARSE-TREE: | | OmpClauseList -> OmpClause -> When -> OmpWhenClause
+!PARSE-TREE: | | | Modifier -> OmpContextSelectorSpecification -> OmpTraitSetSelector
+!PARSE-TREE: | | | | OmpTraitSetSelectorName -> Value = User
+!PARSE-TREE: | | | | OmpTraitSelector
+!PARSE-TREE: | | | | | OmpTraitSelectorName -> Value = Condition
+!PARSE-TREE: | | | | | Properties
+!PARSE-TREE: | | | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4'
+!PARSE-TREE: | | | | | | | LiteralConstant -> LogicalLiteralConstant
+!PARSE-TREE: | | | | | | | | bool = 'true'
+!PARSE-TREE: | | | OmpDirectiveSpecification
+!PARSE-TREE: | | | | OmpDirectiveName -> llvm::omp::Directive = parallel do
+!PARSE-TREE: | | | | OmpClauseList -> OmpClause -> Reduction -> OmpReductionClause
+!PARSE-TREE: | | | | | Modifier -> OmpReductionIdentifier -> DefinedOperator -> IntrinsicOperator = Add
+!PARSE-TREE: | | | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 's'
+!PARSE-TREE: | | | | Flags = {}
+!PARSE-TREE: | | OmpClause -> Otherwise -> OmpOtherwiseClause -> OmpDirectiveSpecification
+!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = do
+!PARSE-TREE: | | | OmpClauseList ->
+!PARSE-TREE: | | | Flags = {}
+!PARSE-TREE: | | Flags = {ExplicitBegin}
+!PARSE-TREE: | Block
+!PARSE-TREE: | OmpEndDirective
+!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = metadirective
+!PARSE-TREE: | | OmpClauseList ->
+!PARSE-TREE: | | Flags = {}
+
diff --git a/flang/test/Semantics/OpenMP/begin-metadirective.f90 b/flang/test/Semantics/OpenMP/begin-metadirective.f90
new file mode 100644
index 0000000000000..f557252362a07
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/begin-metadirective.f90
@@ -0,0 +1,8 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
+
+subroutine f00
+ !ERROR: A directive in BEGIN METADIRECTIVE should have a corresponding end-directive
+ !$omp begin metadirective when(user={condition(.true.)}: taskwait)
+ continue
+ !$omp end metadirective
+end
More information about the flang-commits
mailing list