[flang] Redo IsInitialDataTarget

Original-commit: flang-compiler/f18@988c38e1f5
Reviewed-on: https://github.com/flang-compiler/f18/pull/755
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-09-18 16:47:25 -07:00
parent 0bc6d134a6
commit e6e66c022b
2 changed files with 92 additions and 74 deletions

View File

@ -79,82 +79,66 @@ bool IsConstantExpr(const Expr<SomeType> &expr) {
// data address used to initialize a pointer with "=> x". See C765.
// The caller is responsible for checking the base object symbol's
// characteristics (TARGET, SAVE, &c.) since this code can't use GetUltimate().
template<typename A> bool IsInitialDataTarget(const A &) { return false; }
template<typename... A> bool IsInitialDataTarget(const std::variant<A...> &);
bool IsInitialDataTarget(const DataRef &);
template<typename T> bool IsInitialDataTarget(const Expr<T> &);
bool IsInitialDataTarget(const semantics::Symbol &) { return true; }
bool IsInitialDataTarget(const semantics::Symbol *s) {
return IsInitialDataTarget(*s);
}
bool IsInitialDataTarget(const Component &x) {
return IsInitialDataTarget(x.base());
}
bool IsInitialDataTarget(const NamedEntity &x) {
if (const Component * c{x.UnwrapComponent()}) {
return IsInitialDataTarget(*c);
} else {
return IsInitialDataTarget(x.GetLastSymbol());
struct IsInitialDataTargetHelper
: public PredicateTraverse<IsInitialDataTargetHelper, false, true> {
using Base = PredicateTraverse<IsInitialDataTargetHelper, false, true>;
using Base::operator();
IsInitialDataTargetHelper() : Base{*this} {}
bool operator()(const BOZLiteralConstant &) const { return false; }
bool operator()(const NullPointer &) const { return true; }
template<typename T> bool operator()(const Constant<T> &) const {
return false;
}
}
bool IsInitialDataTarget(const Triplet &x) {
if (auto lower{x.lower()}) {
if (!IsConstantExpr(*lower)) {
return false;
}
bool operator()(const semantics::Symbol &) const { return true; }
bool operator()(const StaticDataObject &) const { return false; }
template<int KIND> bool operator()(const TypeParamInquiry<KIND> &) const {
return false;
}
if (auto upper{x.upper()}) {
if (!IsConstantExpr(*upper)) {
return false;
}
bool operator()(const Triplet &x) const {
return IsConstantExpr(x.lower()) && IsConstantExpr(x.upper()) &&
IsConstantExpr(x.stride());
}
return IsConstantExpr(x.stride());
}
bool IsInitialDataTarget(const Subscript &x) {
return std::visit(
common::visitors{
[](const Triplet &t) { return IsInitialDataTarget(t); },
[&](const auto &y) {
return y.value().Rank() == 0 && IsConstantExpr(y.value());
},
},
x.u);
}
bool IsInitialDataTarget(const ArrayRef &x) {
for (const Subscript &ss : x.subscript()) {
if (!IsInitialDataTarget(ss)) {
return false;
}
bool operator()(const Subscript &x) const {
return std::visit(
common::visitors{
[&](const Triplet &t) { return (*this)(t); },
[&](const auto &y) {
return y.value().Rank() == 0 && IsConstantExpr(y.value());
},
},
x.u);
}
return IsInitialDataTarget(x.base());
}
bool IsInitialDataTarget(const DataRef &x) { return IsInitialDataTarget(x.u); }
bool IsInitialDataTarget(const Substring &x) {
return IsConstantExpr(x.lower()) && IsConstantExpr(x.upper());
}
bool IsInitialDataTarget(const ComplexPart &x) {
return IsInitialDataTarget(x.complex());
}
template<typename T> bool IsInitialDataTarget(const Designator<T> &x) {
return IsInitialDataTarget(x.u);
}
bool IsInitialDataTarget(const NullPointer &) { return true; }
template<typename T> bool IsInitialDataTarget(const Expr<T> &x) {
return IsInitialDataTarget(x.u);
}
template<typename... A> bool IsInitialDataTarget(const std::variant<A...> &u) {
return std::visit([](const auto &x) { return IsInitialDataTarget(x); }, u);
}
bool operator()(const CoarrayRef &) const { return false; }
bool operator()(const Substring &x) const {
return IsConstantExpr(x.lower()) && IsConstantExpr(x.upper()) &&
(*this)(x.parent());
}
bool operator()(const DescriptorInquiry &) const { return false; }
template<typename T> bool operator()(const ArrayConstructor<T> &) const {
return false;
}
bool operator()(const StructureConstructor &) const { return false; }
template<typename T> bool operator()(const FunctionRef<T> &) { return false; }
template<typename D, typename R, typename... O>
bool operator()(const Operation<D, R, O...> &) const {
return false;
}
template<typename T> bool operator()(const Parentheses<T> &x) const {
return (*this)(x.left());
}
bool operator()(const Relational<SomeType> &) const { return false; }
};
bool IsInitialDataTarget(const Expr<SomeType> &x) {
return IsInitialDataTarget(x.u);
return IsInitialDataTargetHelper{}(x);
}
// Specification expression validation (10.1.11(2), C1010)
class CheckSpecificationExprHelper
: public PredicateTraverse<CheckSpecificationExprHelper> {
: public PredicateTraverse<CheckSpecificationExprHelper, true, true> {
public:
using Base = PredicateTraverse<CheckSpecificationExprHelper>;
using Base = PredicateTraverse<CheckSpecificationExprHelper, true, true>;
using Base::operator();
explicit CheckSpecificationExprHelper(std::string &why)
@ -245,9 +229,9 @@ void CheckSpecificationExpr(const A &x, parser::ContextualMessages &messages) {
if (!why.empty()) {
why = " ("s + why + ')';
}
messages.Say(
"The expression (%s) cannot be used as a "
"specification expression%s"_err_en_US, ss.str(), why);
messages.Say("The expression (%s) cannot be used as a "
"specification expression%s"_err_en_US,
ss.str(), why);
}
}
@ -256,5 +240,6 @@ template void CheckSpecificationExpr(
template void CheckSpecificationExpr(
const std::optional<Expr<SomeInteger>> &, parser::ContextualMessages &);
template void CheckSpecificationExpr(
const std::optional<Expr<SubscriptInteger>> &, parser::ContextualMessages &);
const std::optional<Expr<SubscriptInteger>> &,
parser::ContextualMessages &);
}

View File

@ -15,7 +15,28 @@
#ifndef FORTRAN_EVALUATE_TRAVERSE_H_
#define FORTRAN_EVALUATE_TRAVERSE_H_
// TODO pmk documentation
// A utility for scanning all of the constituent objects in an Expr<>
// expression representation with a sheaf of mutually-recursive functions.
//
// The class template Traverse<> below implements a function object that
// can handle every type that can appear in or around an Expr<>.
// Each of its overloads for operator() should be viewed as a *default*
// handler that can be overridden by the client. These default handlers
// simply forward the constituents of the argument to the client's
// visitor function object.
//
// The client (Visitor) of Traverse<Visitor,Result> must define:
// - a data member "defaultResult"
// - a member function Combine() that merges two Result values
// - a default "template<typename A> Result operator()(const A &x) const"
// handler that reflects back into Traverse<Visitor,Result>
// - overrides for "Result operator()"
//
// Predicates are made a little easier with the PredicateTraverse<>
// class template, which encapsulates most of the client
// boilerplate.
//
// See CheckSpecificationExpr() in check-expression.cc for an example client.
#include "expression.h"
#include "../semantics/symbol.h"
@ -122,6 +143,9 @@ public:
}
// Calls
Result operator()(const SpecificIntrinsic &) const {
return visitor_.defaultResult;
}
Result operator()(const ProcedureDesignator &x) const {
if (const Component * component{x.GetComponent()}) {
return visitor_(*component);
@ -219,13 +243,22 @@ private:
Visitor &visitor_;
};
template<typename Visitor> class PredicateTraverse {
template<typename Visitor, bool DEFAULT = true, bool AND = true>
class PredicateTraverse {
public:
explicit PredicateTraverse(Visitor &v) : traverse_{v} {}
static constexpr bool defaultResult{true};
static constexpr bool Combine(bool x, bool y) { return x && y; }
static constexpr bool defaultResult{DEFAULT};
static constexpr bool Combine(bool x, bool y) {
if constexpr (AND) {
return x && y;
} else {
return x || y;
}
}
template<typename A> bool operator()(const A &x) { return traverse_(x); }
template<typename A> bool operator()(const A &x) const {
return traverse_(x);
}
private:
Traverse<Visitor> traverse_;