From 84a099df05320bf7a3c5d97bcc51d53012f24667 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Fri, 27 Mar 2020 14:17:25 -0700 Subject: [PATCH] [flang] Fix missing substring bounds (bug flang-compiler/f18#1091) Original-commit: flang-compiler/f18@3b0c150b2e4d194cb5a46b40f41b3be59ef5fa51 Reviewed-on: https://github.com/flang-compiler/f18/pull/1093 --- flang/include/flang/Evaluate/tools.h | 201 ++++++++++++++------------- flang/lib/Evaluate/tools.cpp | 40 +++--- flang/lib/Semantics/assignment.cpp | 18 +-- flang/lib/Semantics/expression.cpp | 138 ++++++++++-------- flang/lib/Semantics/tools.cpp | 49 ++++--- 5 files changed, 240 insertions(+), 206 deletions(-) diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h index 2d2a46fc3eb1..d14827377b22 100644 --- a/flang/include/flang/Evaluate/tools.h +++ b/flang/include/flang/Evaluate/tools.h @@ -31,7 +31,7 @@ namespace Fortran::evaluate { // When an Expr holds something that is a Variable (i.e., a Designator // or pointer-valued FunctionRef), return a copy of its contents in // a Variable. -template +template std::optional> AsVariable(const Expr &expr) { using Variant = decltype(Variable::u); return std::visit( @@ -44,7 +44,7 @@ std::optional> AsVariable(const Expr &expr) { expr.u); } -template +template std::optional> AsVariable(const std::optional> &expr) { if (expr) { return AsVariable(*expr); @@ -58,8 +58,8 @@ std::optional> AsVariable(const std::optional> &expr) { // pointer is a "variable" in Fortran (it can be the left-hand side of // an assignment). struct IsVariableHelper - : public AnyTraverse> { - using Result = std::optional; // effectively tri-state + : public AnyTraverse> { + using Result = std::optional; // effectively tri-state using Base = AnyTraverse; IsVariableHelper() : Base{*this} {} using Base::operator(); @@ -71,7 +71,7 @@ struct IsVariableHelper Result operator()(const CoarrayRef &) const { return true; } Result operator()(const ComplexPart &) const { return true; } Result operator()(const ProcedureDesignator &) const; - template Result operator()(const Expr &x) const { + template Result operator()(const Expr &x) const { if constexpr (common::HasMember || std::is_same_v) { // Expression with a specific type @@ -88,7 +88,7 @@ struct IsVariableHelper } }; -template bool IsVariable(const A &x) { +template bool IsVariable(const A &x) { if (auto known{IsVariableHelper{}(x)}) { return *known; } else { @@ -99,39 +99,39 @@ template bool IsVariable(const A &x) { // Predicate: true when an expression is assumed-rank bool IsAssumedRank(const Symbol &); bool IsAssumedRank(const ActualArgument &); -template bool IsAssumedRank(const A &) { return false; } -template bool IsAssumedRank(const Designator &designator) { +template bool IsAssumedRank(const A &) { return false; } +template bool IsAssumedRank(const Designator &designator) { if (const auto *symbol{std::get_if(&designator.u)}) { return IsAssumedRank(symbol->get()); } else { return false; } } -template bool IsAssumedRank(const Expr &expr) { +template bool IsAssumedRank(const Expr &expr) { return std::visit([](const auto &x) { return IsAssumedRank(x); }, expr.u); } -template bool IsAssumedRank(const std::optional &x) { +template bool IsAssumedRank(const std::optional &x) { return x && IsAssumedRank(*x); } // Generalizing packagers: these take operations and expressions of more // specific types and wrap them in Expr<> containers of more abstract types. -template common::IfNoLvalue>, A> AsExpr(A &&x) { +template common::IfNoLvalue>, A> AsExpr(A &&x) { return Expr>{std::move(x)}; } -template Expr AsExpr(Expr &&x) { +template Expr AsExpr(Expr &&x) { static_assert(IsSpecificIntrinsicType); return std::move(x); } -template +template Expr> AsCategoryExpr(Expr> &&x) { return std::move(x); } -template +template common::IfNoLvalue, A> AsGenericExpr(A &&x) { if constexpr (common::HasMember) { return Expr{std::move(x)}; @@ -140,7 +140,7 @@ common::IfNoLvalue, A> AsGenericExpr(A &&x) { } } -template +template common::IfNoLvalue::category>>, A> AsCategoryExpr( A &&x) { return Expr::category>>{AsExpr(std::move(x))}; @@ -153,13 +153,13 @@ Expr Parenthesize(Expr &&); Expr GetComplexPart( const Expr &, bool isImaginary = false); -template +template Expr MakeComplex(Expr> &&re, Expr> &&im) { return AsCategoryExpr(ComplexConstructor{std::move(re), std::move(im)}); } -template constexpr bool IsNumericCategoryExpr() { +template constexpr bool IsNumericCategoryExpr() { if constexpr (common::HasMember) { return false; } else { @@ -170,7 +170,7 @@ template constexpr bool IsNumericCategoryExpr() { // Specializing extractor. If an Expr wraps some type of object, perhaps // in several layers, return a pointer to it; otherwise null. Also works // with expressions contained in ActualArgument. -template +template auto UnwrapExpr(B &x) -> common::Constify * { using Ty = std::decay_t; if constexpr (std::is_same_v) { @@ -190,7 +190,7 @@ auto UnwrapExpr(B &x) -> common::Constify * { return nullptr; } -template +template const A *UnwrapExpr(const std::optional &x) { if (x) { return UnwrapExpr(*x); @@ -199,7 +199,7 @@ const A *UnwrapExpr(const std::optional &x) { } } -template A *UnwrapExpr(std::optional &x) { +template A *UnwrapExpr(std::optional &x) { if (x) { return UnwrapExpr(*x); } else { @@ -208,41 +208,52 @@ template A *UnwrapExpr(std::optional &x) { } // If an expression simply wraps a DataRef, extract and return it. -template -common::IfNoLvalue, A> ExtractDataRef(const A &) { - return std::nullopt; // default base case +// The Boolean argument controls the handling of Substring +// references: when true (not default), it extracts the base DataRef +// of a substring, if it has one. +template +common::IfNoLvalue, A> ExtractDataRef( + const A &, bool intoSubstring) { + return std::nullopt; // default base case } -template -std::optional ExtractDataRef(const Designator &d) { +template +std::optional ExtractDataRef( + const Designator &d, bool intoSubstring = false) { return std::visit( - [](const auto &x) -> std::optional { + [=](const auto &x) -> std::optional { if constexpr (common::HasMember) { return DataRef{x}; } if constexpr (std::is_same_v, Substring>) { - return ExtractDataRef(x); + if (intoSubstring) { + return ExtractSubstringBase(x); + } } - return std::nullopt; // w/o "else" to dodge bogus g++ 8.1 warning + return std::nullopt; // w/o "else" to dodge bogus g++ 8.1 warning }, d.u); } -template -std::optional ExtractDataRef(const Expr &expr) { - return std::visit([](const auto &x) { return ExtractDataRef(x); }, expr.u); +template +std::optional ExtractDataRef( + const Expr &expr, bool intoSubstring = false) { + return std::visit( + [=](const auto &x) { return ExtractDataRef(x, intoSubstring); }, expr.u); } -template -std::optional ExtractDataRef(const std::optional &x) { +template +std::optional ExtractDataRef( + const std::optional &x, bool intoSubstring = false) { if (x) { - return ExtractDataRef(*x); + return ExtractDataRef(*x, intoSubstring); } else { return std::nullopt; } } -std::optional ExtractDataRef(const Substring &); +std::optional ExtractSubstringBase(const Substring &); // Predicate: is an expression is an array element reference? -template bool IsArrayElement(const Expr &expr) { - if (auto dataRef{ExtractDataRef(expr)}) { +template +bool IsArrayElement(const Expr &expr, bool intoSubstring = false) { + if (auto dataRef{ExtractDataRef(expr, intoSubstring)}) { const DataRef *ref{&*dataRef}; while (const Component * component{std::get_if(&ref->u)}) { ref = &component->base(); @@ -253,8 +264,9 @@ template bool IsArrayElement(const Expr &expr) { } } -template std::optional ExtractNamedEntity(const A &x) { - if (auto dataRef{ExtractDataRef(x)}) { +template +std::optional ExtractNamedEntity(const A &x) { + if (auto dataRef{ExtractDataRef(x, true)}) { return std::visit( common::visitors{ [](SymbolRef &&symbol) -> std::optional { @@ -275,11 +287,11 @@ template std::optional ExtractNamedEntity(const A &x) { } struct ExtractCoindexedObjectHelper { - template std::optional operator()(const A &) const { + template std::optional operator()(const A &) const { return std::nullopt; } std::optional operator()(const CoarrayRef &x) const { return x; } - template + template std::optional operator()(const Expr &expr) const { return std::visit(*this, expr.u); } @@ -309,8 +321,8 @@ struct ExtractCoindexedObjectHelper { } }; -template std::optional ExtractCoarrayRef(const A &x) { - if (auto dataRef{ExtractDataRef(x)}) { +template std::optional ExtractCoarrayRef(const A &x) { + if (auto dataRef{ExtractDataRef(x, true)}) { return ExtractCoindexedObjectHelper{}(*dataRef); } else { return ExtractCoindexedObjectHelper{}(x); @@ -319,7 +331,7 @@ template std::optional ExtractCoarrayRef(const A &x) { // If an expression is simply a whole symbol data designator, // extract and return that symbol, else null. -template const Symbol *UnwrapWholeSymbolDataRef(const A &x) { +template const Symbol *UnwrapWholeSymbolDataRef(const A &x) { if (auto dataRef{ExtractDataRef(x)}) { if (const SymbolRef * p{std::get_if(&dataRef->u)}) { return &p->get(); @@ -329,8 +341,8 @@ template const Symbol *UnwrapWholeSymbolDataRef(const A &x) { } // GetFirstSymbol(A%B%C[I]%D) -> A -template const Symbol *GetFirstSymbol(const A &x) { - if (auto dataRef{ExtractDataRef(x)}) { +template const Symbol *GetFirstSymbol(const A &x) { + if (auto dataRef{ExtractDataRef(x, true)}) { return &dataRef->GetFirstSymbol(); } else { return nullptr; @@ -341,7 +353,7 @@ template const Symbol *GetFirstSymbol(const A &x) { // specific intrinsic type with ConvertToType(x) or by converting // one arbitrary expression to the type of another with ConvertTo(to, from). -template +template Expr ConvertToType(Expr> &&x) { static_assert(IsSpecificIntrinsicType); if constexpr (FROMCAT != TO::category) { @@ -390,12 +402,12 @@ Expr ConvertToType(Expr> &&x) { } } -template +template Expr ConvertToType(Expr> &&x) { return ConvertToType(Expr>{std::move(x)}); } -template Expr ConvertToType(BOZLiteralConstant &&x) { +template Expr ConvertToType(BOZLiteralConstant &&x) { static_assert(IsSpecificIntrinsicType); if constexpr (TO::category == TypeCategory::Integer) { return Expr{ @@ -418,13 +430,13 @@ std::optional> ConvertToType( const Symbol &, std::optional> &&); // Conversions to the type of another expression -template +template common::IfNoLvalue>, FROM> ConvertTo( const Expr> &, FROM &&x) { return ConvertToType>(std::move(x)); } -template +template common::IfNoLvalue>, FROM> ConvertTo( const Expr> &to, FROM &&from) { return std::visit( @@ -436,7 +448,7 @@ common::IfNoLvalue>, FROM> ConvertTo( to.u); } -template +template common::IfNoLvalue, FROM> ConvertTo( const Expr &to, FROM &&from) { return std::visit( @@ -448,11 +460,11 @@ common::IfNoLvalue, FROM> ConvertTo( // Convert an expression of some known category to a dynamically chosen // kind of some category (usually but not necessarily distinct). -template struct ConvertToKindHelper { +template struct ConvertToKindHelper { using Result = std::optional>>; using Types = CategoryTypes; ConvertToKindHelper(int k, VALUE &&x) : kind{k}, value{std::move(x)} {} - template Result Test() { + template Result Test() { if (kind == T::kind) { return std::make_optional( AsCategoryExpr(ConvertToType(std::move(value)))); @@ -463,7 +475,7 @@ template struct ConvertToKindHelper { VALUE value; }; -template +template common::IfNoLvalue>, VALUE> ConvertToKind( int kind, VALUE &&x) { return common::SearchTypes( @@ -474,11 +486,11 @@ common::IfNoLvalue>, VALUE> ConvertToKind( // Given a type category CAT, SameKindExprs is a variant that // holds an arrays of expressions of the same supported kind in that // category. -template using SameExprs = std::array, N>; -template struct SameKindExprsHelper { - template using SameExprs = std::array, N>; +template using SameExprs = std::array, N>; +template struct SameKindExprsHelper { + template using SameExprs = std::array, N>; }; -template +template using SameKindExprs = common::MapTemplate::template SameExprs, CategoryTypes>; @@ -486,7 +498,7 @@ using SameKindExprs = // Given references to two expressions of arbitrary kind in the same type // category, convert one to the kind of the other when it has the smaller kind, // then return them in a type-safe package. -template +template SameKindExprs AsSameKindExprs( Expr> &&x, Expr> &&y) { return std::visit( @@ -528,7 +540,7 @@ std::optional> ConstructComplex(parser::ContextualMessages &, std::optional> &&, std::optional> &&, int defaultRealKind); -template Expr> ScalarConstantToExpr(const A &x) { +template Expr> ScalarConstantToExpr(const A &x) { using Ty = TypeOf; static_assert( std::is_same_v, std::decay_t>, "TypeOf<> is broken"); @@ -538,7 +550,7 @@ template Expr> ScalarConstantToExpr(const A &x) { // Combine two expressions of the same specific numeric type with an operation // to produce a new expression. Implements piecewise addition and subtraction // for COMPLEX. -template class OPR, typename SPECIFIC> +template