[flang-commits] [flang] [flang][OpenMP] Use OmpDirectiveSpecification in DECLARE_VARIANT (PR #160371)
Krzysztof Parzyszek via flang-commits
flang-commits at lists.llvm.org
Thu Sep 25 06:55:57 PDT 2025
https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/160371
>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 1/4] [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 2/4] [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 3/4] 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 5ee1124c719d4dee6859911ea4f584a678e81db9 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Thu, 25 Sep 2025 08:50:38 -0500
Subject: [PATCH 4/4] Make "name is implicitly declared" be a note
---
flang/lib/Semantics/check-omp-structure.cpp | 14 +++++++-------
flang/test/Semantics/OpenMP/declare-variant.f90 | 2 --
2 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 9b1932255bd05..a70668e4bfe9c 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1383,13 +1383,13 @@ void OmpStructureChecker::Enter(const parser::OmpDeclareVariantDirective &x) {
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());
+ auto &msg{context_.Say(source,
+ "The name '%s' should refer to a procedure"_err_en_US,
+ sym->name())};
+ if (sym->test(Symbol::Flag::Implicit)) {
+ msg.Attach(source,
+ "The name '%s' has been implicitly declared"_en_US, sym->name());
+ }
}
} else {
InvalidArgument(source);
diff --git a/flang/test/Semantics/OpenMP/declare-variant.f90 b/flang/test/Semantics/OpenMP/declare-variant.f90
index 59b8bda3f2a99..6fc94a4fb837f 100644
--- a/flang/test/Semantics/OpenMP/declare-variant.f90
+++ b/flang/test/Semantics/OpenMP/declare-variant.f90
@@ -2,10 +2,8 @@
subroutine sub0
!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: 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
More information about the flang-commits
mailing list