From: Tim Keith Date: Wed, 15 Jan 2020 01:39:29 +0000 (-0800) Subject: [flang] Make GenericAssignmentWrapper more like GenericExprWrapper X-Git-Tag: llvmorg-12-init~9537^2~183 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0ac2761f2c9ec1ce189ef9c4849a5edbac235b8a;p=platform%2Fupstream%2Fllvm.git [flang] Make GenericAssignmentWrapper more like GenericExprWrapper Have it wrap an optional Assignment so that we can distinguish between unanalyzed and analyzed with error. Change analysis of PointerAssignmentStmt to proceed with bounds even if the DataRef or Expr has an error. Otherwise any bounds expressions won't be analyzed in that case. In GetExpr() and GetAssignment() if we get an internal error due to an unanalyzed expression, dump the parse tree for the expression so we have some context for the error. They should only be called after the expression analysis phase. At that point, every expression and assignment should be analyzed, though some may have resulted in errors(indicated by returning `nullptr`). Original-commit: flang-compiler/f18@3b865d7703f53099cd491ed1aa9b80b46fee9f58 Reviewed-on: https://github.com/flang-compiler/f18/pull/944 Tree-same-pre-rewrite: false --- diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index f10ba21..00363b5 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -847,9 +847,10 @@ struct GenericExprWrapper { // Like GenericExprWrapper but for analyzed assignments struct GenericAssignmentWrapper { + GenericAssignmentWrapper() {} explicit GenericAssignmentWrapper(Assignment &&x) : v{std::move(x)} {} ~GenericAssignmentWrapper(); - Assignment v; + std::optional v; // vacant if error }; FOR_EACH_CATEGORY_TYPE(extern template class Expr, ) diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index a5eb00b..e24b310 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -1915,7 +1915,9 @@ const Assignment *ExpressionAnalyzer::Analyze(const parser::AssignmentStmt &x) { ArgumentAnalyzer analyzer{*this}; analyzer.Analyze(std::get(x.t)); analyzer.Analyze(std::get(x.t)); - if (!analyzer.fatalErrors()) { + if (analyzer.fatalErrors()) { + x.typedAssignment.reset(new GenericAssignmentWrapper{}); + } else { std::optional procRef{analyzer.TryDefinedAssignment()}; x.typedAssignment.reset(new GenericAssignmentWrapper{procRef ? Assignment{std::move(*procRef)} @@ -1923,50 +1925,55 @@ const Assignment *ExpressionAnalyzer::Analyze(const parser::AssignmentStmt &x) { Fold(analyzer.MoveExpr(0)), Fold(analyzer.MoveExpr(1))}}}); } } - return x.typedAssignment ? &x.typedAssignment->v : nullptr; + return common::GetPtrFromOptional(x.typedAssignment->v); } const Assignment *ExpressionAnalyzer::Analyze( const parser::PointerAssignmentStmt &x) { - MaybeExpr lhs{Analyze(std::get(x.t))}; - MaybeExpr rhs{Analyze(std::get(x.t))}; - if (!lhs || !rhs) { - return nullptr; - } - Assignment::PointerAssignment assignment{ - Fold(std::move(*lhs)), Fold(std::move(*rhs))}; - std::visit( - common::visitors{ - [&](const std::list &list) { - if (!list.empty()) { - Assignment::PointerAssignment::BoundsRemapping bounds; - for (const auto &elem : list) { - auto lower{AsSubscript(Analyze(std::get<0>(elem.t)))}; - auto upper{AsSubscript(Analyze(std::get<1>(elem.t)))}; - if (lower && upper) { - bounds.emplace_back( - Fold(std::move(*lower)), Fold(std::move(*upper))); + if (!x.typedAssignment) { + MaybeExpr lhs{Analyze(std::get(x.t))}; + MaybeExpr rhs{Analyze(std::get(x.t))}; + decltype(Assignment::PointerAssignment::bounds) pointerBounds; + std::visit( + common::visitors{ + [&](const std::list &list) { + if (!list.empty()) { + Assignment::PointerAssignment::BoundsRemapping bounds; + for (const auto &elem : list) { + auto lower{AsSubscript(Analyze(std::get<0>(elem.t)))}; + auto upper{AsSubscript(Analyze(std::get<1>(elem.t)))}; + if (lower && upper) { + bounds.emplace_back( + Fold(std::move(*lower)), Fold(std::move(*upper))); + } } + pointerBounds = bounds; } - assignment.bounds = bounds; - } - }, - [&](const std::list &list) { - if (!list.empty()) { - Assignment::PointerAssignment::BoundsSpec bounds; - for (const auto &bound : list) { - if (auto lower{AsSubscript(Analyze(bound.v))}) { - bounds.emplace_back(Fold(std::move(*lower))); + }, + [&](const std::list &list) { + if (!list.empty()) { + Assignment::PointerAssignment::BoundsSpec bounds; + for (const auto &bound : list) { + if (auto lower{AsSubscript(Analyze(bound.v))}) { + bounds.emplace_back(Fold(std::move(*lower))); + } } + pointerBounds = bounds; } - assignment.bounds = bounds; - } - }, - }, - std::get(x.t).u); - x.typedAssignment.reset( - new GenericAssignmentWrapper{Assignment{std::move(assignment)}}); - return &x.typedAssignment->v; + }, + }, + std::get(x.t).u); + if (!lhs || !rhs) { + x.typedAssignment.reset(new GenericAssignmentWrapper{}); + } else { + Assignment::PointerAssignment assignment{ + Fold(std::move(*lhs)), Fold(std::move(*rhs))}; + assignment.bounds = pointerBounds; + x.typedAssignment.reset( + new GenericAssignmentWrapper{Assignment{std::move(assignment)}}); + } + } + return common::GetPtrFromOptional(x.typedAssignment->v); } static bool IsExternalCalledImplicitly( diff --git a/flang/lib/semantics/tools.cc b/flang/lib/semantics/tools.cc index 18c5c82..8342e41 100644 --- a/flang/lib/semantics/tools.cc +++ b/flang/lib/semantics/tools.cc @@ -13,11 +13,13 @@ #include "type.h" #include "../common/Fortran.h" #include "../common/indirection.h" +#include "../parser/dump-parse-tree.h" #include "../parser/message.h" #include "../parser/parse-tree.h" #include "../parser/tools.h" #include #include +#include #include namespace Fortran::semantics { @@ -383,14 +385,33 @@ bool ExprTypeKindIsDefault( dynamicType->kind() == context.GetDefaultKind(dynamicType->category()); } +// If an analyzed expr or assignment is missing, dump the node and die. +template static void CheckMissingAnalysis(bool absent, const T &x) { + if (absent) { + std::ostringstream ss; + ss << "node has not been analyzed:\n"; + parser::DumpTree(ss, x); + common::die(ss.str().c_str()); + } +} + +const SomeExpr *GetExprHelper::Get(const parser::Expr &x) { + CheckMissingAnalysis(!x.typedExpr, x); + return common::GetPtrFromOptional(x.typedExpr->v); +} +const SomeExpr *GetExprHelper::Get(const parser::Variable &x) { + CheckMissingAnalysis(!x.typedExpr, x); + return common::GetPtrFromOptional(x.typedExpr->v); +} + const evaluate::Assignment *GetAssignment(const parser::AssignmentStmt &x) { - const auto &typed{x.typedAssignment}; - return typed ? &typed->v : nullptr; + CheckMissingAnalysis(!x.typedAssignment, x); + return common::GetPtrFromOptional(x.typedAssignment->v); } const evaluate::Assignment *GetAssignment( const parser::PointerAssignmentStmt &x) { - const auto &typed{x.typedAssignment}; - return typed ? &typed->v : nullptr; + CheckMissingAnalysis(!x.typedAssignment, x); + return common::GetPtrFromOptional(x.typedAssignment->v); } const Symbol *FindInterface(const Symbol &symbol) { diff --git a/flang/lib/semantics/tools.h b/flang/lib/semantics/tools.h index d857654..83741bd 100644 --- a/flang/lib/semantics/tools.h +++ b/flang/lib/semantics/tools.h @@ -226,12 +226,8 @@ bool ExprTypeKindIsDefault( const SomeExpr &expr, const SemanticsContext &context); struct GetExprHelper { - const SomeExpr *Get(const parser::Expr::TypedExpr &x) { - CHECK(x); - return x && x->v ? &*x->v : nullptr; - } - const SomeExpr *Get(const parser::Expr &x) { return Get(x.typedExpr); } - const SomeExpr *Get(const parser::Variable &x) { return Get(x.typedExpr); } + const SomeExpr *Get(const parser::Expr &); + const SomeExpr *Get(const parser::Variable &); template const SomeExpr *Get(const common::Indirection &x) { return Get(x.value()); } diff --git a/flang/tools/f18/f18.cc b/flang/tools/f18/f18.cc index f23f6e4..6e68540 100644 --- a/flang/tools/f18/f18.cc +++ b/flang/tools/f18/f18.cc @@ -172,7 +172,11 @@ static Fortran::parser::AnalyzedObjectsAsFortran asFortran{ } }, [](std::ostream &o, const Fortran::evaluate::GenericAssignmentWrapper &x) { - x.v.AsFortran(o); + if (x.v) { + x.v->AsFortran(o); + } else { + o << "(bad assignment)"; + } }, [](std::ostream &o, const Fortran::evaluate::ProcedureRef &x) { x.AsFortran(o << "CALL ");