diff --git a/flang/include/flang/Semantics/expression.h b/flang/include/flang/Semantics/expression.h --- a/flang/include/flang/Semantics/expression.h +++ b/flang/include/flang/Semantics/expression.h @@ -154,6 +154,7 @@ MaybeExpr Analyze(const parser::Expr &); MaybeExpr Analyze(const parser::Variable &); + MaybeExpr Analyze(const parser::Selector &); MaybeExpr Analyze(const parser::Designator &); MaybeExpr Analyze(const parser::DataStmtValue &); MaybeExpr Analyze(const parser::AllocateObject &); @@ -295,30 +296,6 @@ template MaybeExpr Analyze(const std::variant &u) { return std::visit( [&](const auto &x) { - using Ty = std::decay_t; - // Function references might turn out to be misparsed structure - // constructors; we have to try generic procedure resolution - // first to be sure. - if constexpr (common::IsTypeInList) { - std::optional ctor; - MaybeExpr result; - if constexpr (std::is_same_v>) { - result = Analyze(x.value(), &ctor); - } else if constexpr (std::is_same_v) { - result = Analyze(x, &ctor); - } else { - return Analyze(x); - } - if (ctor) { - // A misparsed function reference is really a structure - // constructor. Repair the parse tree in situ. - const_cast &>(u) = std::move(*ctor); - } - return result; - } return Analyze(x); }, u); @@ -413,7 +390,7 @@ namespace Fortran::semantics { -// Semantic analysis of one expression, variable, or designator. +// Semantic analysis of one expression, variable, selector, designator, &c. template std::optional> AnalyzeExpr( SemanticsContext &context, const A &expr) { @@ -449,6 +426,10 @@ exprAnalyzer_.Analyze(x); return false; } + bool Pre(const parser::Selector &x) { + exprAnalyzer_.Analyze(x); + return false; + } bool Pre(const parser::DataStmtValue &x) { exprAnalyzer_.Analyze(x); return false; diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -2758,46 +2758,105 @@ } if (AssumedTypeDummy(x)) { // C710 Say("TYPE(*) dummy argument may only be used as an actual argument"_err_en_US); - } else if (MaybeExpr result{Analyze(x.u)}) { + ResetExpr(x); + return std::nullopt; + } + MaybeExpr result; + if constexpr (common::HasMember> && + common::HasMember, + std::decay_t>) { + if (const auto *funcRef{ + std::get_if>( + &x.u)}) { + // Function references in Exprs might turn out to be misparsed structure + // constructors; we have to try generic procedure resolution + // first to be sure. + std::optional ctor; + result = Analyze(funcRef->value(), &ctor); + if (result && ctor) { + // A misparsed function reference is really a structure + // constructor. Repair the parse tree in situ. + const_cast(x).u = std::move(*ctor); + } + } else { + result = Analyze(x.u); + } + } else { + result = Analyze(x.u); + } + if (result) { SetExpr(x, Fold(std::move(*result))); return x.typedExpr->v; + } else { + ResetExpr(x); + if (!context_.AnyFatalError()) { + std::string buf; + llvm::raw_string_ostream dump{buf}; + parser::DumpTree(dump, x); + Say("Internal error: Expression analysis failed on: %s"_err_en_US, + dump.str()); + } + return std::nullopt; } - ResetExpr(x); - if (!context_.AnyFatalError()) { - std::string buf; - llvm::raw_string_ostream dump{buf}; - parser::DumpTree(dump, x); - Say("Internal error: Expression analysis failed on: %s"_err_en_US, - dump.str()); - } - return std::nullopt; } MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr &expr) { - auto restorer{GetContextualMessages().SetLocation(expr.source)}; return ExprOrVariable(expr, expr.source); } MaybeExpr ExpressionAnalyzer::Analyze(const parser::Variable &variable) { - auto restorer{GetContextualMessages().SetLocation(variable.GetSource())}; return ExprOrVariable(variable, variable.GetSource()); } +MaybeExpr ExpressionAnalyzer::Analyze(const parser::Selector &selector) { + if (const auto *var{std::get_if(&selector.u)}) { + if (!useSavedTypedExprs_ || !var->typedExpr) { + parser::CharBlock source{var->GetSource()}; + auto restorer{GetContextualMessages().SetLocation(source)}; + FixMisparsedFunctionReference(context_, var->u); + if (const auto *funcRef{ + std::get_if>( + &var->u)}) { + // A Selector that parsed as a Variable might turn out during analysis + // to actually be a structure constructor. In that case, repair the + // Variable parse tree node into an Expr + std::optional ctor; + if (MaybeExpr result{Analyze(funcRef->value(), &ctor)}) { + if (ctor) { + auto &writable{const_cast(selector)}; + writable.u = parser::Expr{std::move(*ctor)}; + auto &expr{std::get(writable.u)}; + expr.source = source; + SetExpr(expr, Fold(std::move(*result))); + return expr.typedExpr->v; + } else { + SetExpr(*var, Fold(std::move(*result))); + return var->typedExpr->v; + } + } else { + ResetExpr(*var); + if (context_.AnyFatalError()) { + return std::nullopt; + } + } + } + } + } + // Not a Variable -> FunctionReference; handle normally as Variable or Expr + return Analyze(selector.u); +} + MaybeExpr ExpressionAnalyzer::Analyze(const parser::DataStmtConstant &x) { - auto restorer{GetContextualMessages().SetLocation(x.source)}; return ExprOrVariable(x, x.source); } MaybeExpr ExpressionAnalyzer::Analyze(const parser::AllocateObject &x) { - parser::CharBlock source{parser::FindSourceLocation(x)}; - auto restorer{GetContextualMessages().SetLocation(source)}; - return ExprOrVariable(x, source); + return ExprOrVariable(x, parser::FindSourceLocation(x)); } MaybeExpr ExpressionAnalyzer::Analyze(const parser::PointerObject &x) { - parser::CharBlock source{parser::FindSourceLocation(x)}; - auto restorer{GetContextualMessages().SetLocation(source)}; - return ExprOrVariable(x, source); + return ExprOrVariable(x, parser::FindSourceLocation(x)); } Expr ExpressionAnalyzer::AnalyzeKindSelector( diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -5625,10 +5625,10 @@ const parser::Selector &x) { return std::visit(common::visitors{ [&](const parser::Expr &expr) { - return Selector{expr.source, EvaluateExpr(expr)}; + return Selector{expr.source, EvaluateExpr(x)}; }, [&](const parser::Variable &var) { - return Selector{var.GetSource(), EvaluateExpr(var)}; + return Selector{var.GetSource(), EvaluateExpr(x)}; }, }, x.u);