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 <[email protected]> Date: Fri, 9 Jan 2026 15:50:38 -0600 Subject: [PATCH 1/2] [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 <[email protected]> Date: Mon, 12 Jan 2026 09:46:25 -0600 Subject: [PATCH 2/2] 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)); _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
