[flang-commits] [flang] [flang][OpenMP] Use OmpDirectiveSpecification in ASSUMES (PR #160591)
Krzysztof Parzyszek via flang-commits
flang-commits at lists.llvm.org
Fri Sep 26 13:49:10 PDT 2025
https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/160591
>From 2b1bc65cbd8fceffd44a84e0339b5f0965d7f4b1 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 23 Sep 2025 11:51:01 -0500
Subject: [PATCH 01/11] [flang][OpenMP] Introduce variant argument, customize
OmpArgument parsing
The DECLARE_VARIANT directive takes two names separated by a colon as an
argument: base-name:variant-name. Define OmpBaseVariantNames to represent
this, since no existing argument alternative matches it.
However, there is an issue. The syntax "name1:name2" can be the argument
to DECLARE_VARIANT (if both names are OmpObjects), but it can also be a
reduction-specifier if "name2" is a type. This conflict can only be
resolved once we know what the names are, which is after name resolution
has visited them. The problem is that name resolution has side-effects
that may be (practically) impossible to undo (e.g. creating new symbols,
emitting diagnostic messages).
To avoid this problem this PR makes the parsing of OmpArgument directive-
sensitive: when the directive is DECLARE_VARIANT, don't attempt to parse
a reduction-specifier, consider OmpBaseVariantNames instead. Otherwise
ignore OmpBaseVariantNames in favor of reduction-specifier.
---
flang/include/flang/Parser/dump-parse-tree.h | 1 +
flang/include/flang/Parser/parse-tree.h | 13 ++++
flang/lib/Parser/openmp-parsers.cpp | 68 +++++++++++++++++---
flang/lib/Parser/unparse.cpp | 5 ++
flang/lib/Semantics/resolve-names.cpp | 4 ++
5 files changed, 83 insertions(+), 8 deletions(-)
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index b2341226c7688..7540d38baa584 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -522,6 +522,7 @@ class ParseTreeDumper {
NODE(parser, OmpAtomicDefaultMemOrderClause)
NODE(parser, OmpAutomapModifier)
NODE_ENUM(OmpAutomapModifier, Value)
+ NODE(parser, OmpBaseVariantNames)
NODE(parser, OmpBeginDirective)
NODE(parser, OmpBeginLoopDirective)
NODE(parser, OmpBeginSectionsDirective)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 39dbeb5e7cfbe..4808a5b844a6f 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3555,6 +3555,18 @@ struct OmpLocator {
WRAPPER_CLASS(OmpLocatorList, std::list<OmpLocator>);
+// Ref: [4.5:58-60], [5.0:58-60], [5.1:63-68], [5.2:197-198], [6.0:334-336]
+//
+// Argument to DECLARE VARIANT with the base-name present. (When only
+// variant-name is present, it is a simple OmpObject).
+//
+// base-name-variant-name -> // since 4.5
+// base-name : variant-name
+struct OmpBaseVariantNames {
+ TUPLE_CLASS_BOILERPLATE(OmpBaseVariantNames);
+ std::tuple<OmpObject, OmpObject> t;
+};
+
// Ref: [5.0:326:10-16], [5.1:359:5-11], [5.2:163:2-7], [6.0:293:16-21]
//
// mapper-specifier ->
@@ -3584,6 +3596,7 @@ struct OmpArgument {
CharBlock source;
UNION_CLASS_BOILERPLATE(OmpArgument);
std::variant<OmpLocator, // {variable, extended, locator}-list-item
+ OmpBaseVariantNames, // base-name:variant-name
OmpMapperSpecifier, OmpReductionSpecifier>
u;
};
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 30bc02ce851db..3b32e1a4a67b1 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -315,15 +315,56 @@ TYPE_PARSER( //
construct<OmpLocator>(Parser<OmpObject>{}) ||
construct<OmpLocator>(Parser<FunctionReference>{}))
-TYPE_PARSER(sourced( //
- construct<OmpArgument>(Parser<OmpMapperSpecifier>{}) ||
- construct<OmpArgument>(Parser<OmpReductionSpecifier>{}) ||
- construct<OmpArgument>(Parser<OmpLocator>{})))
+TYPE_PARSER(construct<OmpBaseVariantNames>(
+ Parser<OmpObject>{} / ":", Parser<OmpObject>{}))
+
+// Make the parsing of OmpArgument directive-sensitive. The issue is that
+// name1:name2 can match either OmpBaseVariantNames or OmpReductionSpecifier.
+// In the former case, "name2" is a name of a function, in the latter, of a
+// type. To resolve the conflict we need information provided by name
+// resolution, but by that time we can't modify the AST anymore, and the
+// name resolution may have implicitly declared a symbol, or issued a message.
+template <llvm::omp::Directive Id = llvm::omp::Directive::OMPD_unknown>
+struct OmpArgumentParser {
+ using resultType = OmpArgument;
+
+ std::optional<resultType> Parse(ParseState &state) const {
+ constexpr auto parser{sourced(first( //
+ construct<OmpArgument>(Parser<OmpMapperSpecifier>{}),
+ // By default, prefer OmpReductionSpecifier over OmpBaseVariantNames.
+ construct<OmpArgument>(Parser<OmpReductionSpecifier>{}),
+ construct<OmpArgument>(Parser<OmpLocator>{})))};
+ return parser.Parse(state);
+ }
+};
+
+template <>
+struct OmpArgumentParser<llvm::omp::Directive::OMPD_declare_variant> {
+ using resultType = OmpArgument;
+
+ std::optional<resultType> Parse(ParseState &state) const {
+ constexpr auto parser{sourced(first( //
+ construct<OmpArgument>(Parser<OmpMapperSpecifier>{}),
+ // In DECLARE_VARIANT parse OmpBaseVariantNames instead of
+ // OmpReductionSpecifier.
+ construct<OmpArgument>(Parser<OmpBaseVariantNames>{}),
+ construct<OmpArgument>(Parser<OmpLocator>{})))};
+ return parser.Parse(state);
+ }
+};
TYPE_PARSER(construct<OmpLocatorList>(nonemptyList(Parser<OmpLocator>{})))
-TYPE_PARSER(sourced( //
- construct<OmpArgumentList>(nonemptyList(Parser<OmpArgument>{}))))
+template <llvm::omp::Directive Id = llvm::omp::Directive::OMPD_unknown>
+struct OmpArgumentListParser {
+ using resultType = OmpArgumentList;
+
+ std::optional<resultType> Parse(ParseState &state) const {
+ return sourced(
+ construct<OmpArgumentList>(nonemptyList(OmpArgumentParser<Id>{})))
+ .Parse(state);
+ }
+};
TYPE_PARSER( //
construct<OmpTypeSpecifier>(Parser<DeclarationTypeSpec>{}) ||
@@ -1312,12 +1353,23 @@ TYPE_PARSER(
applyFunction<OmpDirectiveSpecification>(makeFlushFromOldSyntax,
verbatim("FLUSH"_tok) / !lookAhead("("_tok),
maybe(Parser<OmpClauseList>{}),
- maybe(parenthesized(Parser<OmpArgumentList>{})),
+ maybe(parenthesized(
+ OmpArgumentListParser<llvm::omp::Directive::OMPD_flush>{})),
pure(OmpDirectiveSpecification::Flags::DeprecatedSyntax)))) ||
+ // Parse DECLARE_VARIANT individually, because the "[base:]variant"
+ // argument will conflict with DECLARE_REDUCTION's "ident:types...".
+ predicated(Parser<OmpDirectiveName>{},
+ IsDirective(llvm::omp::Directive::OMPD_declare_variant)) >=
+ sourced(construct<OmpDirectiveSpecification>(
+ sourced(OmpDirectiveNameParser{}),
+ maybe(parenthesized(OmpArgumentListParser<
+ llvm::omp::Directive::OMPD_declare_variant>{})),
+ maybe(Parser<OmpClauseList>{}),
+ pure(OmpDirectiveSpecification::Flags::None))) ||
// Parse the standard syntax: directive [(arguments)] [clauses]
sourced(construct<OmpDirectiveSpecification>( //
sourced(OmpDirectiveNameParser{}),
- maybe(parenthesized(Parser<OmpArgumentList>{})),
+ maybe(parenthesized(OmpArgumentListParser<>{})),
maybe(Parser<OmpClauseList>{}),
pure(OmpDirectiveSpecification::Flags::None))))
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 3455b535ccb51..1b3eef0eefba3 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2089,6 +2089,11 @@ class UnparseVisitor {
// OpenMP Clauses & Directives
void Unparse(const OmpArgumentList &x) { Walk(x.v, ", "); }
+ void Unparse(const OmpBaseVariantNames &x) {
+ Walk(std::get<0>(x.t)); // OmpObject
+ Put(":");
+ Walk(std::get<1>(x.t)); // OmpObject
+ }
void Unparse(const OmpTypeNameList &x) { //
Walk(x.v, ",");
}
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 699cb562da8cc..b73d794c11d31 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1998,6 +1998,10 @@ bool OmpVisitor::Pre(const parser::OmpDirectiveSpecification &x) {
ProcessReductionSpecifier(spec, clauses);
visitClauses = false;
},
+ [&](const parser::OmpBaseVariantNames &names) {
+ Walk(std::get<0>(names.t));
+ Walk(std::get<1>(names.t));
+ },
[&](const parser::OmpLocator &locator) {
// Manually resolve names in CRITICAL directives. This is because
// these names do not denote Fortran objects, and the CRITICAL
>From 38cf6a6c62918458888ec4899ae9faf357b9a633 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 23 Sep 2025 13:40:10 -0500
Subject: [PATCH 02/11] [flang][OpenMP] Use OmpDirectiveSpecification in
DECLARE_VARIANT
---
flang/include/flang/Parser/openmp-utils.h | 4 +-
flang/include/flang/Parser/parse-tree.h | 8 +-
flang/lib/Parser/openmp-parsers.cpp | 5 +-
flang/lib/Parser/unparse.cpp | 8 +-
flang/lib/Semantics/check-omp-structure.cpp | 52 +++++++++++--
flang/lib/Semantics/resolve-names.cpp | 25 ++-----
flang/test/Parser/OpenMP/declare-variant.f90 | 73 +++++++++++--------
.../OpenMP/openmp6-directive-spellings.f90 | 9 ++-
.../test/Semantics/OpenMP/declare-variant.f90 | 6 +-
9 files changed, 116 insertions(+), 74 deletions(-)
diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h
index 34eb6ac3436bc..64be9714f6cc2 100644
--- a/flang/include/flang/Parser/openmp-utils.h
+++ b/flang/include/flang/Parser/openmp-utils.h
@@ -38,7 +38,6 @@ struct ConstructId {
static constexpr llvm::omp::Directive id{Id}; \
}
-MAKE_CONSTR_ID(OmpDeclareVariantDirective, D::OMPD_declare_variant);
MAKE_CONSTR_ID(OpenMPDeclarativeAllocate, D::OMPD_allocate);
MAKE_CONSTR_ID(OpenMPDeclarativeAssumes, D::OMPD_assumes);
MAKE_CONSTR_ID(OpenMPDeclareReductionConstruct, D::OMPD_declare_reduction);
@@ -92,8 +91,7 @@ struct DirectiveNameScope {
} else if constexpr (TupleTrait<T>) {
if constexpr (std::is_base_of_v<OmpBlockConstruct, T>) {
return std::get<OmpBeginDirective>(x.t).DirName();
- } else if constexpr (std::is_same_v<T, OmpDeclareVariantDirective> ||
- std::is_same_v<T, OpenMPDeclarativeAllocate> ||
+ } else if constexpr (std::is_same_v<T, OpenMPDeclarativeAllocate> ||
std::is_same_v<T, OpenMPDeclarativeAssumes> ||
std::is_same_v<T, OpenMPDeclareReductionConstruct> ||
std::is_same_v<T, OpenMPDeclareSimdConstruct> ||
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 4808a5b844a6f..de65088c01eae 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4933,10 +4933,14 @@ struct OpenMPSectionsConstruct {
t;
};
+// Ref: [4.5:58-60], [5.0:58-60], [5.1:63-68], [5.2:197-198], [6.0:334-336]
+//
+// declare-variant-directive ->
+// DECLARE_VARIANT([base-name:]variant-name) // since 4.5
struct OmpDeclareVariantDirective {
- TUPLE_CLASS_BOILERPLATE(OmpDeclareVariantDirective);
+ WRAPPER_CLASS_BOILERPLATE(
+ OmpDeclareVariantDirective, OmpDirectiveSpecification);
CharBlock source;
- std::tuple<Verbatim, std::optional<Name>, Name, OmpClauseList> t;
};
// 2.10.6 declare-target -> DECLARE TARGET (extended-list) |
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 3b32e1a4a67b1..6ec6eb4038933 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1763,8 +1763,9 @@ TYPE_PARSER(construct<OmpInitializerClause>(
// OpenMP 5.2: 7.5.4 Declare Variant directive
TYPE_PARSER(sourced(construct<OmpDeclareVariantDirective>(
- verbatim("DECLARE VARIANT"_tok) || verbatim("DECLARE_VARIANT"_tok),
- "(" >> maybe(name / ":"), name / ")", Parser<OmpClauseList>{})))
+ predicated(Parser<OmpDirectiveName>{},
+ IsDirective(llvm::omp::Directive::OMPD_declare_variant)) >=
+ Parser<OmpDirectiveSpecification>{})))
// 2.16 Declare Reduction Construct
TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>(
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 1b3eef0eefba3..fc81cfb7a3818 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2539,12 +2539,8 @@ class UnparseVisitor {
}
void Unparse(const OmpDeclareVariantDirective &x) {
BeginOpenMP();
- Word("!$OMP DECLARE VARIANT ");
- Put("(");
- Walk(std::get<std::optional<Name>>(x.t), ":");
- Walk(std::get<Name>(x.t));
- Put(")");
- Walk(std::get<OmpClauseList>(x.t));
+ Word("!$OMP ");
+ Walk(x.v);
Put("\n");
EndOpenMP();
}
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index e9bd34d449461..f10858ac1356d 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -634,11 +634,6 @@ template <typename Checker> struct DirectiveSpellingVisitor {
std::get<parser::Verbatim>(x.t).source, Directive::OMPD_declare_target);
return false;
}
- bool Pre(const parser::OmpDeclareVariantDirective &x) {
- checker_(std::get<parser::Verbatim>(x.t).source,
- Directive::OMPD_declare_variant);
- return false;
- }
bool Pre(const parser::OpenMPGroupprivate &x) {
checker_(x.v.DirName().source, Directive::OMPD_groupprivate);
return false;
@@ -1370,9 +1365,50 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclareSimdConstruct &) {
}
void OmpStructureChecker::Enter(const parser::OmpDeclareVariantDirective &x) {
- const auto &dir{std::get<parser::Verbatim>(x.t)};
- PushContextAndClauseSets(
- dir.source, llvm::omp::Directive::OMPD_declare_variant);
+ const parser::OmpDirectiveName &dirName{x.v.DirName()};
+ PushContextAndClauseSets(dirName.source, dirName.v);
+
+ const parser::OmpArgumentList &args{x.v.Arguments()};
+ if (args.v.size() != 1) {
+ context_.Say(args.source,
+ "DECLARE_VARIANT directive should have a single argument"_err_en_US);
+ return;
+ }
+
+ auto InvalidArgument{[&](parser::CharBlock source) {
+ context_.Say(source,
+ "The argument to the DECLARE_MAPPER directive should be [base-name:]variant-name"_err_en_US);
+ }};
+
+ auto CheckSymbol{[&](const Symbol *sym, parser::CharBlock source) {
+ if (sym) {
+ if (!IsProcedure(*sym) && !IsFunction(*sym)) {
+ context_.Say(source,
+ "The name '%s' should refer to a procedure"_err_en_US, sym->name());
+ }
+ if (sym->test(Symbol::Flag::Implicit)) {
+ context_.Say(source,
+ "The name '%s' has been implicitly declared"_err_en_US,
+ sym->name());
+ }
+ } else {
+ InvalidArgument(source);
+ }
+ }};
+
+ const parser::OmpArgument &arg{args.v.front()};
+ common::visit( //
+ common::visitors{
+ [&](const parser::OmpBaseVariantNames &y) {
+ CheckSymbol(GetObjectSymbol(std::get<0>(y.t)), arg.source);
+ CheckSymbol(GetObjectSymbol(std::get<1>(y.t)), arg.source);
+ },
+ [&](const parser::OmpLocator &y) {
+ CheckSymbol(GetArgumentSymbol(arg), arg.source);
+ },
+ [&](auto &&y) { InvalidArgument(arg.source); },
+ },
+ arg.u);
}
void OmpStructureChecker::Leave(const parser::OmpDeclareVariantDirective &) {
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index b73d794c11d31..3a6115dae2da5 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1540,20 +1540,6 @@ class OmpVisitor : public virtual DeclarationVisitor {
bool Pre(const parser::OmpDeclareVariantDirective &x) {
AddOmpSourceRange(x.source);
- auto FindSymbolOrError = [&](const parser::Name &procName) {
- auto *symbol{FindSymbol(NonDerivedTypeScope(), procName)};
- if (!symbol) {
- context().Say(procName.source,
- "Implicit subroutine declaration '%s' in !$OMP DECLARE VARIANT"_err_en_US,
- procName.source);
- }
- };
- auto &baseProcName = std::get<std::optional<parser::Name>>(x.t);
- if (baseProcName) {
- FindSymbolOrError(*baseProcName);
- }
- auto &varProcName = std::get<parser::Name>(x.t);
- FindSymbolOrError(varProcName);
return true;
}
@@ -1687,16 +1673,19 @@ class OmpVisitor : public virtual DeclarationVisitor {
PopScope();
}
}
+
+ // These objects are handled explicitly, and the AST traversal should not
+ // reach a point where it calls the Pre functions for them.
bool Pre(const parser::OmpMapperSpecifier &x) {
- // OmpMapperSpecifier is handled explicitly, and the AST traversal
- // should not reach a point where it calls this function.
llvm_unreachable("This function should not be reached by AST traversal");
}
bool Pre(const parser::OmpReductionSpecifier &x) {
- // OmpReductionSpecifier is handled explicitly, and the AST traversal
- // should not reach a point where it calls this function.
llvm_unreachable("This function should not be reached by AST traversal");
}
+ bool Pre(const parser::OmpBaseVariantNames &x) {
+ llvm_unreachable("This function should not be reached by AST traversal");
+ }
+
bool Pre(const parser::OmpDirectiveSpecification &x);
void Post(const parser::OmpDirectiveSpecification &) {
messageHandler().set_currStmtSource(std::nullopt);
diff --git a/flang/test/Parser/OpenMP/declare-variant.f90 b/flang/test/Parser/OpenMP/declare-variant.f90
index 3366b143e62e6..f5c34abd84ac7 100644
--- a/flang/test/Parser/OpenMP/declare-variant.f90
+++ b/flang/test/Parser/OpenMP/declare-variant.f90
@@ -2,15 +2,19 @@
! RUN: %flang_fc1 -fdebug-dump-parse-tree-no-sema -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s
subroutine sub0
-!CHECK: !$OMP DECLARE VARIANT (sub:vsub) MATCH(CONSTRUCT={PARALLEL})
-!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective
-!PARSE-TREE: | Verbatim
-!PARSE-TREE: | Name = 'sub'
-!PARSE-TREE: | Name = 'vsub'
+!CHECK: !$OMP DECLARE VARIANT(sub:vsub) MATCH(CONSTRUCT={PARALLEL})
+
+!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant
+!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpBaseVariantNames
+!PARSE-TREE: | | OmpObject -> Designator -> DataRef -> Name = 'sub'
+!PARSE-TREE: | | OmpObject -> Designator -> DataRef -> Name = 'vsub'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector
!PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct
!PARSE-TREE: | | OmpTraitSelector
!PARSE-TREE: | | | OmpTraitSelectorName -> llvm::omp::Directive = parallel
+!PARSE-TREE: | Flags = None
+
!$omp declare variant (sub:vsub) match (construct={parallel})
contains
subroutine vsub
@@ -30,14 +34,17 @@ subroutine vsub (v1)
integer, value :: v1
end
subroutine sub (v1)
-!CHECK: !$OMP DECLARE VARIANT (vsub) MATCH(CONSTRUCT={DISPATCH}
-!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective
-!PARSE-TREE: | Verbatim
-!PARSE-TREE: | Name = 'vsub'
+!CHECK: !$OMP DECLARE VARIANT(vsub) MATCH(CONSTRUCT={DISPATCH})
+
+!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant
+!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'vsub'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector
!PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct
!PARSE-TREE: | | OmpTraitSelector
!PARSE-TREE: | | | OmpTraitSelectorName -> llvm::omp::Directive = dispatch
+!PARSE-TREE: | Flags = None
+
!$omp declare variant(vsub), match(construct={dispatch})
integer, value :: v1
end
@@ -56,17 +63,20 @@ subroutine vsub (v1, a1, a2)
integer(omp_interop_kind), value :: a2
end
subroutine sub (v1)
-!CHECK: !$OMP DECLARE VARIANT (vsub) MATCH(CONSTRUCT={DISPATCH}) APPEND_ARGS(INTEROP(T&
-!CHECK: !$OMP&ARGET),INTEROP(TARGET))
-!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective
-!PARSE-TREE: | Verbatim
-!PARSE-TREE: | Name = 'vsub'
+!CHECK: !$OMP DECLARE VARIANT(vsub) MATCH(CONSTRUCT={DISPATCH}) APPEND_ARGS(INTEROP(TA&
+!CHECK: !$OMP&RGET),INTEROP(TARGET))
+
+!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant
+!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'vsub'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector
!PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct
!PARSE-TREE: | | OmpTraitSelector
!PARSE-TREE: | | | OmpTraitSelectorName -> llvm::omp::Directive = dispatch
!PARSE-TREE: | OmpClause -> AppendArgs -> OmpAppendArgsClause -> OmpAppendOp -> OmpInteropType -> Value = Target
!PARSE-TREE: | OmpAppendOp -> OmpInteropType -> Value = Target
+!PARSE-TREE: | Flags = None
+
!$omp declare variant(vsub), match(construct={dispatch}), append_args (interop(target), interop(target))
integer, value :: v1
end
@@ -81,11 +91,12 @@ subroutine sb3 (x1, x2)
contains
subroutine sub (v1, v2)
type(c_ptr), value :: v1, v2
-!CHECK: !$OMP DECLARE VARIANT (vsub) MATCH(CONSTRUCT={DISPATCH}) ADJUST_ARGS(NOTHING:v&
-!CHECK: !$OMP&1) ADJUST_ARGS(NEED_DEVICE_PTR:v2)
-!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective
-!PARSE-TREE: | Verbatim
-!PARSE-TREE: | Name = 'vsub'
+!CHECK: !$OMP DECLARE VARIANT(vsub) MATCH(CONSTRUCT={DISPATCH}) ADJUST_ARGS(NOTHING:v1&
+!CHECK: !$OMP&) ADJUST_ARGS(NEED_DEVICE_PTR:v2)
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant
+!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'vsub'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector
!PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct
!PARSE-TREE: | | OmpTraitSelector
@@ -96,6 +107,8 @@ subroutine sub (v1, v2)
!PARSE-TREE: | OmpClause -> AdjustArgs -> OmpAdjustArgsClause
!PARSE-TREE: | | OmpAdjustOp -> Value = Need_Device_Ptr
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'v2'
+!PARSE-TREE: | Flags = None
+
!$omp declare variant(vsub) match ( construct = { dispatch } ) adjust_args(nothing : v1 ) adjust_args(need_device_ptr : v2)
end
subroutine vsub(v1, v2)
@@ -119,13 +132,15 @@ subroutine f2 (x, y)
!$omp declare variant (f1) match (construct={simd(uniform(y))})
end
end subroutine
-!CHECK: !$OMP DECLARE VARIANT (f1) MATCH(CONSTRUCT={SIMD(UNIFORM(y))})
-!PARSE-TREE: | | | | DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective
-!PARSE-TREE-NEXT: | | | | | Verbatim
-!PARSE-TREE-NEXT: | | | | | Name = 'f1'
-!PARSE-TREE-NEXT: | | | | | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector
-!PARSE-TREE-NEXT: | | | | | | OmpTraitSetSelectorName -> Value = Construct
-!PARSE-TREE-NEXT: | | | | | | OmpTraitSelector
-!PARSE-TREE-NEXT: | | | | | | | OmpTraitSelectorName -> Value = Simd
-!PARSE-TREE-NEXT: | | | | | | | Properties
-!PARSE-TREE-NEXT: | | | | | | | | OmpTraitProperty -> OmpClause -> Uniform -> Name = 'y'
+!CHECK: !$OMP DECLARE VARIANT(f1) MATCH(CONSTRUCT={SIMD(UNIFORM(y))})
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant
+!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'f1'
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector
+!PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct
+!PARSE-TREE: | | OmpTraitSelector
+!PARSE-TREE: | | | OmpTraitSelectorName -> Value = Simd
+!PARSE-TREE: | | | Properties
+!PARSE-TREE: | | | | OmpTraitProperty -> OmpClause -> Uniform -> Name = 'y'
+!PARSE-TREE: | Flags = None
diff --git a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90
index a25d750adc39d..f55ff958b0952 100644
--- a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90
+++ b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90
@@ -145,12 +145,12 @@ subroutine g05
!UNPARSE: SUBROUTINE g05
!UNPARSE: END SUBROUTINE
!UNPARSE: END INTERFACE
-!UNPARSE: !$OMP DECLARE VARIANT (g05) MATCH(USER={CONDITION(.true._4)})
+!UNPARSE: !$OMP DECLARE_VARIANT(g05) MATCH(USER={CONDITION(.true._4)})
!UNPARSE: END SUBROUTINE
-!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective
-!PARSE-TREE: | Verbatim
-!PARSE-TREE: | Name = 'g05'
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant
+!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'g05'
!PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector
!PARSE-TREE: | | OmpTraitSetSelectorName -> Value = User
!PARSE-TREE: | | OmpTraitSelector
@@ -159,6 +159,7 @@ subroutine g05
!PARSE-TREE: | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4'
!PARSE-TREE: | | | | | LiteralConstant -> LogicalLiteralConstant
!PARSE-TREE: | | | | | | bool = 'true'
+!PARSE-TREE: | Flags = None
subroutine f06
implicit none
diff --git a/flang/test/Semantics/OpenMP/declare-variant.f90 b/flang/test/Semantics/OpenMP/declare-variant.f90
index 84a0cdcd10d91..59b8bda3f2a99 100644
--- a/flang/test/Semantics/OpenMP/declare-variant.f90
+++ b/flang/test/Semantics/OpenMP/declare-variant.f90
@@ -1,9 +1,11 @@
! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=51
subroutine sub0
-!ERROR: Implicit subroutine declaration 'vsub1' in !$OMP DECLARE VARIANT
+!ERROR: The name 'vsub1' should refer to a procedure
+!ERROR: The name 'vsub1' has been implicitly declared
!$omp declare variant (sub:vsub1) match (construct={parallel})
-!ERROR: Implicit subroutine declaration 'sub1' in !$OMP DECLARE VARIANT
+!ERROR: The name 'sub1' should refer to a procedure
+!ERROR: The name 'sub1' has been implicitly declared
!$omp declare variant (sub1:vsub) match (construct={parallel})
contains
subroutine vsub
>From 7e54af8cd0a27970bccc319b5a23924a90aaea1d Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 23 Sep 2025 14:57:40 -0500
Subject: [PATCH 03/11] Fix directive name in message
---
flang/lib/Semantics/check-omp-structure.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index f10858ac1356d..9b1932255bd05 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1377,7 +1377,7 @@ void OmpStructureChecker::Enter(const parser::OmpDeclareVariantDirective &x) {
auto InvalidArgument{[&](parser::CharBlock source) {
context_.Say(source,
- "The argument to the DECLARE_MAPPER directive should be [base-name:]variant-name"_err_en_US);
+ "The argument to the DECLARE_VARIANT directive should be [base-name:]variant-name"_err_en_US);
}};
auto CheckSymbol{[&](const Symbol *sym, parser::CharBlock source) {
>From 6f624f979480e2998ef276d47d95761919bf61e2 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 23 Sep 2025 14:56:14 -0500
Subject: [PATCH 04/11] [flang][OpenMP] Use OmpDirectiveSpecification in
DECLARE_SIMD
---
flang/include/flang/Parser/openmp-utils.h | 2 -
flang/include/flang/Parser/parse-tree.h | 4 +-
flang/lib/Parser/openmp-parsers.cpp | 5 ++-
flang/lib/Parser/unparse.cpp | 7 ++--
flang/lib/Semantics/check-omp-structure.cpp | 34 ++++++++++++----
flang/lib/Semantics/resolve-directives.cpp | 7 ++--
flang/test/Parser/OpenMP/linear-clause.f90 | 40 +++++++++----------
.../OpenMP/openmp6-directive-spellings.f90 | 7 ++--
flang/test/Semantics/OpenMP/declare-simd.f90 | 23 +++++++++++
9 files changed, 84 insertions(+), 45 deletions(-)
create mode 100644 flang/test/Semantics/OpenMP/declare-simd.f90
diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h
index 64be9714f6cc2..e17728b5413e2 100644
--- a/flang/include/flang/Parser/openmp-utils.h
+++ b/flang/include/flang/Parser/openmp-utils.h
@@ -41,7 +41,6 @@ struct ConstructId {
MAKE_CONSTR_ID(OpenMPDeclarativeAllocate, D::OMPD_allocate);
MAKE_CONSTR_ID(OpenMPDeclarativeAssumes, D::OMPD_assumes);
MAKE_CONSTR_ID(OpenMPDeclareReductionConstruct, D::OMPD_declare_reduction);
-MAKE_CONSTR_ID(OpenMPDeclareSimdConstruct, D::OMPD_declare_simd);
MAKE_CONSTR_ID(OpenMPDeclareTargetConstruct, D::OMPD_declare_target);
MAKE_CONSTR_ID(OpenMPExecutableAllocate, D::OMPD_allocate);
MAKE_CONSTR_ID(OpenMPRequiresConstruct, D::OMPD_requires);
@@ -94,7 +93,6 @@ struct DirectiveNameScope {
} else if constexpr (std::is_same_v<T, OpenMPDeclarativeAllocate> ||
std::is_same_v<T, OpenMPDeclarativeAssumes> ||
std::is_same_v<T, OpenMPDeclareReductionConstruct> ||
- std::is_same_v<T, OpenMPDeclareSimdConstruct> ||
std::is_same_v<T, OpenMPDeclareTargetConstruct> ||
std::is_same_v<T, OpenMPExecutableAllocate> ||
std::is_same_v<T, OpenMPRequiresConstruct>) {
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index de65088c01eae..be30a95763208 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4987,9 +4987,9 @@ struct OpenMPDeclareReductionConstruct {
// 2.8.2 declare-simd -> DECLARE SIMD [(proc-name)] [declare-simd-clause[ [,]
// declare-simd-clause]...]
struct OpenMPDeclareSimdConstruct {
- TUPLE_CLASS_BOILERPLATE(OpenMPDeclareSimdConstruct);
+ WRAPPER_CLASS_BOILERPLATE(
+ OpenMPDeclareSimdConstruct, OmpDirectiveSpecification);
CharBlock source;
- std::tuple<Verbatim, std::optional<Name>, OmpClauseList> t;
};
// ref: [6.0:301-303]
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 6ec6eb4038933..0085576292ff5 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1836,8 +1836,9 @@ TYPE_PARSER(
// 2.8.2 Declare Simd construct
TYPE_PARSER(sourced(construct<OpenMPDeclareSimdConstruct>(
- verbatim("DECLARE SIMD"_tok) || verbatim("DECLARE_SIMD"_tok),
- maybe(parenthesized(name)), Parser<OmpClauseList>{})))
+ predicated(Parser<OmpDirectiveName>{},
+ IsDirective(llvm::omp::Directive::OMPD_declare_simd)) >=
+ Parser<OmpDirectiveSpecification>{})))
TYPE_PARSER(sourced( //
construct<OpenMPGroupprivate>(
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index fc81cfb7a3818..c9774dd137d2b 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2573,11 +2573,10 @@ class UnparseVisitor {
Put("\n");
EndOpenMP();
}
- void Unparse(const OpenMPDeclareSimdConstruct &y) {
+ void Unparse(const OpenMPDeclareSimdConstruct &x) {
BeginOpenMP();
- Word("!$OMP DECLARE SIMD ");
- Walk("(", std::get<std::optional<Name>>(y.t), ")");
- Walk(std::get<OmpClauseList>(y.t));
+ Word("!$OMP ");
+ Walk(x.v);
Put("\n");
EndOpenMP();
}
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 9b1932255bd05..55aa5a0a9f54d 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -624,11 +624,6 @@ template <typename Checker> struct DirectiveSpellingVisitor {
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_assumes);
return false;
}
- bool Pre(const parser::OpenMPDeclareSimdConstruct &x) {
- checker_(
- std::get<parser::Verbatim>(x.t).source, Directive::OMPD_declare_simd);
- return false;
- }
bool Pre(const parser::OpenMPDeclareTargetConstruct &x) {
checker_(
std::get<parser::Verbatim>(x.t).source, Directive::OMPD_declare_target);
@@ -1356,8 +1351,33 @@ void OmpStructureChecker::Leave(const parser::OpenMPThreadprivate &x) {
}
void OmpStructureChecker::Enter(const parser::OpenMPDeclareSimdConstruct &x) {
- const auto &dir{std::get<parser::Verbatim>(x.t)};
- PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_declare_simd);
+ const parser::OmpDirectiveName &dirName{x.v.DirName()};
+ PushContextAndClauseSets(dirName.source, dirName.v);
+
+ const parser::OmpArgumentList &args{x.v.Arguments()};
+ if (args.v.empty()) {
+ return;
+ } else if (args.v.size() > 1) {
+ context_.Say(args.source,
+ "DECLARE_SIMD directive should have at most one argument"_err_en_US);
+ return;
+ }
+
+ const parser::OmpArgument &arg{args.v.front()};
+ if (auto *sym{GetArgumentSymbol(arg)}) {
+ if (!IsProcedure(*sym) && !IsFunction(*sym)) {
+ context_.Say(arg.source,
+ "The name '%s' should refer to a procedure"_err_en_US, sym->name());
+ }
+ if (sym->test(Symbol::Flag::Implicit)) {
+ context_.Say(arg.source,
+ "The name '%s' has been implicitly declared"_err_en_US,
+ sym->name());
+ }
+ } else {
+ context_.Say(arg.source,
+ "The argument to the DECLARE_SIMD directive should be a procedure name"_err_en_US);
+ }
}
void OmpStructureChecker::Leave(const parser::OpenMPDeclareSimdConstruct &) {
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index f1f78620532f5..218e3e7266ca9 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -473,9 +473,10 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
bool Pre(const parser::OpenMPDeclareSimdConstruct &x) {
PushContext(x.source, llvm::omp::Directive::OMPD_declare_simd);
- const auto &name{std::get<std::optional<parser::Name>>(x.t)};
- if (name) {
- ResolveOmpName(*name, Symbol::Flag::OmpDeclareSimd);
+ for (const parser::OmpArgument &arg : x.v.Arguments().v) {
+ if (auto *object{omp::GetArgumentObject(arg)}) {
+ ResolveOmpObject(*object, Symbol::Flag::OmpDeclareSimd);
+ }
}
return true;
}
diff --git a/flang/test/Parser/OpenMP/linear-clause.f90 b/flang/test/Parser/OpenMP/linear-clause.f90
index 5ea31ce58fc5a..b53dfe5f941a3 100644
--- a/flang/test/Parser/OpenMP/linear-clause.f90
+++ b/flang/test/Parser/OpenMP/linear-clause.f90
@@ -84,18 +84,16 @@ subroutine f03(x)
!UNPARSE: SUBROUTINE f03 (x)
!UNPARSE: INTEGER x
-!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL)
+!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL)
!UNPARSE: END SUBROUTINE
-!PARSE-TREE: SpecificationPart
-![...]
-!PARSE-TREE: | DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct
-!PARSE-TREE: | | Verbatim
-!PARSE-TREE: | | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
-!PARSE-TREE: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
-!PARSE-TREE: | | | Modifier -> OmpLinearModifier -> Value = Uval
-!PARSE-TREE: | | | bool = 'true'
-!PARSE-TREE: ExecutionPart -> Block
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare simd
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | Modifier -> OmpLinearModifier -> Value = Uval
+!PARSE-TREE: | | bool = 'true'
+!PARSE-TREE: | Flags = None
subroutine f04(x)
integer :: x
@@ -104,17 +102,15 @@ subroutine f04(x)
!UNPARSE: SUBROUTINE f04 (x)
!UNPARSE: INTEGER x
-!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL, STEP(3_4))
+!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL, STEP(3_4))
!UNPARSE: END SUBROUTINE
-!PARSE-TREE: SpecificationPart
-![...]
-!PARSE-TREE: | DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct
-!PARSE-TREE: | | Verbatim
-!PARSE-TREE: | | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
-!PARSE-TREE: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
-!PARSE-TREE: | | | Modifier -> OmpLinearModifier -> Value = Uval
-!PARSE-TREE: | | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr = '3_4'
-!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '3'
-!PARSE-TREE: | | | bool = 'true'
-!PARSE-TREE: ExecutionPart -> Block
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare simd
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | Modifier -> OmpLinearModifier -> Value = Uval
+!PARSE-TREE: | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr = '3_4'
+!PARSE-TREE: | | | LiteralConstant -> IntLiteralConstant = '3'
+!PARSE-TREE: | | bool = 'true'
+!PARSE-TREE: | Flags = None
diff --git a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90
index f55ff958b0952..b72c5a2c1c086 100644
--- a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90
+++ b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90
@@ -111,12 +111,13 @@ subroutine f03
end
!UNPARSE: SUBROUTINE f03
-!UNPARSE: !$OMP DECLARE SIMD
+!UNPARSE: !$OMP DECLARE_SIMD
!UNPARSE: END SUBROUTINE
-!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct
-!PARSE-TREE: | Verbatim
+!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare simd
!PARSE-TREE: | OmpClauseList ->
+!PARSE-TREE: | Flags = None
subroutine f04
!$omp declare_target
diff --git a/flang/test/Semantics/OpenMP/declare-simd.f90 b/flang/test/Semantics/OpenMP/declare-simd.f90
new file mode 100644
index 0000000000000..825eb58f2adb5
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/declare-simd.f90
@@ -0,0 +1,23 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60
+
+module m
+
+!ERROR: The name 'x' should refer to a procedure
+!ERROR: The name 'x' has been implicitly declared
+!$omp declare_simd(x)
+
+!ERROR: DECLARE_SIMD directive should have at most one argument
+!$omp declare_simd(f00, f01)
+
+!ERROR: The argument to the DECLARE_SIMD directive should be a procedure name
+!$omp declare_simd(v : integer)
+
+contains
+
+subroutine f00
+end
+
+subroutine f01
+end
+
+end module
>From acc37ebde987738210f7dc4a24e7591765858cc4 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 23 Sep 2025 15:39:46 -0500
Subject: [PATCH 05/11] format
---
flang/lib/Semantics/check-omp-structure.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 55aa5a0a9f54d..cf89d305e3cb2 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1371,8 +1371,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPDeclareSimdConstruct &x) {
}
if (sym->test(Symbol::Flag::Implicit)) {
context_.Say(arg.source,
- "The name '%s' has been implicitly declared"_err_en_US,
- sym->name());
+ "The name '%s' has been implicitly declared"_err_en_US, sym->name());
}
} else {
context_.Say(arg.source,
>From 30c575b992259508b690f691d83412ba506c9ce1 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 23 Sep 2025 16:39:41 -0500
Subject: [PATCH 06/11] Add missing trivial overload
---
flang/include/flang/Parser/openmp-utils.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h
index e17728b5413e2..4b8fe6a5b49f0 100644
--- a/flang/include/flang/Parser/openmp-utils.h
+++ b/flang/include/flang/Parser/openmp-utils.h
@@ -56,6 +56,10 @@ struct DirectiveNameScope {
return name;
}
+ static OmpDirectiveName GetOmpDirectiveName(const OmpDirectiveName &x) {
+ return x;
+ }
+
static OmpDirectiveName GetOmpDirectiveName(const OmpBeginLoopDirective &x) {
return x.DirName();
}
>From 525f12fa0da6c22dded6c19e2338b6bcc3c2da6f Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 24 Sep 2025 07:59:16 -0500
Subject: [PATCH 07/11] [flang][OpenMP] Use OmpDirectiveSpecification in
DECLARE_TARGET
---
flang/include/flang/Parser/openmp-utils.h | 2 -
flang/include/flang/Parser/parse-tree.h | 10 +-
flang/lib/Lower/OpenMP/OpenMP.cpp | 14 +-
flang/lib/Parser/openmp-parsers.cpp | 18 +-
flang/lib/Parser/unparse.cpp | 4 +-
flang/lib/Semantics/check-omp-structure.cpp | 245 +++++++++---------
flang/lib/Semantics/check-omp-structure.h | 3 -
flang/lib/Semantics/resolve-directives.cpp | 27 +-
flang/lib/Semantics/resolve-names.cpp | 77 +++---
.../OpenMP/declare-target-indirect-tree.f90 | 28 +-
.../OpenMP/declare-target-to-clause.f90 | 14 +-
.../OpenMP/declare_target-device_type.f90 | 108 ++++++--
.../Parser/OpenMP/enter-automap-modifier.f90 | 11 +-
.../OpenMP/openmp6-directive-spellings.f90 | 9 +-
.../Semantics/OpenMP/blank-common-block.f90 | 1 +
...lare-target-function-name-with-symbols.f90 | 2 +-
16 files changed, 319 insertions(+), 254 deletions(-)
diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h
index 4b8fe6a5b49f0..bf54f970a7d3a 100644
--- a/flang/include/flang/Parser/openmp-utils.h
+++ b/flang/include/flang/Parser/openmp-utils.h
@@ -41,7 +41,6 @@ struct ConstructId {
MAKE_CONSTR_ID(OpenMPDeclarativeAllocate, D::OMPD_allocate);
MAKE_CONSTR_ID(OpenMPDeclarativeAssumes, D::OMPD_assumes);
MAKE_CONSTR_ID(OpenMPDeclareReductionConstruct, D::OMPD_declare_reduction);
-MAKE_CONSTR_ID(OpenMPDeclareTargetConstruct, D::OMPD_declare_target);
MAKE_CONSTR_ID(OpenMPExecutableAllocate, D::OMPD_allocate);
MAKE_CONSTR_ID(OpenMPRequiresConstruct, D::OMPD_requires);
@@ -97,7 +96,6 @@ struct DirectiveNameScope {
} else if constexpr (std::is_same_v<T, OpenMPDeclarativeAllocate> ||
std::is_same_v<T, OpenMPDeclarativeAssumes> ||
std::is_same_v<T, OpenMPDeclareReductionConstruct> ||
- std::is_same_v<T, OpenMPDeclareTargetConstruct> ||
std::is_same_v<T, OpenMPExecutableAllocate> ||
std::is_same_v<T, OpenMPRequiresConstruct>) {
return MakeName(std::get<Verbatim>(x.t).source, ConstructId<T>::id);
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index be30a95763208..e7593d9875097 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4961,10 +4961,16 @@ struct OmpDeclareTargetSpecifier {
std::variant<OmpDeclareTargetWithList, OmpDeclareTargetWithClause> u;
};
+// Ref: [4.5:110-113], [5.0:180-185], [5.1:210-216], [5.2:206-207],
+// [6.0:346-348]
+//
+// declare-target-directive -> // since 4.5
+// DECLARE_TARGET[(extended-list)] |
+// DECLARE_TARGET clause-list
struct OpenMPDeclareTargetConstruct {
- TUPLE_CLASS_BOILERPLATE(OpenMPDeclareTargetConstruct);
+ WRAPPER_CLASS_BOILERPLATE(
+ OpenMPDeclareTargetConstruct, OmpDirectiveSpecification);
CharBlock source;
- std::tuple<Verbatim, OmpDeclareTargetSpecifier> t;
};
// OMP v5.2: 5.8.8
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index d2e865b3e1d0c..1cb3335abbd06 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -761,19 +761,17 @@ static void promoteNonCPtrUseDevicePtrArgsToUseDeviceAddr(
static void getDeclareTargetInfo(
lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
- const parser::OpenMPDeclareTargetConstruct &declareTargetConstruct,
+ const parser::OpenMPDeclareTargetConstruct &construct,
mlir::omp::DeclareTargetOperands &clauseOps,
llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &symbolAndClause) {
- const auto &spec =
- std::get<parser::OmpDeclareTargetSpecifier>(declareTargetConstruct.t);
- if (const auto *objectList{parser::Unwrap<parser::OmpObjectList>(spec.u)}) {
- ObjectList objects{makeObjects(*objectList, semaCtx)};
+
+ if (!construct.v.Arguments().v.empty()) {
+ ObjectList objects{makeObjects(construct.v.Arguments(), semaCtx)};
// Case: declare target(func, var1, var2)
gatherFuncAndVarSyms(objects, mlir::omp::DeclareTargetCaptureClause::to,
symbolAndClause, /*automap=*/false);
- } else if (const auto *clauseList{
- parser::Unwrap<parser::OmpClauseList>(spec.u)}) {
- List<Clause> clauses = makeClauses(*clauseList, semaCtx);
+ } else {
+ List<Clause> clauses = makeClauses(construct.v.Clauses(), semaCtx);
if (clauses.empty()) {
Fortran::lower::pft::FunctionLikeUnit *owningProc =
eval.getOwningProcedure();
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 0085576292ff5..bd080386c0aea 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1773,23 +1773,11 @@ TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>(
IsDirective(llvm::omp::Directive::OMPD_declare_reduction)) >=
Parser<OmpDirectiveSpecification>{})))
-// declare-target with list
-TYPE_PARSER(sourced(construct<OmpDeclareTargetWithList>(
- parenthesized(Parser<OmpObjectList>{}))))
-
-// declare-target with clause
-TYPE_PARSER(
- sourced(construct<OmpDeclareTargetWithClause>(Parser<OmpClauseList>{})))
-
-// declare-target-specifier
-TYPE_PARSER(
- construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithList>{}) ||
- construct<OmpDeclareTargetSpecifier>(Parser<OmpDeclareTargetWithClause>{}))
-
// 2.10.6 Declare Target Construct
TYPE_PARSER(sourced(construct<OpenMPDeclareTargetConstruct>(
- verbatim("DECLARE TARGET"_tok) || verbatim("DECLARE_TARGET"_tok),
- Parser<OmpDeclareTargetSpecifier>{})))
+ predicated(Parser<OmpDirectiveName>{},
+ IsDirective(llvm::omp::Directive::OMPD_declare_target)) >=
+ Parser<OmpDirectiveSpecification>{})))
static OmpMapperSpecifier ConstructOmpMapperSpecifier(
std::optional<Name> &&mapperName, TypeSpec &&typeSpec, Name &&varName) {
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index c9774dd137d2b..be166bcb743ba 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2582,8 +2582,8 @@ class UnparseVisitor {
}
void Unparse(const OpenMPDeclareTargetConstruct &x) {
BeginOpenMP();
- Word("!$OMP DECLARE TARGET ");
- Walk(std::get<parser::OmpDeclareTargetSpecifier>(x.t));
+ Word("!$OMP ");
+ Walk(x.v);
Put("\n");
EndOpenMP();
}
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index cf89d305e3cb2..05ff541657b1a 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -624,11 +624,6 @@ template <typename Checker> struct DirectiveSpellingVisitor {
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_assumes);
return false;
}
- bool Pre(const parser::OpenMPDeclareTargetConstruct &x) {
- checker_(
- std::get<parser::Verbatim>(x.t).source, Directive::OMPD_declare_target);
- return false;
- }
bool Pre(const parser::OpenMPGroupprivate &x) {
checker_(x.v.DirName().source, Directive::OMPD_groupprivate);
return false;
@@ -1615,38 +1610,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Allocate &x) {
}
}
-void OmpStructureChecker::Enter(const parser::OmpDeclareTargetWithClause &x) {
- SetClauseSets(llvm::omp::Directive::OMPD_declare_target);
-}
-
-void OmpStructureChecker::Leave(const parser::OmpDeclareTargetWithClause &x) {
- if (x.v.v.size() > 0) {
- const parser::OmpClause *enterClause =
- FindClause(llvm::omp::Clause::OMPC_enter);
- const parser::OmpClause *toClause = FindClause(llvm::omp::Clause::OMPC_to);
- const parser::OmpClause *linkClause =
- FindClause(llvm::omp::Clause::OMPC_link);
- const parser::OmpClause *indirectClause =
- FindClause(llvm::omp::Clause::OMPC_indirect);
- if (!enterClause && !toClause && !linkClause) {
- context_.Say(x.source,
- "If the DECLARE TARGET directive has a clause, it must contain at least one ENTER clause or LINK clause"_err_en_US);
- }
- if (indirectClause && !enterClause) {
- context_.Say(x.source,
- "The INDIRECT clause cannot be used without the ENTER clause with the DECLARE TARGET directive."_err_en_US);
- }
- unsigned version{context_.langOptions().OpenMPVersion};
- if (toClause && version >= 52) {
- context_.Warn(common::UsageWarning::OpenMPUsage, toClause->source,
- "The usage of TO clause on DECLARE TARGET directive has been deprecated. Use ENTER clause instead."_warn_en_US);
- }
- if (indirectClause) {
- CheckAllowedClause(llvm::omp::Clause::OMPC_indirect);
- }
- }
-}
-
void OmpStructureChecker::Enter(const parser::OpenMPDeclareMapperConstruct &x) {
const parser::OmpDirectiveName &dirName{x.v.DirName()};
PushContextAndClauseSets(dirName.source, dirName.v);
@@ -1698,42 +1661,6 @@ void OmpStructureChecker::Leave(
dirContext_.pop_back();
}
-void OmpStructureChecker::Enter(const parser::OpenMPDeclareTargetConstruct &x) {
- const auto &dir{std::get<parser::Verbatim>(x.t)};
- PushContext(dir.source, llvm::omp::Directive::OMPD_declare_target);
-}
-
-void OmpStructureChecker::Enter(const parser::OmpDeclareTargetWithList &x) {
- SymbolSourceMap symbols;
- GetSymbolsInObjectList(x.v, symbols);
- for (auto &[symbol, source] : symbols) {
- const GenericDetails *genericDetails = symbol->detailsIf<GenericDetails>();
- if (genericDetails) {
- context_.Say(source,
- "The procedure '%s' in DECLARE TARGET construct cannot be a generic name."_err_en_US,
- symbol->name());
- genericDetails->specific();
- }
- if (IsProcedurePointer(*symbol)) {
- context_.Say(source,
- "The procedure '%s' in DECLARE TARGET construct cannot be a procedure pointer."_err_en_US,
- symbol->name());
- }
- const SubprogramDetails *entryDetails =
- symbol->detailsIf<SubprogramDetails>();
- if (entryDetails && entryDetails->entryScope()) {
- context_.Say(source,
- "The procedure '%s' in DECLARE TARGET construct cannot be an entry name."_err_en_US,
- symbol->name());
- }
- if (IsStmtFunction(*symbol)) {
- context_.Say(source,
- "The procedure '%s' in DECLARE TARGET construct cannot be a statement function."_err_en_US,
- symbol->name());
- }
- }
-}
-
void OmpStructureChecker::CheckSymbolName(
const parser::CharBlock &source, const parser::OmpObject &object) {
common::visit(
@@ -1766,62 +1693,138 @@ void OmpStructureChecker::CheckSymbolNames(
}
}
+void OmpStructureChecker::Enter(const parser::OpenMPDeclareTargetConstruct &x) {
+ const parser::OmpDirectiveName &dirName{x.v.DirName()};
+ PushContext(dirName.source, dirName.v);
+
+ // Check if arguments are extended-list-items.
+ for (const parser::OmpArgument &arg : x.v.Arguments().v) {
+ const Symbol *symbol{GetArgumentSymbol(arg)};
+ if (!symbol) {
+ context_.Say(arg.source,
+ "An argument to the DECLARE TARGET directive should be an extended-list-item"_err_en_US);
+ continue;
+ }
+ const GenericDetails *genericDetails = symbol->detailsIf<GenericDetails>();
+ if (genericDetails) {
+ context_.Say(arg.source,
+ "The procedure '%s' in DECLARE TARGET construct cannot be a generic name."_err_en_US,
+ symbol->name());
+ genericDetails->specific();
+ }
+ if (IsProcedurePointer(*symbol)) {
+ context_.Say(arg.source,
+ "The procedure '%s' in DECLARE TARGET construct cannot be a procedure pointer."_err_en_US,
+ symbol->name());
+ }
+ const SubprogramDetails *entryDetails =
+ symbol->detailsIf<SubprogramDetails>();
+ if (entryDetails && entryDetails->entryScope()) {
+ context_.Say(arg.source,
+ "The procedure '%s' in DECLARE TARGET construct cannot be an entry name."_err_en_US,
+ symbol->name());
+ }
+ if (IsStmtFunction(*symbol)) {
+ context_.Say(arg.source,
+ "The procedure '%s' in DECLARE TARGET construct cannot be a statement function."_err_en_US,
+ symbol->name());
+ }
+ }
+
+ // Check if there are arguments or clauses, but not both.
+ if (!x.v.Clauses().v.empty()) {
+ if (!x.v.Arguments().v.empty()) {
+ context_.Say(x.source,
+ "DECLARE TARGET directive can have argument or clauses, but not both"_err_en_US);
+ }
+ SetClauseSets(llvm::omp::Directive::OMPD_declare_target);
+ }
+}
+
void OmpStructureChecker::Leave(const parser::OpenMPDeclareTargetConstruct &x) {
- const auto &dir{std::get<parser::Verbatim>(x.t)};
- const auto &spec{std::get<parser::OmpDeclareTargetSpecifier>(x.t)};
+ const parser::OmpDirectiveName &dirName{x.v.DirName()};
+
// Handle both forms of DECLARE TARGET.
// - Extended list: It behaves as if there was an ENTER/TO clause with the
// list of objects as argument. It accepts no explicit clauses.
// - With clauses.
- if (const auto *objectList{parser::Unwrap<parser::OmpObjectList>(spec.u)}) {
- deviceConstructFound_ = true;
- CheckSymbolNames(dir.source, *objectList);
- CheckVarIsNotPartOfAnotherVar(dir.source, *objectList);
- CheckThreadprivateOrDeclareTargetVar(*objectList);
- } else if (const auto *clauseList{
- parser::Unwrap<parser::OmpClauseList>(spec.u)}) {
- bool toClauseFound{false}, deviceTypeClauseFound{false},
- enterClauseFound{false};
- for (const auto &clause : clauseList->v) {
- common::visit(
- common::visitors{
- [&](const parser::OmpClause::To &toClause) {
- toClauseFound = true;
- auto &objList{std::get<parser::OmpObjectList>(toClause.v.t)};
- CheckSymbolNames(dir.source, objList);
- CheckVarIsNotPartOfAnotherVar(dir.source, objList);
- CheckThreadprivateOrDeclareTargetVar(objList);
- },
- [&](const parser::OmpClause::Link &linkClause) {
- CheckSymbolNames(dir.source, linkClause.v);
- CheckVarIsNotPartOfAnotherVar(dir.source, linkClause.v);
- CheckThreadprivateOrDeclareTargetVar(linkClause.v);
- },
- [&](const parser::OmpClause::Enter &enterClause) {
- enterClauseFound = true;
- auto &objList{std::get<parser::OmpObjectList>(enterClause.v.t)};
- CheckSymbolNames(dir.source, objList);
- CheckVarIsNotPartOfAnotherVar(dir.source, objList);
- CheckThreadprivateOrDeclareTargetVar(objList);
- },
- [&](const parser::OmpClause::DeviceType &deviceTypeClause) {
- deviceTypeClauseFound = true;
- if (deviceTypeClause.v.v !=
- parser::OmpDeviceTypeClause::DeviceTypeDescription::Host) {
- // Function / subroutine explicitly marked as runnable by the
- // target device.
- deviceConstructFound_ = true;
- }
- },
- [&](const auto &) {},
- },
- clause.u);
+ for (const parser::OmpArgument &arg : x.v.Arguments().v) {
+ if (auto *object{GetArgumentObject(arg)}) {
+ deviceConstructFound_ = true;
+ CheckSymbolName(dirName.source, *object);
+ CheckVarIsNotPartOfAnotherVar(dirName.source, *object);
+ CheckThreadprivateOrDeclareTargetVar(*object);
+ }
+ }
- if ((toClauseFound || enterClauseFound) && !deviceTypeClauseFound) {
- deviceConstructFound_ = true;
- }
+ if (!x.v.Clauses().v.empty()) {
+ const parser::OmpClause *enterClause =
+ FindClause(llvm::omp::Clause::OMPC_enter);
+ const parser::OmpClause *toClause = FindClause(llvm::omp::Clause::OMPC_to);
+ const parser::OmpClause *linkClause =
+ FindClause(llvm::omp::Clause::OMPC_link);
+ const parser::OmpClause *indirectClause =
+ FindClause(llvm::omp::Clause::OMPC_indirect);
+ if (!enterClause && !toClause && !linkClause) {
+ context_.Say(x.source,
+ "If the DECLARE TARGET directive has a clause, it must contain at least one ENTER clause or LINK clause"_err_en_US);
+ }
+ if (indirectClause && !enterClause) {
+ context_.Say(x.source,
+ "The INDIRECT clause cannot be used without the ENTER clause with the DECLARE TARGET directive."_err_en_US);
+ }
+ unsigned version{context_.langOptions().OpenMPVersion};
+ if (toClause && version >= 52) {
+ context_.Warn(common::UsageWarning::OpenMPUsage, toClause->source,
+ "The usage of TO clause on DECLARE TARGET directive has been deprecated. Use ENTER clause instead."_warn_en_US);
+ }
+ if (indirectClause) {
+ CheckAllowedClause(llvm::omp::Clause::OMPC_indirect);
}
}
+
+ bool toClauseFound{false}, deviceTypeClauseFound{false},
+ enterClauseFound{false};
+ for (const parser::OmpClause &clause : x.v.Clauses().v) {
+ common::visit(
+ common::visitors{
+ [&](const parser::OmpClause::To &toClause) {
+ toClauseFound = true;
+ auto &objList{std::get<parser::OmpObjectList>(toClause.v.t)};
+ CheckSymbolNames(dirName.source, objList);
+ CheckVarIsNotPartOfAnotherVar(dirName.source, objList);
+ CheckThreadprivateOrDeclareTargetVar(objList);
+ },
+ [&](const parser::OmpClause::Link &linkClause) {
+ CheckSymbolNames(dirName.source, linkClause.v);
+ CheckVarIsNotPartOfAnotherVar(dirName.source, linkClause.v);
+ CheckThreadprivateOrDeclareTargetVar(linkClause.v);
+ },
+ [&](const parser::OmpClause::Enter &enterClause) {
+ enterClauseFound = true;
+ auto &objList{std::get<parser::OmpObjectList>(enterClause.v.t)};
+ CheckSymbolNames(dirName.source, objList);
+ CheckVarIsNotPartOfAnotherVar(dirName.source, objList);
+ CheckThreadprivateOrDeclareTargetVar(objList);
+ },
+ [&](const parser::OmpClause::DeviceType &deviceTypeClause) {
+ deviceTypeClauseFound = true;
+ if (deviceTypeClause.v.v !=
+ parser::OmpDeviceTypeClause::DeviceTypeDescription::Host) {
+ // Function / subroutine explicitly marked as runnable by the
+ // target device.
+ deviceConstructFound_ = true;
+ }
+ },
+ [&](const auto &) {},
+ },
+ clause.u);
+
+ if ((toClauseFound || enterClauseFound) && !deviceTypeClauseFound) {
+ deviceConstructFound_ = true;
+ }
+ }
+
dirContext_.pop_back();
}
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 176f6568814c5..193784555a887 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -113,9 +113,6 @@ class OmpStructureChecker
void Leave(const parser::OpenMPDeclareTargetConstruct &);
void Enter(const parser::OpenMPDepobjConstruct &);
void Leave(const parser::OpenMPDepobjConstruct &);
- void Enter(const parser::OmpDeclareTargetWithList &);
- void Enter(const parser::OmpDeclareTargetWithClause &);
- void Leave(const parser::OmpDeclareTargetWithClause &);
void Enter(const parser::OpenMPDispatchConstruct &);
void Leave(const parser::OpenMPDispatchConstruct &);
void Enter(const parser::OmpErrorDirective &);
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 218e3e7266ca9..7ef211c8b428c 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -2324,22 +2324,17 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPCriticalConstruct &x) {
bool OmpAttributeVisitor::Pre(const parser::OpenMPDeclareTargetConstruct &x) {
PushContext(x.source, llvm::omp::Directive::OMPD_declare_target);
- const auto &spec{std::get<parser::OmpDeclareTargetSpecifier>(x.t)};
- if (const auto *objectList{parser::Unwrap<parser::OmpObjectList>(spec.u)}) {
- ResolveOmpObjectList(*objectList, Symbol::Flag::OmpDeclareTarget);
- } else if (const auto *clauseList{
- parser::Unwrap<parser::OmpClauseList>(spec.u)}) {
- for (const auto &clause : clauseList->v) {
- if (const auto *toClause{std::get_if<parser::OmpClause::To>(&clause.u)}) {
- auto &objList{std::get<parser::OmpObjectList>(toClause->v.t)};
- ResolveOmpObjectList(objList, Symbol::Flag::OmpDeclareTarget);
- } else if (const auto *linkClause{
- std::get_if<parser::OmpClause::Link>(&clause.u)}) {
- ResolveOmpObjectList(linkClause->v, Symbol::Flag::OmpDeclareTarget);
- } else if (const auto *enterClause{
- std::get_if<parser::OmpClause::Enter>(&clause.u)}) {
- ResolveOmpObjectList(std::get<parser::OmpObjectList>(enterClause->v.t),
- Symbol::Flag::OmpDeclareTarget);
+
+ for (const parser::OmpArgument &arg : x.v.Arguments().v) {
+ if (auto *object{omp::GetArgumentObject(arg)}) {
+ ResolveOmpObject(*object, Symbol::Flag::OmpDeclareTarget);
+ }
+ }
+
+ for (const parser::OmpClause &clause : x.v.Clauses().v) {
+ if (auto *objects{parser::omp::GetOmpObjectList(clause)}) {
+ for (const parser::OmpObject &object : objects->v) {
+ ResolveOmpObject(object, Symbol::Flag::OmpDeclareTarget);
}
}
}
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 3a6115dae2da5..9b728d6b70deb 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -24,6 +24,7 @@
#include "flang/Evaluate/intrinsics.h"
#include "flang/Evaluate/tools.h"
#include "flang/Evaluate/type.h"
+#include "flang/Parser/openmp-utils.h"
#include "flang/Parser/parse-tree-visitor.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Parser/tools.h"
@@ -1572,51 +1573,41 @@ class OmpVisitor : public virtual DeclarationVisitor {
}
void Post(const parser::OpenMPThreadprivate &) { SkipImplicitTyping(false); }
bool Pre(const parser::OpenMPDeclareTargetConstruct &x) {
- const auto &spec{std::get<parser::OmpDeclareTargetSpecifier>(x.t)};
- auto populateDeclareTargetNames{[this](const parser::OmpObjectList
- &objectList) {
- for (const auto &ompObject : objectList.v) {
- common::visit(
- common::visitors{
- [&](const parser::Designator &designator) {
- if (const auto *name{
- semantics::getDesignatorNameIfDataRef(designator)}) {
- specPartState_.declareTargetNames.insert(name->source);
- }
- },
- [&](const parser::Name &name) {
- specPartState_.declareTargetNames.insert(name.source);
- },
- [&](const parser::OmpObject::Invalid &invalid) {
- switch (invalid.v) {
- SWITCH_COVERS_ALL_CASES
- case parser::OmpObject::Invalid::Kind::BlankCommonBlock:
- context().Say(invalid.source,
- "Blank common blocks are not allowed as directive or clause arguments"_err_en_US);
- break;
- }
- },
- },
- ompObject.u);
- }
+ auto addObjectName{[&](const parser::OmpObject &object) {
+ common::visit(
+ common::visitors{
+ [&](const parser::Designator &designator) {
+ if (const auto *name{
+ semantics::getDesignatorNameIfDataRef(designator)}) {
+ specPartState_.declareTargetNames.insert(name->source);
+ }
+ },
+ [&](const parser::Name &name) {
+ specPartState_.declareTargetNames.insert(name.source);
+ },
+ [&](const parser::OmpObject::Invalid &invalid) {
+ switch (invalid.v) {
+ SWITCH_COVERS_ALL_CASES
+ case parser::OmpObject::Invalid::Kind::BlankCommonBlock:
+ context().Say(invalid.source,
+ "Blank common blocks are not allowed as directive or clause arguments"_err_en_US);
+ break;
+ }
+ },
+ },
+ object.u);
}};
- if (const auto *objectList{parser::Unwrap<parser::OmpObjectList>(spec.u)}) {
- populateDeclareTargetNames(*objectList);
- } else if (const auto *clauseList{
- parser::Unwrap<parser::OmpClauseList>(spec.u)}) {
- for (const auto &clause : clauseList->v) {
- if (const auto *toClause{
- std::get_if<parser::OmpClause::To>(&clause.u)}) {
- populateDeclareTargetNames(
- std::get<parser::OmpObjectList>(toClause->v.t));
- } else if (const auto *linkClause{
- std::get_if<parser::OmpClause::Link>(&clause.u)}) {
- populateDeclareTargetNames(linkClause->v);
- } else if (const auto *enterClause{
- std::get_if<parser::OmpClause::Enter>(&clause.u)}) {
- populateDeclareTargetNames(
- std::get<parser::OmpObjectList>(enterClause->v.t));
+ for (const parser::OmpArgument &arg : x.v.Arguments().v) {
+ if (auto *object{omp::GetArgumentObject(arg)}) {
+ addObjectName(*object);
+ }
+ }
+
+ for (const parser::OmpClause &clause : x.v.Clauses().v) {
+ if (auto *objects{parser::omp::GetOmpObjectList(clause)}) {
+ for (const parser::OmpObject &object : objects->v) {
+ addObjectName(object);
}
}
}
diff --git a/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90 b/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90
index 916bd66017ce0..16dc4eb44e6fd 100644
--- a/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90
+++ b/flang/test/Parser/OpenMP/declare-target-indirect-tree.f90
@@ -1,5 +1,3 @@
-! REQUIRES: openmp_runtime
-
! RUN: %flang_fc1 %openmp_flags -fopenmp-version=52 -fdebug-dump-parse-tree %s | FileCheck %s
! RUN: %flang_fc1 %openmp_flags -fdebug-unparse -fopenmp-version=52 %s | FileCheck %s --check-prefix="UNPARSE"
@@ -15,11 +13,14 @@ function func() result(i)
contains
function func1() result(i)
!$omp declare target enter(func1) indirect(.true.)
- !CHECK: | | | | | OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> Enter -> OmpEnterClause
- !CHECK-NEXT: | | | | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func1'
- !CHECK-NEXT: | | | | | OmpClause -> Indirect -> OmpIndirectClause -> Scalar -> Logical -> Expr = '.true._4'
- !CHECK-NEXT: | | | | | | LiteralConstant -> LogicalLiteralConstant
- !CHECK-NEXT: | | | | | | | bool = 'true'
+ !CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+ !CHECK-NEXT: | OmpDirectiveName -> llvm::omp::Directive = declare target
+ !CHECK-NEXT: | OmpClauseList -> OmpClause -> Enter -> OmpEnterClause
+ !CHECK-NEXT: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func1'
+ !CHECK-NEXT: | OmpClause -> Indirect -> OmpIndirectClause -> Scalar -> Logical -> Expr = '.true._4'
+ !CHECK-NEXT: | | LiteralConstant -> LogicalLiteralConstant
+ !CHECK-NEXT: | | | bool = 'true'
+ !CHECK-NEXT: | Flags = None
character(1) :: i
i = 'a'
return
@@ -27,9 +28,12 @@ function func1() result(i)
function func2() result(i)
!$omp declare target enter(func2) indirect
- !CHECK: | | | | | OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> Enter -> OmpEnterClause
- !CHECK-NEXT: | | | | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func2'
- !CHECK-NEXT: | | | | | OmpClause -> Indirect -> OmpIndirectClause ->
+ !CHECK: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+ !CHECK-NEXT: | OmpDirectiveName -> llvm::omp::Directive = declare target
+ !CHECK-NEXT: | OmpClauseList -> OmpClause -> Enter -> OmpEnterClause
+ !CHECK-NEXT: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'func2'
+ !CHECK-NEXT: | OmpClause -> Indirect -> OmpIndirectClause ->
+ !CHECK-NEXT: | Flags = None
character(1) :: i
i = 'b'
return
@@ -51,5 +55,5 @@ program main
end program
-!UNPARSE: !$OMP DECLARE TARGET ENTER(func1) INDIRECT(.true._4)
-!UNPARSE: !$OMP DECLARE TARGET ENTER(func2) INDIRECT()
+!UNPARSE: !$OMP DECLARE TARGET ENTER(func1) INDIRECT(.true._4)
+!UNPARSE: !$OMP DECLARE TARGET ENTER(func2) INDIRECT()
diff --git a/flang/test/Parser/OpenMP/declare-target-to-clause.f90 b/flang/test/Parser/OpenMP/declare-target-to-clause.f90
index bcb23f821e403..8198f44bcec18 100644
--- a/flang/test/Parser/OpenMP/declare-target-to-clause.f90
+++ b/flang/test/Parser/OpenMP/declare-target-to-clause.f90
@@ -9,11 +9,13 @@ module m
!UNPARSE: MODULE m
!UNPARSE: INTEGER x, y
-!UNPARSE: !$OMP DECLARE TARGET TO(x,y)
+!UNPARSE: !$OMP DECLARE TARGET TO(x,y)
!UNPARSE: END MODULE
-!PARSE-TREE: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpToClause
-!PARSE-TREE: | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
-!PARSE-TREE: | OmpObject -> Designator -> DataRef -> Name = 'y'
-!PARSE-TREE: | bool = 'true'
-
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
+!PARSE-TREE: | OmpClauseList -> OmpClause -> To -> OmpToClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | OmpObject -> Designator -> DataRef -> Name = 'y'
+!PARSE-TREE: | | bool = 'true'
+!PARSE-TREE: | Flags = None
diff --git a/flang/test/Parser/OpenMP/declare_target-device_type.f90 b/flang/test/Parser/OpenMP/declare_target-device_type.f90
index b6903614a628e..7df796288f4d4 100644
--- a/flang/test/Parser/OpenMP/declare_target-device_type.f90
+++ b/flang/test/Parser/OpenMP/declare_target-device_type.f90
@@ -3,35 +3,113 @@
subroutine openmp_declare_target
integer, save :: x, y
- !CHECK: !$omp declare target device_type(host) enter(x)
+!CHECK: !$omp declare target device_type(host) enter(x)
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host
+!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | Flags = None
!$omp declare target device_type(host) enter(x)
- !CHECK: !$omp declare target device_type(nohost) enter(x)
+
+!CHECK: !$omp declare target device_type(nohost) enter(x)
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost
+!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | Flags = None
!$omp declare target device_type(nohost) enter(x)
- !CHECK: !$omp declare target device_type(any) enter(x)
+
+!CHECK: !$omp declare target device_type(any) enter(x)
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any
+!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | Flags = None
!$omp declare target device_type(any) enter(x)
- !CHECK: !$omp declare target device_type(host) to(x)
+!CHECK: !$omp declare target device_type(host) to(x)
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host
+!PARSE-TREE: | OmpClause -> To -> OmpToClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | bool = 'true'
+!PARSE-TREE: | Flags = None
!$omp declare target device_type(host) to(x)
- !CHECK: !$omp declare target device_type(nohost) to(x)
+
+!CHECK: !$omp declare target device_type(nohost) to(x)
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost
+!PARSE-TREE: | OmpClause -> To -> OmpToClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | bool = 'true'
+!PARSE-TREE: | Flags = None
!$omp declare target device_type(nohost) to(x)
- !CHECK: !$omp declare target device_type(any) to(x)
+
+!CHECK: !$omp declare target device_type(any) to(x)
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any
+!PARSE-TREE: | OmpClause -> To -> OmpToClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | bool = 'true'
+!PARSE-TREE: | Flags = None
!$omp declare target device_type(any) to(x)
- !CHECK: !$omp declare target device_type(host) enter(y) to(x)
+!CHECK: !$omp declare target device_type(host) enter(y) to(x)
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host
+!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y'
+!PARSE-TREE: | OmpClause -> To -> OmpToClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | bool = 'true'
+!PARSE-TREE: | Flags = None
!$omp declare target device_type(host) enter(y) to(x)
- !CHECK: !$omp declare target device_type(nohost) enter(y) to(x)
+
+!CHECK: !$omp declare target device_type(nohost) enter(y) to(x)
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost
+!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y'
+!PARSE-TREE: | OmpClause -> To -> OmpToClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | bool = 'true'
+!PARSE-TREE: | Flags = None
!$omp declare target device_type(nohost) enter(y) to(x)
- !CHECK: !$omp declare target device_type(any) enter(y) to(x)
+
+!CHECK: !$omp declare target device_type(any) enter(y) to(x)
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
+!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any
+!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y'
+!PARSE-TREE: | OmpClause -> To -> OmpToClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | bool = 'true'
+!PARSE-TREE: | Flags = None
!$omp declare target device_type(any) enter(y) to(x)
+
integer :: a(1024), i
- !CHECK: do
+!CHECK: do
do i = 1, 1024
a(i) = i
- !CHECK: end do
+!CHECK: end do
end do
-!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct
-!PARSE-TREE: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host
-!PARSE-TREE: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost
-!PARSE-TREE: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any
END subroutine openmp_declare_target
diff --git a/flang/test/Parser/OpenMP/enter-automap-modifier.f90 b/flang/test/Parser/OpenMP/enter-automap-modifier.f90
index 1f361ca5c2f06..bc5b5eb3e7ef3 100644
--- a/flang/test/Parser/OpenMP/enter-automap-modifier.f90
+++ b/flang/test/Parser/OpenMP/enter-automap-modifier.f90
@@ -8,9 +8,12 @@ program automap
!UNPARSE: PROGRAM AUTOMAP
!UNPARSE: INTEGER x
-!UNPARSE: !$OMP DECLARE TARGET ENTER(AUTOMAP: x)
+!UNPARSE: !$OMP DECLARE_TARGET ENTER(AUTOMAP: x)
!UNPARSE: END PROGRAM
-!PARSE-TREE: OmpClauseList -> OmpClause -> Enter -> OmpEnterClause
-!PARSE-TREE-NEXT: | Modifier -> OmpAutomapModifier -> Value = Automap
-!PARSE-TREE-NEXT: | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Enter -> OmpEnterClause
+!PARSE-TREE: | | Modifier -> OmpAutomapModifier -> Value = Automap
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | Flags = None
diff --git a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90
index b72c5a2c1c086..f4cdd556bd4e5 100644
--- a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90
+++ b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90
@@ -124,12 +124,13 @@ subroutine f04
end
!UNPARSE: SUBROUTINE f04
-!UNPARSE: !$OMP DECLARE TARGET
+!UNPARSE: !$OMP DECLARE_TARGET
!UNPARSE: END SUBROUTINE
-!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct
-!PARSE-TREE: | Verbatim
-!PARSE-TREE: | OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList ->
+!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclareTargetConstruct -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
+!PARSE-TREE: | OmpClauseList ->
+!PARSE-TREE: | Flags = None
subroutine f05
implicit none
diff --git a/flang/test/Semantics/OpenMP/blank-common-block.f90 b/flang/test/Semantics/OpenMP/blank-common-block.f90
index 4a217fced0ff7..e410f0c56d1c0 100644
--- a/flang/test/Semantics/OpenMP/blank-common-block.f90
+++ b/flang/test/Semantics/OpenMP/blank-common-block.f90
@@ -4,6 +4,7 @@ module m
integer :: a
common // a
!ERROR: Blank common blocks are not allowed as directive or clause arguments
+ !ERROR: An argument to the DECLARE TARGET directive should be an extended-list-item
!$omp declare_target(//)
!ERROR: Blank common blocks are not allowed as directive or clause arguments
!$omp threadprivate(//)
diff --git a/flang/test/Semantics/OpenMP/declare-target-function-name-with-symbols.f90 b/flang/test/Semantics/OpenMP/declare-target-function-name-with-symbols.f90
index 9a0acdb3dd100..3439e6fd13981 100644
--- a/flang/test/Semantics/OpenMP/declare-target-function-name-with-symbols.f90
+++ b/flang/test/Semantics/OpenMP/declare-target-function-name-with-symbols.f90
@@ -19,7 +19,7 @@ end module test
!CHECK: !DEF: /test/ex/b ObjectEntity INTEGER(4)
!CHECK: !DEF: /test/ex/c ObjectEntity INTEGER(4)
!CHECK: function ex(a, b, c)
-!CHECK: !$omp declare target (ex)
+!CHECK: !$omp declare target(ex)
!CHECK: !REF: /test/ex/a
!CHECK: !REF: /test/ex/b
!CHECK: !REF: /test/ex/c
>From 0f8c8248ca815c1de700e93d7df1d753c10d215e Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 24 Sep 2025 12:58:20 -0500
Subject: [PATCH 08/11] Remove unused AST classes
---
flang/include/flang/Parser/dump-parse-tree.h | 3 ---
flang/include/flang/Parser/parse-tree.h | 18 ------------------
flang/lib/Parser/unparse.cpp | 3 ---
3 files changed, 24 deletions(-)
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 7540d38baa584..fadca0a3876f4 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -538,9 +538,6 @@ class ParseTreeDumper {
NODE_ENUM(OmpCloseModifier, Value)
NODE(parser, OmpContainsClause)
NODE(parser, OmpContextSelectorSpecification)
- NODE(parser, OmpDeclareTargetSpecifier)
- NODE(parser, OmpDeclareTargetWithClause)
- NODE(parser, OmpDeclareTargetWithList)
NODE(parser, OmpDeclareVariantDirective)
NODE(parser, OmpDefaultClause)
NODE_ENUM(OmpDefaultClause, DataSharingAttribute)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index e7593d9875097..486be8b60ff8c 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4943,24 +4943,6 @@ struct OmpDeclareVariantDirective {
CharBlock source;
};
-// 2.10.6 declare-target -> DECLARE TARGET (extended-list) |
-// DECLARE TARGET [declare-target-clause[ [,]
-// declare-target-clause]...]
-struct OmpDeclareTargetWithList {
- WRAPPER_CLASS_BOILERPLATE(OmpDeclareTargetWithList, OmpObjectList);
- CharBlock source;
-};
-
-struct OmpDeclareTargetWithClause {
- WRAPPER_CLASS_BOILERPLATE(OmpDeclareTargetWithClause, OmpClauseList);
- CharBlock source;
-};
-
-struct OmpDeclareTargetSpecifier {
- UNION_CLASS_BOILERPLATE(OmpDeclareTargetSpecifier);
- std::variant<OmpDeclareTargetWithList, OmpDeclareTargetWithClause> u;
-};
-
// Ref: [4.5:110-113], [5.0:180-185], [5.1:210-216], [5.2:206-207],
// [6.0:346-348]
//
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index be166bcb743ba..a2b0b9ef3196c 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2492,9 +2492,6 @@ class UnparseVisitor {
void Unparse(const OpenMPCriticalConstruct &x) {
Unparse(static_cast<const OmpBlockConstruct &>(x));
}
- void Unparse(const OmpDeclareTargetWithList &x) {
- Put("("), Walk(x.v), Put(")");
- }
void Unparse(const OmpInitializerProc &x) {
Walk(std::get<ProcedureDesignator>(x.t));
Put("(");
>From f5eb99ffbc20b6d787b62d620471e556cf71ab57 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 24 Sep 2025 14:12:44 -0500
Subject: [PATCH 09/11] Fix example
---
flang/examples/FeatureList/FeatureList.cpp | 3 ---
1 file changed, 3 deletions(-)
diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp
index 569d2b2307f36..daa012e3eb08b 100644
--- a/flang/examples/FeatureList/FeatureList.cpp
+++ b/flang/examples/FeatureList/FeatureList.cpp
@@ -451,9 +451,6 @@ struct NodeVisitor {
READ_FEATURE(OmpBlockConstruct)
READ_FEATURE(OmpClause)
READ_FEATURE(OmpClauseList)
- READ_FEATURE(OmpDeclareTargetSpecifier)
- READ_FEATURE(OmpDeclareTargetWithClause)
- READ_FEATURE(OmpDeclareTargetWithList)
READ_FEATURE(OmpDefaultClause)
READ_FEATURE(OmpDefaultClause::DataSharingAttribute)
READ_FEATURE(OmpDefaultmapClause)
>From eb12400ffc25b62205183f3102a1e0afdb785510 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 24 Sep 2025 14:38:40 -0500
Subject: [PATCH 10/11] [flang][OpenMP] Use OmpDirectiveSpecification in
ASSUMES
---
flang/include/flang/Parser/openmp-utils.h | 2 --
flang/include/flang/Parser/parse-tree.h | 4 ++--
flang/lib/Parser/openmp-parsers.cpp | 6 ++++--
flang/lib/Parser/unparse.cpp | 4 ++--
flang/lib/Semantics/check-omp-structure.cpp | 4 ----
flang/test/Parser/OpenMP/assumption.f90 | 8 +++++---
6 files changed, 13 insertions(+), 15 deletions(-)
diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h
index bf54f970a7d3a..77c31b939e522 100644
--- a/flang/include/flang/Parser/openmp-utils.h
+++ b/flang/include/flang/Parser/openmp-utils.h
@@ -39,7 +39,6 @@ struct ConstructId {
}
MAKE_CONSTR_ID(OpenMPDeclarativeAllocate, D::OMPD_allocate);
-MAKE_CONSTR_ID(OpenMPDeclarativeAssumes, D::OMPD_assumes);
MAKE_CONSTR_ID(OpenMPDeclareReductionConstruct, D::OMPD_declare_reduction);
MAKE_CONSTR_ID(OpenMPExecutableAllocate, D::OMPD_allocate);
MAKE_CONSTR_ID(OpenMPRequiresConstruct, D::OMPD_requires);
@@ -94,7 +93,6 @@ struct DirectiveNameScope {
if constexpr (std::is_base_of_v<OmpBlockConstruct, T>) {
return std::get<OmpBeginDirective>(x.t).DirName();
} else if constexpr (std::is_same_v<T, OpenMPDeclarativeAllocate> ||
- std::is_same_v<T, OpenMPDeclarativeAssumes> ||
std::is_same_v<T, OpenMPDeclareReductionConstruct> ||
std::is_same_v<T, OpenMPExecutableAllocate> ||
std::is_same_v<T, OpenMPRequiresConstruct>) {
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 486be8b60ff8c..bd55166eb9f80 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4877,8 +4877,8 @@ struct OpenMPUtilityConstruct {
// ASSUMES absent-clause | contains-clause | holds-clause | no-openmp-clause |
// no-openmp-routines-clause | no-parallelism-clause
struct OpenMPDeclarativeAssumes {
- TUPLE_CLASS_BOILERPLATE(OpenMPDeclarativeAssumes);
- std::tuple<Verbatim, OmpClauseList> t;
+ WRAPPER_CLASS_BOILERPLATE(
+ OpenMPDeclarativeAssumes, OmpDirectiveSpecification);
CharBlock source;
};
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index bd080386c0aea..12e89e8c35456 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1852,8 +1852,10 @@ TYPE_PARSER(
lookAhead(endOmpLine / !statement(allocateStmt)))
// Assumes Construct
-TYPE_PARSER(sourced(construct<OpenMPDeclarativeAssumes>(
- verbatim("ASSUMES"_tok), Parser<OmpClauseList>{})))
+TYPE_PARSER(construct<OpenMPDeclarativeAssumes>(
+ predicated(OmpDirectiveNameParser{},
+ IsDirective(llvm::omp::Directive::OMPD_assumes)) >=
+ Parser<OmpDirectiveSpecification>{}))
// Declarative constructs
TYPE_PARSER(
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index a2b0b9ef3196c..9812a656092ac 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2558,8 +2558,8 @@ class UnparseVisitor {
void Unparse(const OpenMPDeclarativeAssumes &x) {
BeginOpenMP();
- Word("!$OMP ASSUMES ");
- Walk(std::get<OmpClauseList>(x.t));
+ Word("!$OMP ");
+ Walk(x.v);
Put("\n");
EndOpenMP();
}
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 05ff541657b1a..6538e0b794791 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -620,10 +620,6 @@ template <typename Checker> struct DirectiveSpellingVisitor {
checker_(GetDirName(x.t).source, Directive::OMPD_allocators);
return false;
}
- bool Pre(const parser::OpenMPDeclarativeAssumes &x) {
- checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_assumes);
- return false;
- }
bool Pre(const parser::OpenMPGroupprivate &x) {
checker_(x.v.DirName().source, Directive::OMPD_groupprivate);
return false;
diff --git a/flang/test/Parser/OpenMP/assumption.f90 b/flang/test/Parser/OpenMP/assumption.f90
index 0f333f99f9085..86cbad9e42f78 100644
--- a/flang/test/Parser/OpenMP/assumption.f90
+++ b/flang/test/Parser/OpenMP/assumption.f90
@@ -141,9 +141,11 @@ program p
end program p
!UNPARSE: PROGRAM p
-!UNPARSE: !$OMP ASSUMES NO_OPENMP
+!UNPARSE: !$OMP ASSUMES NO_OPENMP
!UNPARSE: END PROGRAM p
-!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclarativeAssumes
-!PARSE-TREE: | Verbatim
+!PARSE-TREE: OpenMPDeclarativeConstruct -> OpenMPDeclarativeAssumes -> OmpDirectiveSpecification
+!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = assumes
!PARSE-TREE: | OmpClauseList -> OmpClause -> NoOpenmp
+!PARSE-TREE: | Flags = None
+!PARSE-TREE: ImplicitPart ->
>From 7f1df5bd47499d75180ba2c8509730e4bba60956 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 24 Sep 2025 14:49:35 -0500
Subject: [PATCH 11/11] Forgot "sourced"
---
flang/lib/Parser/openmp-parsers.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 12e89e8c35456..5fd3c1768a17f 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1852,10 +1852,10 @@ TYPE_PARSER(
lookAhead(endOmpLine / !statement(allocateStmt)))
// Assumes Construct
-TYPE_PARSER(construct<OpenMPDeclarativeAssumes>(
+TYPE_PARSER(sourced(construct<OpenMPDeclarativeAssumes>(
predicated(OmpDirectiveNameParser{},
IsDirective(llvm::omp::Directive::OMPD_assumes)) >=
- Parser<OmpDirectiveSpecification>{}))
+ Parser<OmpDirectiveSpecification>{})))
// Declarative constructs
TYPE_PARSER(
More information about the flang-commits
mailing list