From: peter klausler Date: Fri, 8 Mar 2019 20:55:57 +0000 (-0800) Subject: [flang] Resolve misparse of structure constructor as function reference. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=64ea462e3afac2e0a21f4d099fb4d2797f2c134f;p=platform%2Fupstream%2Fllvm.git [flang] Resolve misparse of structure constructor as function reference. Original-commit: flang-compiler/f18@5b6b2540f6c66b3f2900b24b06d732de3436b4ea Reviewed-on: https://github.com/flang-compiler/f18/pull/322 Tree-same-pre-rewrite: false --- diff --git a/flang/lib/parser/parse-tree.cc b/flang/lib/parser/parse-tree.cc index f4894fa..17b6f57 100644 --- a/flang/lib/parser/parse-tree.cc +++ b/flang/lib/parser/parse-tree.cc @@ -89,34 +89,50 @@ static Designator MakeArrayElementRef(Name &name, std::list &subscripts) { return Designator{DataRef{common::Indirection{std::move(arrayElement)}}}; } +static std::optional ActualArgToExpr(ActualArgSpec &arg) { + return std::visit( + common::visitors{ + [&](common::Indirection &y) { + return std::make_optional(std::move(y.value())); + }, + [&](common::Indirection &y) { + return std::visit( + [&](auto &indirection) { + return std::make_optional( + std::move(indirection.value())); + }, + y.value().u); + }, + [&](auto &) -> std::optional { return std::nullopt; }, + }, + std::get(arg.t).u); +} + Designator FunctionReference::ConvertToArrayElementRef() { auto &name{std::get(std::get(v.t).u)}; std::list args; for (auto &arg : std::get>(v.t)) { - std::visit( - common::visitors{ - [&](common::Indirection &y) { - args.push_back(std::move(y.value())); - }, - [&](common::Indirection &y) { - args.push_back(std::visit( - common::visitors{ - [&](common::Indirection &z) { - return Expr{std::move(z.value())}; - }, - [&](common::Indirection &z) { - return Expr{std::move(z.value())}; - }, - }, - y.value().u)); - }, - [&](auto &) { CHECK(!"unexpected kind of ActualArg"); }, - }, - std::get(arg.t).u); + args.emplace_back(std::move(ActualArgToExpr(arg).value())); } return MakeArrayElementRef(name, args); } +StructureConstructor FunctionReference::ConvertToStructureConstructor() { + Name name{std::get(std::get(v.t).u)}; + std::list components; + for (auto &arg : std::get>(v.t)) { + std::optional keyword; + if (auto &kw{std::get>(arg.t)}) { + keyword.emplace(Keyword{Name{kw->v}}); + } + components.emplace_back( + std::move(keyword), ComponentDataSource{ActualArgToExpr(arg).value()}); + } + return StructureConstructor{ + DerivedTypeSpec{std::move(name), std::list{}}, + std::move(components)}; +} + // R1544 stmt-function-stmt // Convert this stmt-function-stmt to an array element assignment statement. Statement StmtFunctionStmt::ConvertToAssignment() { diff --git a/flang/lib/parser/parse-tree.h b/flang/lib/parser/parse-tree.h index 2c25c82..5bdff06 100644 --- a/flang/lib/parser/parse-tree.h +++ b/flang/lib/parser/parse-tree.h @@ -538,8 +538,6 @@ WRAPPER_CLASS(Program, std::list); // R603 name -> letter [alphanumeric-character]... struct Name { - Name() {} - COPY_AND_ASSIGN_BOILERPLATE(Name); std::string ToString() const { return source.ToString(); } CharBlock source; mutable semantics::Symbol *symbol{nullptr}; // filled in during semantics @@ -3094,6 +3092,7 @@ struct Call { struct FunctionReference { WRAPPER_CLASS_BOILERPLATE(FunctionReference, Call); Designator ConvertToArrayElementRef(); + StructureConstructor ConvertToStructureConstructor(); }; // R1521 call-stmt -> CALL procedure-designator [( [actual-arg-spec-list] )] diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index 87c6363..7be75a5 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -196,7 +196,8 @@ MaybeExpr TypedWrapper(const DynamicType &dyType, WRAPPED &&x) { // Wraps a data reference in a typed Designator<>. static MaybeExpr Designate(DataRef &&ref) { - if (std::optional dyType{GetSymbolType(ref.GetLastSymbol())}) { + if (std::optional dyType{ + GetSymbolType(ref.GetLastSymbol().GetUltimate())}) { return TypedWrapper( std::move(*dyType), std::move(ref)); } @@ -205,7 +206,8 @@ static MaybeExpr Designate(DataRef &&ref) { } // Catch and resolve the ambiguous parse of a substring reference -// that looks like a 1-D array element or section. +// that looks like a 1-D array element or section. The parse tree is +// not adjusted. static MaybeExpr ResolveAmbiguousSubstring(ArrayRef &&ref) { if (std::optional dyType{GetSymbolType(ref.GetLastSymbol())}) { if (dyType->category == TypeCategory::Character && ref.size() == 1) { @@ -240,7 +242,7 @@ static MaybeExpr ResolveAmbiguousSubstring(ArrayRef &&ref) { // ambiguous parse of a substring reference that looks like a 1-D array // element or section. MaybeExpr ExpressionAnalyzer::CompleteSubscripts(ArrayRef &&ref) { - const Symbol &symbol{ref.GetLastSymbol()}; + const Symbol &symbol{ref.GetLastSymbol().GetUltimate()}; int symbolRank{symbol.Rank()}; int subscripts = ref.size(); if (subscripts == 0) { @@ -627,23 +629,24 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Name &n) { if (std::optional kind{IsAcImpliedDo(n.source)}) { return AsMaybeExpr(ConvertToKind( *kind, AsExpr(ImpliedDoIndex{n.source}))); - } else if (n.symbol == nullptr) { - // error should have been reported in name resolution - } else if (n.symbol->attrs().test(semantics::Attr::PARAMETER)) { - if (auto *details{n.symbol->detailsIf()}) { - if (auto &init{details->init()}) { - return init; + } else if (n.symbol != nullptr) { + const Symbol &ultimate{n.symbol->GetUltimate()}; + if (ultimate.attrs().test(semantics::Attr::PARAMETER)) { + if (auto *details{ultimate.detailsIf()}) { + if (auto &init{details->init()}) { + return init; + } } + // TODO: enumerators, do they have the PARAMETER attribute? + } else if (ultimate.detailsIf()) { + // A bare reference to a derived type parameter (within a parameterized + // derived type definition) + return AsMaybeExpr(MakeTypeParamInquiry(&ultimate)); + } else if (MaybeExpr result{Designate(DataRef{*n.symbol})}) { + return result; + } else { + Say(n.source, "not of a supported type and kind"_err_en_US); } - // TODO: enumerators, do they have the PARAMETER attribute? - } else if (n.symbol->detailsIf()) { - // A bare reference to a derived type parameter (within a parameterized - // derived type definition) - return AsMaybeExpr(MakeTypeParamInquiry(n.symbol)); - } else if (MaybeExpr result{Designate(DataRef{*n.symbol})}) { - return result; - } else { - Say(n.source, "not of a supported type and kind"_err_en_US); } return std::nullopt; } @@ -1382,38 +1385,31 @@ auto ExpressionAnalyzer::Procedure(const parser::ProcedureDesignator &pd, n.ToString().data()); return std::nullopt; } - return std::visit( - common::visitors{ - [&](const semantics::ProcEntityDetails &p) - -> std::optional { - if (p.HasExplicitInterface()) { - // TODO: check actual arguments vs. interface - } else { - CallCharacteristics cc{n.source}; - if (std::optional specificCall{ - context().intrinsics().Probe( - cc, arguments, &GetContextualMessages())}) { - return {CallAndArguments{ - ProcedureDesignator{ - std::move(specificCall->specificIntrinsic)}, - std::move(specificCall->arguments)}}; - } else { - // TODO: if name is not INTRINSIC, call with implicit - // interface - } - } - return {CallAndArguments{ProcedureDesignator{*n.symbol}, - std::move(arguments)}}; - }, - [&](const auto &) -> std::optional { - // TODO pmk WIP: resolve ambiguous array reference or - // structure constructor usage that reach here - Say("TODO: unimplemented/invalid kind of symbol as procedure designator '%s'"_err_en_US, - n.ToString().data()); - return std::nullopt; - }, - }, - n.symbol->details()); + const Symbol &ultimate{n.symbol->GetUltimate()}; + if (const auto *proc{ + ultimate.detailsIf()}) { + if (proc->HasExplicitInterface()) { + // TODO: check actual arguments vs. interface + } else { + CallCharacteristics cc{n.source}; + if (std::optional specificCall{ + context().intrinsics().Probe( + cc, arguments, &GetContextualMessages())}) { + return { + CallAndArguments{ProcedureDesignator{std::move( + specificCall->specificIntrinsic)}, + std::move(specificCall->arguments)}}; + } else { + // TODO: if name is not INTRINSIC, call with implicit + // interface + } + } + return {CallAndArguments{ + ProcedureDesignator{*n.symbol}, std::move(arguments)}}; + } else { + Say(n.source, "not a procedure"_err_en_US); + return std::nullopt; + } }, [&](const parser::ProcComponentRef &pcr) -> std::optional { @@ -1756,21 +1752,60 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::DefinedBinary &) { return std::nullopt; } +// Converts, if appropriate, a misparse of the ambiguous syntax A(1) as +// a function reference into an array reference or a structure constructor. +template +void FixMisparsedFunctionReference(const std::variant &constU) { + // The parse tree is updated in situ when resolving an ambiguous parse. + using uType = std::decay_t; + auto &u{const_cast(constU)}; + if (auto *func{ + std::get_if>(&u)}) { + parser::FunctionReference &funcRef{func->value()}; + auto &proc{std::get(funcRef.v.t)}; + if (auto *name{std::get_if(&proc.u)}) { + if (name->symbol == nullptr) { + return; + } + Symbol &symbol{name->symbol->GetUltimate()}; + if constexpr (common::HasMember, + uType>) { + if (symbol.has()) { + u = common::Indirection{funcRef.ConvertToArrayElementRef()}; + return; + // N.B. Expression semantics will reinterpret an array element + // reference as a single-character substring elsewhere if necessary. + } + } + if constexpr (common::HasMember) { + if (symbol.has()) { + u = funcRef.ConvertToStructureConstructor(); + return; + } + } + } + } +} + MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr &expr) { if (expr.typedExpr.has_value()) { // Expression was already checked by ExprChecker return std::make_optional>(expr.typedExpr.value().v); - } else if (!expr.source.empty()) { - // Analyze the expression in a specified source position context for better - // error reporting. - auto save{GetFoldingContext().messages().SetLocation(expr.source)}; - return Analyze(expr.u); } else { - return Analyze(expr.u); + FixMisparsedFunctionReference(expr.u); + if (!expr.source.empty()) { + // Analyze the expression in a specified source position context for + // better error reporting. + auto save{GetFoldingContext().messages().SetLocation(expr.source)}; + return Analyze(expr.u); + } else { + return Analyze(expr.u); + } } } MaybeExpr ExpressionAnalyzer::Analyze(const parser::Variable &variable) { + FixMisparsedFunctionReference(variable.u); return Analyze(variable.u); } @@ -1894,4 +1929,19 @@ void ExprChecker::Enter(const parser::Expr &expr) { } } } + +void ExprChecker::Enter(const parser::Variable &var) { +#if PMKDEBUG + if (MaybeExpr checked{AnalyzeExpr(context_, var)}) { +// checked->AsFortran(std::cout << "checked variable: ") << '\n'; +#else + if (AnalyzeExpr(context_, var)) { +#endif + } else { +#if PMKDEBUG + std::cout << "TODO: expression analysis failed for this variable: "; + DumpTree(std::cout, var); +#endif + } +} } diff --git a/flang/lib/semantics/expression.h b/flang/lib/semantics/expression.h index 2728dc7..96cdd74 100644 --- a/flang/lib/semantics/expression.h +++ b/flang/lib/semantics/expression.h @@ -297,6 +297,7 @@ class ExprChecker : public virtual BaseChecker { public: explicit ExprChecker(SemanticsContext &context) : context_{context} {} void Enter(const parser::Expr &); + void Enter(const parser::Variable &); private: SemanticsContext &context_; diff --git a/flang/lib/semantics/rewrite-parse-tree.cc b/flang/lib/semantics/rewrite-parse-tree.cc index 02748ca..1788f11 100644 --- a/flang/lib/semantics/rewrite-parse-tree.cc +++ b/flang/lib/semantics/rewrite-parse-tree.cc @@ -37,8 +37,6 @@ public: void Post(parser::Name &); void Post(parser::SpecificationPart &); bool Pre(parser::ExecutionPart &); - void Post(parser::Variable &x) { ConvertFunctionRef(x); } - void Post(parser::Expr &x) { ConvertFunctionRef(x); } // Name resolution yet implemented: bool Pre(parser::EquivalenceStmt &) { return false; } @@ -62,24 +60,6 @@ private: bool errorOnUnresolvedName_{true}; parser::Messages &messages_; std::list stmtFuncsToConvert_; - - // For T = Variable or Expr, if x has a function reference that really - // should be an array element reference (i.e. the name occurs in an - // entity declaration, convert it. - template void ConvertFunctionRef(T &x) { - auto *funcRef{ - std::get_if>(&x.u)}; - if (!funcRef) { - return; - } - parser::Name *name{std::get_if( - &std::get(funcRef->value().v.t).u)}; - if (!name || !name->symbol || - !name->symbol->GetUltimate().has()) { - return; - } - x.u = common::Indirection{funcRef->value().ConvertToArrayElementRef()}; - } }; // Check that name has been resolved to a symbol