[llvm-branch-commits] [flang] [flang] Add traits to more AST nodes (PR #175566)
Krzysztof Parzyszek via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Jan 12 07:51:45 PST 2026
https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/175566
>From f7b0374e8dce1abc307d1a3aca74f1be33ad6811 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Fri, 9 Jan 2026 15:50:38 -0600
Subject: [PATCH 1/3] [flang] Add traits to more AST nodes
Follow-up to PR175211.
There are still a few AST nodes that don't have any of the standard
traits (Wrapper/Tuple/etc). Because of that they require special
handling in the parse tree visitor.
Convert a subset of these nodes to the typical format, and remove the
special cases from the parse tree visitor.
---
.../include/flang/Parser/parse-tree-visitor.h | 110 ------------------
flang/include/flang/Parser/parse-tree.h | 53 +++------
flang/lib/Lower/Bridge.cpp | 3 +-
flang/lib/Lower/PFTBuilder.cpp | 6 +-
flang/lib/Parser/parse-tree.cpp | 16 +--
flang/lib/Parser/unparse.cpp | 38 +++---
flang/lib/Semantics/check-do-forall.cpp | 4 +-
flang/lib/Semantics/expression.cpp | 20 ++--
flang/lib/Semantics/program-tree.cpp | 5 +-
flang/lib/Semantics/resolve-names.cpp | 72 ++++++++----
flang/lib/Semantics/tools.cpp | 6 +-
11 files changed, 121 insertions(+), 212 deletions(-)
diff --git a/flang/include/flang/Parser/parse-tree-visitor.h b/flang/include/flang/Parser/parse-tree-visitor.h
index 61470f8c30604..191e74ee89f1c 100644
--- a/flang/include/flang/Parser/parse-tree-visitor.h
+++ b/flang/include/flang/Parser/parse-tree-visitor.h
@@ -433,38 +433,6 @@ struct ParseTreeVisitorLookupScope {
x, mutator);
}
- template <typename V> static void Walk(const CallStmt &x, V &visitor) {
- if (visitor.Pre(x)) {
- Walk(x.source, visitor);
- Walk(x.call, visitor);
- Walk(x.chevrons, visitor);
- visitor.Post(x);
- }
- }
- template <typename M> static void Walk(CallStmt &x, M &mutator) {
- if (mutator.Pre(x)) {
- Walk(x.source, mutator);
- Walk(x.call, mutator);
- Walk(x.chevrons, mutator);
- mutator.Post(x);
- }
- }
- template <typename V> static void Walk(const PartRef &x, V &visitor) {
- if (visitor.Pre(x)) {
- Walk(x.name, visitor);
- Walk(x.subscripts, visitor);
- Walk(x.imageSelector, visitor);
- visitor.Post(x);
- }
- }
- template <typename M> static void Walk(PartRef &x, M &mutator) {
- if (mutator.Pre(x)) {
- Walk(x.name, mutator);
- Walk(x.subscripts, mutator);
- Walk(x.imageSelector, mutator);
- mutator.Post(x);
- }
- }
template <typename V> static void Walk(const ReadStmt &x, V &visitor) {
if (visitor.Pre(x)) {
Walk(x.iounit, visitor);
@@ -484,35 +452,6 @@ struct ParseTreeVisitorLookupScope {
}
}
template <typename V>
- static void Walk(const RealLiteralConstant &x, V &visitor) {
- if (visitor.Pre(x)) {
- Walk(x.real, visitor);
- Walk(x.kind, visitor);
- visitor.Post(x);
- }
- }
- template <typename M> static void Walk(RealLiteralConstant &x, M &mutator) {
- if (mutator.Pre(x)) {
- Walk(x.real, mutator);
- Walk(x.kind, mutator);
- mutator.Post(x);
- }
- }
- template <typename V>
- static void Walk(const RealLiteralConstant::Real &x, V &visitor) {
- if (visitor.Pre(x)) {
- Walk(x.source, visitor);
- visitor.Post(x);
- }
- }
- template <typename M>
- static void Walk(RealLiteralConstant::Real &x, M &mutator) {
- if (mutator.Pre(x)) {
- Walk(x.source, mutator);
- mutator.Post(x);
- }
- }
- template <typename V>
static void Walk(const StructureComponent &x, V &visitor) {
if (visitor.Pre(x)) {
Walk(x.base, visitor);
@@ -527,55 +466,6 @@ struct ParseTreeVisitorLookupScope {
mutator.Post(x);
}
}
- template <typename V> static void Walk(const Suffix &x, V &visitor) {
- if (visitor.Pre(x)) {
- Walk(x.binding, visitor);
- Walk(x.resultName, visitor);
- visitor.Post(x);
- }
- }
- template <typename M> static void Walk(Suffix &x, M &mutator) {
- if (mutator.Pre(x)) {
- Walk(x.binding, mutator);
- Walk(x.resultName, mutator);
- mutator.Post(x);
- }
- }
- template <typename V>
- static void Walk(const TypeBoundProcedureStmt::WithInterface &x, V &visitor) {
- if (visitor.Pre(x)) {
- Walk(x.interfaceName, visitor);
- Walk(x.attributes, visitor);
- Walk(x.bindingNames, visitor);
- visitor.Post(x);
- }
- }
- template <typename M>
- static void Walk(TypeBoundProcedureStmt::WithInterface &x, M &mutator) {
- if (mutator.Pre(x)) {
- Walk(x.interfaceName, mutator);
- Walk(x.attributes, mutator);
- Walk(x.bindingNames, mutator);
- mutator.Post(x);
- }
- }
- template <typename V>
- static void Walk(
- const TypeBoundProcedureStmt::WithoutInterface &x, V &visitor) {
- if (visitor.Pre(x)) {
- Walk(x.attributes, visitor);
- Walk(x.declarations, visitor);
- visitor.Post(x);
- }
- }
- template <typename M>
- static void Walk(TypeBoundProcedureStmt::WithoutInterface &x, M &mutator) {
- if (mutator.Pre(x)) {
- Walk(x.attributes, mutator);
- Walk(x.declarations, mutator);
- mutator.Post(x);
- }
- }
template <typename V> static void Walk(const UseStmt &x, V &visitor) {
if (visitor.Pre(x)) {
Walk(x.nature, visitor);
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 37c0f699361eb..1d72c1cb1c80e 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -807,16 +807,14 @@ enum class Sign { Positive, Negative };
// R715 significand -> digit-string . [digit-string] | . digit-string
// R717 exponent -> signed-digit-string
struct RealLiteralConstant {
- BOILERPLATE(RealLiteralConstant);
+ TUPLE_CLASS_BOILERPLATE(RealLiteralConstant);
struct Real {
+ using EmptyTrait = std::true_type;
COPY_AND_ASSIGN_BOILERPLATE(Real);
Real() {}
CharBlock source;
};
- RealLiteralConstant(Real &&r, std::optional<KindParam> &&k)
- : real{std::move(r)}, kind{std::move(k)} {}
- Real real;
- std::optional<KindParam> kind;
+ std::tuple<Real, std::optional<KindParam>> t;
};
// R713 signed-real-literal-constant -> [sign] real-literal-constant
@@ -1133,21 +1131,12 @@ struct TypeBoundProcDecl {
struct TypeBoundProcedureStmt {
UNION_CLASS_BOILERPLATE(TypeBoundProcedureStmt);
struct WithoutInterface {
- BOILERPLATE(WithoutInterface);
- WithoutInterface(
- std::list<BindAttr> &&as, std::list<TypeBoundProcDecl> &&ds)
- : attributes(std::move(as)), declarations(std::move(ds)) {}
- std::list<BindAttr> attributes;
- std::list<TypeBoundProcDecl> declarations;
+ TUPLE_CLASS_BOILERPLATE(WithoutInterface);
+ std::tuple<std::list<BindAttr>, std::list<TypeBoundProcDecl>> t;
};
struct WithInterface {
- BOILERPLATE(WithInterface);
- WithInterface(Name &&n, std::list<BindAttr> &&as, std::list<Name> &&bs)
- : interfaceName(std::move(n)), attributes(std::move(as)),
- bindingNames(std::move(bs)) {}
- Name interfaceName;
- std::list<BindAttr> attributes;
- std::list<Name> bindingNames;
+ TUPLE_CLASS_BOILERPLATE(WithInterface);
+ std::tuple<Name, std::list<BindAttr>, std::list<Name>> t;
};
std::variant<WithoutInterface, WithInterface> u;
};
@@ -1794,14 +1783,8 @@ struct Expr {
// R912 part-ref -> part-name [( section-subscript-list )] [image-selector]
struct PartRef {
- BOILERPLATE(PartRef);
- PartRef(Name &&n, std::list<SectionSubscript> &&ss,
- std::optional<ImageSelector> &&is)
- : name{std::move(n)}, subscripts(std::move(ss)),
- imageSelector{std::move(is)} {}
- Name name;
- std::list<SectionSubscript> subscripts;
- std::optional<ImageSelector> imageSelector;
+ TUPLE_CLASS_BOILERPLATE(PartRef);
+ std::tuple<Name, std::list<SectionSubscript>, std::optional<ImageSelector>> t;
};
// R911 data-ref -> part-ref [% part-ref]...
@@ -3121,13 +3104,10 @@ struct PrefixSpec {
// proc-language-binding-spec [RESULT ( result-name )] |
// RESULT ( result-name ) [proc-language-binding-spec]
struct Suffix {
- BOILERPLATE(Suffix);
+ TUPLE_CLASS_BOILERPLATE(Suffix);
Suffix(LanguageBindingSpec &&lbs, std::optional<Name> &&rn)
- : binding(std::move(lbs)), resultName(std::move(rn)) {}
- Suffix(Name &&rn, std::optional<LanguageBindingSpec> &&lbs)
- : binding(std::move(lbs)), resultName(std::move(rn)) {}
- std::optional<LanguageBindingSpec> binding;
- std::optional<Name> resultName;
+ : t(std::move(rn), std::move(lbs)) {}
+ std::tuple<std::optional<Name>, std::optional<LanguageBindingSpec>> t;
};
// R1530 function-stmt ->
@@ -3262,7 +3242,7 @@ struct FunctionReference {
// (CUDA) chevrons -> <<< * | scalar-expr, scalar-expr [,
// scalar-expr [, scalar-int-expr ] ] >>>
struct CallStmt {
- BOILERPLATE(CallStmt);
+ TUPLE_CLASS_BOILERPLATE(CallStmt);
WRAPPER_CLASS(StarOrExpr, std::optional<ScalarExpr>);
struct Chevrons {
TUPLE_CLASS_BOILERPLATE(Chevrons);
@@ -3271,10 +3251,9 @@ struct CallStmt {
t;
};
explicit CallStmt(ProcedureDesignator &&pd, std::optional<Chevrons> &&ch,
- std::list<ActualArgSpec> &&args)
- : call{std::move(pd), std::move(args)}, chevrons{std::move(ch)} {}
- Call call;
- std::optional<Chevrons> chevrons;
+ std::list<ActualArgSpec> &&args) :
+ CallStmt(Call{std::move(pd), std::move(args)}, std::move(ch)) {}
+ std::tuple<Call, std::optional<Chevrons>> t;
CharBlock source;
mutable TypedCall typedCall; // filled by semantics
};
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 9224bc2be1028..609050511f6c9 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2048,8 +2048,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
llvm::SmallVector<int64_t> indexList;
llvm::SmallVector<Fortran::parser::Label> labelList;
int64_t index = 0;
+ const auto &call{std::get<Fortran::parser::Call>(stmt.t)};
for (const Fortran::parser::ActualArgSpec &arg :
- std::get<std::list<Fortran::parser::ActualArgSpec>>(stmt.call.t)) {
+ std::get<std::list<Fortran::parser::ActualArgSpec>>(call.t)) {
const auto &actual = std::get<Fortran::parser::ActualArg>(arg.t);
if (const auto *altReturn =
std::get_if<Fortran::parser::AltReturnSpec>(&actual.u)) {
diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp
index 2dc7032b85f42..1a7fb41f3273c 100644
--- a/flang/lib/Lower/PFTBuilder.cpp
+++ b/flang/lib/Lower/PFTBuilder.cpp
@@ -142,8 +142,9 @@ class PFTBuilder {
/// - 17.4p5 (The rounding modes)
/// - 17.6p1 (Halting)
void checkForFPEnvironmentCalls(const parser::CallStmt &callStmt) {
+ const auto &call = std::get<parser::Call>(callStmt.t);
const auto *callName = std::get_if<parser::Name>(
- &std::get<parser::ProcedureDesignator>(callStmt.call.t).u);
+ &std::get<parser::ProcedureDesignator>(call.t).u);
if (!callName)
return;
const Fortran::semantics::Symbol &procSym = callName->symbol->GetUltimate();
@@ -919,8 +920,9 @@ class PFTBuilder {
// Action statements (except IO statements)
[&](const parser::CallStmt &s) {
// Look for alternate return specifiers.
+ const auto &call = std::get<parser::Call>(s.t);
const auto &args =
- std::get<std::list<parser::ActualArgSpec>>(s.call.t);
+ std::get<std::list<parser::ActualArgSpec>>(call.t);
for (const auto &arg : args) {
const auto &actual = std::get<parser::ActualArg>(arg.t);
if (const auto *altReturn =
diff --git a/flang/lib/Parser/parse-tree.cpp b/flang/lib/Parser/parse-tree.cpp
index dae1912afa99e..819470a43b0c8 100644
--- a/flang/lib/Parser/parse-tree.cpp
+++ b/flang/lib/Parser/parse-tree.cpp
@@ -50,20 +50,22 @@ bool Designator::EndsInBareName() const {
}
// R911 data-ref -> part-ref [% part-ref]...
-DataRef::DataRef(std::list<PartRef> &&prl) : u{std::move(prl.front().name)} {
+DataRef::DataRef(std::list<PartRef> &&prl)
+ : u{std::move(std::get<Name>(prl.front().t))} {
for (bool first{true}; !prl.empty(); first = false, prl.pop_front()) {
- PartRef &pr{prl.front()};
+ auto &&[name, subscripts, imageSelector]{prl.front().t};
+ // PartRef &pr{prl.front()};
if (!first) {
u = common::Indirection<StructureComponent>::Make(
- std::move(*this), std::move(pr.name));
+ std::move(*this), std::move(name));
}
- if (!pr.subscripts.empty()) {
+ if (!subscripts.empty()) {
u = common::Indirection<ArrayElement>::Make(
- std::move(*this), std::move(pr.subscripts));
+ std::move(*this), std::move(subscripts));
}
- if (pr.imageSelector) {
+ if (imageSelector) {
u = common::Indirection<CoindexedNamedObject>::Make(
- std::move(*this), std::move(*pr.imageSelector));
+ std::move(*this), std::move(*imageSelector));
}
}
}
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 9b31454537df5..0465b67aed08d 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -198,7 +198,8 @@ class UnparseVisitor {
Put(x == Sign::Negative ? '-' : '+');
}
void Unparse(const RealLiteralConstant &x) { // R714, R715
- Put(x.real.source.ToString()), Walk("_", x.kind);
+ const auto &[real, kind]{x.t};
+ Put(real.source.ToString()), Walk("_", kind);
}
void Unparse(const ComplexLiteralConstant &x) { // R718 - R720
Put('('), Walk(x.t, ","), Put(')');
@@ -371,13 +372,15 @@ class UnparseVisitor {
Word("PRIVATE");
}
void Unparse(const TypeBoundProcedureStmt::WithoutInterface &x) { // R749
- Word("PROCEDURE"), Walk(", ", x.attributes, ", ");
- Put(" :: "), Walk(x.declarations, ", ");
+ const auto &[attributes, declarations]{x.t};
+ Word("PROCEDURE"), Walk(", ", attributes, ", ");
+ Put(" :: "), Walk(declarations, ", ");
}
void Unparse(const TypeBoundProcedureStmt::WithInterface &x) {
- Word("PROCEDURE("), Walk(x.interfaceName), Put("), ");
- Walk(x.attributes);
- Put(" :: "), Walk(x.bindingNames, ", ");
+ const auto &[interfaceName, attributes, bindingNames]{x.t};
+ Word("PROCEDURE("), Walk(interfaceName), Put("), ");
+ Walk(attributes);
+ Put(" :: "), Walk(bindingNames, ", ");
}
void Unparse(const TypeBoundProcDecl &x) { // R750
Walk(std::get<Name>(x.t));
@@ -789,9 +792,10 @@ class UnparseVisitor {
Walk(x.t, ":");
}
void Unparse(const PartRef &x) { // R912
- Walk(x.name);
- Walk("(", x.subscripts, ",", ")");
- Walk(x.imageSelector);
+ const auto &[name, subscripts, imageSelector]{x.t};
+ Walk(name);
+ Walk("(", subscripts, ",", ")");
+ Walk(imageSelector);
}
void Unparse(const StructureComponent &x) { // R913
Walk(x.base);
@@ -1692,15 +1696,16 @@ class UnparseVisitor {
Put('('), Walk(std::get<std::list<ActualArgSpec>>(x.v.t), ", "), Put(')');
}
void Unparse(const CallStmt &x) { // R1521
+ const auto &[call, chevrons]{x.t};
if (asFortran_ && x.typedCall.get()) {
Put(' ');
asFortran_->call(out_, *x.typedCall);
Put('\n');
} else {
- const auto &pd{std::get<ProcedureDesignator>(x.call.t)};
+ const auto &pd{std::get<ProcedureDesignator>(call.t)};
Word("CALL "), Walk(pd);
- Walk("<<<", x.chevrons, ">>>");
- const auto &args{std::get<std::list<ActualArgSpec>>(x.call.t)};
+ Walk("<<<", chevrons, ">>>");
+ const auto &args{std::get<std::list<ActualArgSpec>>(call.t)};
if (args.empty()) {
if (std::holds_alternative<ProcComponentRef>(pd.u)) {
Put("()"); // pgf90 crashes on CALL to tbp without parentheses
@@ -1745,11 +1750,12 @@ class UnparseVisitor {
Walk(" ", std::get<std::optional<Suffix>>(x.t)), Indent();
}
void Unparse(const Suffix &x) { // R1532
- if (x.resultName) {
- Word("RESULT("), Walk(x.resultName), Put(')');
- Walk(" ", x.binding);
+ const auto &[resultName, binding]{x.t};
+ if (resultName) {
+ Word("RESULT("), Walk(resultName), Put(')');
+ Walk(" ", binding);
} else {
- Walk(x.binding);
+ Walk(binding);
}
}
void Unparse(const EndFunctionStmt &x) { // R1533
diff --git a/flang/lib/Semantics/check-do-forall.cpp b/flang/lib/Semantics/check-do-forall.cpp
index 8a473406b8200..c90479d9e352e 100644
--- a/flang/lib/Semantics/check-do-forall.cpp
+++ b/flang/lib/Semantics/check-do-forall.cpp
@@ -1101,8 +1101,8 @@ static void CheckIfArgIsDoVar(const evaluate::ActualArgument &arg,
// messages.
void DoForallChecker::Leave(const parser::CallStmt &callStmt) {
if (const auto &typedCall{callStmt.typedCall}) {
- const auto &parsedArgs{
- std::get<std::list<parser::ActualArgSpec>>(callStmt.call.t)};
+ const auto &call{std::get<parser::Call>(callStmt.t)};
+ const auto &parsedArgs{std::get<std::list<parser::ActualArgSpec>>(call.t)};
auto parsedArgIter{parsedArgs.begin()};
const evaluate::ActualArguments &checkedArgs{typedCall->arguments()};
for (const auto &checkedOptionalArg : checkedArgs) {
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index b3643e0d35d5f..ece5d23bb59d2 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -869,19 +869,20 @@ struct RealTypeVisitor {
// Reads a real literal constant and encodes it with the right kind.
MaybeExpr ExpressionAnalyzer::Analyze(const parser::RealLiteralConstant &x) {
+ const auto &[xreal, xkind](x.t);
// Use a local message context around the real literal for better
// provenance on any messages.
- auto restorer{GetContextualMessages().SetLocation(x.real.source)};
+ auto restorer{GetContextualMessages().SetLocation(xreal.source)};
// If a kind parameter appears, it defines the kind of the literal and the
// letter used in an exponent part must be 'E' (e.g., the 'E' in
// "6.02214E+23"). In the absence of an explicit kind parameter, any
// exponent letter determines the kind. Otherwise, defaults apply.
auto &defaults{context_.defaultKinds()};
int defaultKind{defaults.GetDefaultKind(TypeCategory::Real)};
- const char *end{x.real.source.end()};
+ const char *end{xreal.source.end()};
char expoLetter{' '};
std::optional<int> letterKind;
- for (const char *p{x.real.source.begin()}; p < end; ++p) {
+ for (const char *p{xreal.source.begin()}; p < end; ++p) {
if (parser::IsLetter(*p)) {
expoLetter = *p;
switch (expoLetter) {
@@ -905,20 +906,20 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::RealLiteralConstant &x) {
}
// C716 requires 'E' as an exponent.
// Extension: allow exponent-letter matching the kind-param.
- auto kind{AnalyzeKindParam(x.kind, defaultKind)};
+ auto kind{AnalyzeKindParam(xkind, defaultKind)};
if (letterKind && expoLetter != 'e') {
if (kind != *letterKind) {
Warn(common::LanguageFeature::ExponentMatchingKindParam,
"Explicit kind parameter on real constant disagrees with exponent letter '%c'"_warn_en_US,
expoLetter);
- } else if (x.kind) {
+ } else if (xkind) {
Warn(common::LanguageFeature::ExponentMatchingKindParam,
"Explicit kind parameter together with non-'E' exponent letter is not standard"_port_en_US);
}
}
- bool isDefaultKind{!x.kind && letterKind.value_or('e') == 'e'};
+ bool isDefaultKind{!xkind && letterKind.value_or('e') == 'e'};
auto result{common::SearchTypes(RealTypeVisitor{
- kind, x.real.source, GetFoldingContext(), isDefaultKind})};
+ kind, xreal.source, GetFoldingContext(), isDefaultKind})};
if (!result) { // C717
Say("Unsupported REAL(KIND=%d)"_err_en_US, kind);
}
@@ -3404,7 +3405,8 @@ std::optional<Chevrons> ExpressionAnalyzer::AnalyzeChevrons(
which);
return false;
}};
- if (const auto &chevrons{call.chevrons}) {
+ if (const auto &chevrons{
+ std::get<std::optional<parser::CallStmt::Chevrons>>(call.t)}) {
auto &starOrExpr{std::get<0>(chevrons->t)};
if (starOrExpr.v) {
if (auto expr{Analyze(*starOrExpr.v)};
@@ -3504,7 +3506,7 @@ static bool HasAlternateReturns(const evaluate::ActualArguments &args) {
}
void ExpressionAnalyzer::Analyze(const parser::CallStmt &callStmt) {
- const parser::Call &call{callStmt.call};
+ const auto &call{std::get<parser::Call>(callStmt.t)};
auto restorer{GetContextualMessages().SetLocation(callStmt.source)};
ArgumentAnalyzer analyzer{*this, callStmt.source, true /* isProcedureCall */};
const auto &actualArgList{std::get<std::list<parser::ActualArgSpec>>(call.t)};
diff --git a/flang/lib/Semantics/program-tree.cpp b/flang/lib/Semantics/program-tree.cpp
index 86085e78803a2..89517982de67c 100644
--- a/flang/lib/Semantics/program-tree.cpp
+++ b/flang/lib/Semantics/program-tree.cpp
@@ -161,8 +161,9 @@ std::optional<ProgramTree> ProgramTree::Build(
const parser::LanguageBindingSpec *bindingSpec{};
if (const auto &suffix{
std::get<std::optional<parser::Suffix>>(stmt.statement.t)}) {
- if (suffix->binding) {
- bindingSpec = &*suffix->binding;
+ if (const auto &binding{
+ std::get<std::optional<parser::LanguageBindingSpec>>(suffix->t)}) {
+ bindingSpec = &*binding;
}
}
return BuildSubprogramTree(name, context, x)
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 527be8645ff81..04d734781265e 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -4660,17 +4660,17 @@ bool SubprogramVisitor::HandleStmtFunction(const parser::StmtFunctionStmt &x) {
}
bool SubprogramVisitor::Pre(const parser::Suffix &suffix) {
- if (suffix.resultName) {
+ if (const auto &resultName{std::get<std::optional<parser::Name>>(suffix.t)}) {
if (IsFunction(currScope())) {
if (FuncResultStack::FuncInfo * info{funcResultStack().Top()}) {
if (info->inFunctionStmt) {
- info->resultName = &suffix.resultName.value();
+ info->resultName = &resultName.value();
} else {
// will check the result name in Post(EntryStmt)
}
}
} else {
- Message &msg{Say(*suffix.resultName,
+ Message &msg{Say(*resultName,
"RESULT(%s) may appear only in a function"_err_en_US)};
if (const Symbol * subprogram{InclusiveScope().symbol()}) {
msg.Attach(subprogram->name(), "Containing subprogram"_en_US);
@@ -4846,7 +4846,10 @@ void SubprogramVisitor::Post(const parser::InterfaceBody::Function &x) {
const auto &stmt{std::get<parser::Statement<parser::FunctionStmt>>(x.t)};
const auto &maybeSuffix{
std::get<std::optional<parser::Suffix>>(stmt.statement.t)};
- EndSubprogram(stmt.source, maybeSuffix ? &maybeSuffix->binding : nullptr);
+ EndSubprogram(stmt.source,
+ maybeSuffix ? &std::get<std::optional<parser::LanguageBindingSpec>>(
+ maybeSuffix->t)
+ : nullptr);
}
bool SubprogramVisitor::Pre(const parser::SubroutineStmt &stmt) {
@@ -4961,7 +4964,7 @@ Symbol &SubprogramVisitor::PostSubprogramStmt() {
void SubprogramVisitor::Post(const parser::EntryStmt &stmt) {
if (const auto &suffix{std::get<std::optional<parser::Suffix>>(stmt.t)}) {
- Walk(suffix->binding);
+ Walk(std::get<std::optional<parser::LanguageBindingSpec>>(suffix->t));
}
PostEntryStmt(stmt);
EndAttrs();
@@ -5000,9 +5003,17 @@ void SubprogramVisitor::CreateEntry(
: Symbol::Flag::Subroutine};
Attrs attrs;
const auto &suffix{std::get<std::optional<parser::Suffix>>(stmt.t)};
- bool hasGlobalBindingName{outer.IsGlobal() && suffix && suffix->binding &&
- std::get<std::optional<parser::ScalarDefaultCharConstantExpr>>(
- suffix->binding->t)
+ const auto *binding{[&]() {
+ if (suffix) {
+ if (auto &b{std::get<std::optional<parser::LanguageBindingSpec>>(
+ suffix->t)}) {
+ return &*b;
+ }
+ }
+ return static_cast<const parser::LanguageBindingSpec *>(nullptr);
+ }()};
+ bool hasGlobalBindingName{outer.IsGlobal() && binding &&
+ std::get<std::optional<parser::ScalarDefaultCharConstantExpr>>(binding->t)
.has_value()};
if (!hasGlobalBindingName) {
if (Symbol * extant{FindSymbol(outer, entryName)}) {
@@ -5019,10 +5030,17 @@ void SubprogramVisitor::CreateEntry(
attrs = extant->attrs();
}
}
+ const auto *resultName{[&]() {
+ if (suffix) {
+ if (auto &n{std::get<std::optional<parser::Name>>(suffix->t)}) {
+ return &*n;
+ }
+ }
+ return static_cast<const parser::Name *>(nullptr);
+ }()};
std::optional<SourceName> distinctResultName;
- if (suffix && suffix->resultName &&
- suffix->resultName->source != entryName.source) {
- distinctResultName = suffix->resultName->source;
+ if (resultName && resultName->source != entryName.source) {
+ distinctResultName = resultName->source;
}
if (outer.IsModule() && !attrs.test(Attr::PRIVATE)) {
attrs.set(Attr::PUBLIC);
@@ -5060,7 +5078,7 @@ void SubprogramVisitor::CreateEntry(
if (distinctResultName) {
// An explicit RESULT() can also be an explicit RESULT()
// of the function or another ENTRY.
- if (auto iter{currScope().find(suffix->resultName->source)};
+ if (auto iter{currScope().find(resultName->source)};
iter != currScope().end()) {
result = &*iter->second;
}
@@ -5076,7 +5094,7 @@ void SubprogramVisitor::CreateEntry(
result = nullptr;
}
if (result) {
- Resolve(*suffix->resultName, *result);
+ Resolve(*resultName, *result);
}
} else {
result = &MakeSymbol(entryName.source, Attrs{}, std::move(resultDetails));
@@ -5315,7 +5333,8 @@ void SubprogramVisitor::EndSubprogram(
if (const auto &suffix{
std::get<std::optional<parser::Suffix>>(entryStmt.t)}) {
const auto &name{std::get<parser::Name>(entryStmt.t)};
- HandleLanguageBinding(name.symbol, name.source, &suffix->binding);
+ HandleLanguageBinding(name.symbol, name.source,
+ &std::get<std::optional<parser::LanguageBindingSpec>>(suffix->t));
}
}
}
@@ -6812,7 +6831,8 @@ void DeclarationVisitor::Post(
if (GetAttrs().test(Attr::DEFERRED)) { // C783
Say("DEFERRED is only allowed when an interface-name is provided"_err_en_US);
}
- for (auto &declaration : x.declarations) {
+ const auto &declarations{std::get<std::list<parser::TypeBoundProcDecl>>(x.t)};
+ for (auto &declaration : declarations) {
auto &bindingName{std::get<parser::Name>(declaration.t)};
auto &optName{std::get<std::optional<parser::Name>>(declaration.t)};
const parser::Name &procedureName{optName ? *optName : bindingName};
@@ -6835,7 +6855,9 @@ void DeclarationVisitor::Post(
void DeclarationVisitor::CheckBindings(
const parser::TypeBoundProcedureStmt::WithoutInterface &tbps) {
CHECK(currScope().IsDerivedType());
- for (auto &declaration : tbps.declarations) {
+ const auto &declarations{
+ std::get<std::list<parser::TypeBoundProcDecl>>(tbps.t)};
+ for (auto &declaration : declarations) {
auto &bindingName{std::get<parser::Name>(declaration.t)};
if (Symbol * binding{FindInScope(bindingName)}) {
if (auto *details{binding->detailsIf<ProcBindingDetails>()}) {
@@ -6869,8 +6891,9 @@ void DeclarationVisitor::Post(
if (!GetAttrs().test(Attr::DEFERRED)) { // C783
Say("DEFERRED is required when an interface-name is provided"_err_en_US);
}
- if (Symbol * interface{NoteInterfaceName(x.interfaceName)}) {
- for (auto &bindingName : x.bindingNames) {
+ const auto &[interfaceName, _, bindingNames]{x.t};
+ if (Symbol * interface{NoteInterfaceName(interfaceName)}) {
+ for (auto &bindingName : bindingNames) {
if (auto *s{
MakeTypeSymbol(bindingName, ProcBindingDetails{*interface})}) {
SetPassNameOn(*s);
@@ -8706,8 +8729,9 @@ bool ResolveNamesVisitor::Pre(const parser::FunctionReference &x) {
return false;
}
bool ResolveNamesVisitor::Pre(const parser::CallStmt &x) {
- HandleCall(Symbol::Flag::Subroutine, x.call);
- Walk(x.chevrons);
+ const auto &[call, chevrons]{x.t};
+ HandleCall(Symbol::Flag::Subroutine, call);
+ Walk(chevrons);
return false;
}
@@ -10398,7 +10422,8 @@ class ExecutionPartCallSkimmer : public ExecutionPartSkimmerBase {
NoteCall(Symbol::Flag::Function, fr.v, false);
}
void Post(const parser::CallStmt &cs) {
- NoteCall(Symbol::Flag::Subroutine, cs.call, cs.chevrons.has_value());
+ const auto &[call, chevrons]{cs.t};
+ NoteCall(Symbol::Flag::Subroutine, call, chevrons.has_value());
}
private:
@@ -10591,7 +10616,8 @@ void ResolveNamesVisitor::EndScopeForNode(const ProgramTree &node) {
if (const auto &maybeSuffix{
std::get<std::optional<parser::Suffix>>(
stmt->statement.t)}) {
- binding = &maybeSuffix->binding;
+ binding = &std::get<std::optional<parser::LanguageBindingSpec>>(
+ maybeSuffix->t);
}
}
},
@@ -10661,7 +10687,7 @@ class DeferredCheckVisitor {
return false;
}
void Post(const parser::TypeBoundProcedureStmt::WithInterface &tbps) {
- resolver_.CheckExplicitInterface(tbps.interfaceName);
+ resolver_.CheckExplicitInterface(std::get<parser::Name>(tbps.t));
}
void Post(const parser::TypeBoundProcedureStmt::WithoutInterface &tbps) {
if (outerScope_) {
diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index cf1e5e7d44565..baa8e6d7f59a3 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -953,13 +953,13 @@ class ImageControlStmtHelper {
return false;
}
bool operator()(const parser::CallStmt &stmt) {
+ const auto &call{std::get<parser::Call>(stmt.t)};
const auto &procedureDesignator{
- std::get<parser::ProcedureDesignator>(stmt.call.t)};
+ std::get<parser::ProcedureDesignator>(call.t)};
if (auto *name{std::get_if<parser::Name>(&procedureDesignator.u)}) {
// TODO: also ensure that the procedure is, in fact, an intrinsic
if (name->source == "move_alloc") {
- const auto &args{
- std::get<std::list<parser::ActualArgSpec>>(stmt.call.t)};
+ const auto &args{std::get<std::list<parser::ActualArgSpec>>(call.t)};
if (!args.empty()) {
const parser::ActualArg &actualArg{
std::get<parser::ActualArg>(args.front().t)};
>From 0899be9a1ae6fe8b427ab44098b29f5c381e5240 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Mon, 12 Jan 2026 09:46:25 -0600
Subject: [PATCH 2/3] Remove leftover comment
---
flang/lib/Parser/parse-tree.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/flang/lib/Parser/parse-tree.cpp b/flang/lib/Parser/parse-tree.cpp
index 819470a43b0c8..e0c668ddc328b 100644
--- a/flang/lib/Parser/parse-tree.cpp
+++ b/flang/lib/Parser/parse-tree.cpp
@@ -54,7 +54,6 @@ DataRef::DataRef(std::list<PartRef> &&prl)
: u{std::move(std::get<Name>(prl.front().t))} {
for (bool first{true}; !prl.empty(); first = false, prl.pop_front()) {
auto &&[name, subscripts, imageSelector]{prl.front().t};
- // PartRef &pr{prl.front()};
if (!first) {
u = common::Indirection<StructureComponent>::Make(
std::move(*this), std::move(name));
>From 38023b284365cac9ac1b41dc45f70190b0918c73 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Mon, 12 Jan 2026 09:51:33 -0600
Subject: [PATCH 3/3] format
---
flang/include/flang/Parser/parse-tree.h | 4 ++--
flang/lib/Semantics/expression.cpp | 4 ++--
flang/lib/Semantics/resolve-names.cpp | 6 +++---
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 1d72c1cb1c80e..c03823b60f0de 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3251,8 +3251,8 @@ struct CallStmt {
t;
};
explicit CallStmt(ProcedureDesignator &&pd, std::optional<Chevrons> &&ch,
- std::list<ActualArgSpec> &&args) :
- CallStmt(Call{std::move(pd), std::move(args)}, std::move(ch)) {}
+ std::list<ActualArgSpec> &&args)
+ : CallStmt(Call{std::move(pd), std::move(args)}, std::move(ch)) {}
std::tuple<Call, std::optional<Chevrons>> t;
CharBlock source;
mutable TypedCall typedCall; // filled by semantics
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index ece5d23bb59d2..d0296e4b1f36c 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -918,8 +918,8 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::RealLiteralConstant &x) {
}
}
bool isDefaultKind{!xkind && letterKind.value_or('e') == 'e'};
- auto result{common::SearchTypes(RealTypeVisitor{
- kind, xreal.source, GetFoldingContext(), isDefaultKind})};
+ auto result{common::SearchTypes(
+ RealTypeVisitor{kind, xreal.source, GetFoldingContext(), isDefaultKind})};
if (!result) { // C717
Say("Unsupported REAL(KIND=%d)"_err_en_US, kind);
}
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 04d734781265e..2f15ab1e82e2b 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -4670,9 +4670,9 @@ bool SubprogramVisitor::Pre(const parser::Suffix &suffix) {
}
}
} else {
- Message &msg{Say(*resultName,
- "RESULT(%s) may appear only in a function"_err_en_US)};
- if (const Symbol * subprogram{InclusiveScope().symbol()}) {
+ Message &msg{Say(
+ *resultName, "RESULT(%s) may appear only in a function"_err_en_US)};
+ if (const Symbol *subprogram{InclusiveScope().symbol()}) {
msg.Attach(subprogram->name(), "Containing subprogram"_en_US);
}
}
More information about the llvm-branch-commits
mailing list