[flang] Add analyzed assignment to parse tree

Add `typedAssignment` to the `AssignmentStmt` node, analagous to
`typedExpr` in `Expr`. This represents the analyzed form of an assignment.
It may be a subroutine call in the case of a user-defined assignment.
Add `GetAssignment` function to get it from the parse tree node if present.

Original-commit: flang-compiler/f18@675b0b9bb7
Reviewed-on: https://github.com/flang-compiler/f18/pull/841
Tree-same-pre-rewrite: false
This commit is contained in:
Tim Keith 2019-11-22 16:04:56 -08:00
parent e67f6a775e
commit ddb4f259f6
7 changed files with 45 additions and 0 deletions

View File

@ -175,6 +175,8 @@ bool GenericExprWrapper::operator==(const GenericExprWrapper &that) const {
return v == that.v;
}
GenericAssignmentWrapper::~GenericAssignmentWrapper() = default;
template<TypeCategory CAT> int Expr<SomeKind<CAT>>::GetKind() const {
return std::visit(
[](const auto &kx) { return std::decay_t<decltype(kx)>::Result::kind; },
@ -194,3 +196,4 @@ std::optional<Expr<SubscriptInteger>> Expr<SomeCharacter>::LEN() const {
INSTANTIATE_EXPRESSION_TEMPLATES
}
DEFINE_DELETER(Fortran::evaluate::GenericExprWrapper)
DEFINE_DELETER(Fortran::evaluate::GenericAssignmentWrapper)

View File

@ -854,6 +854,21 @@ public:
common::CombineVariants<TypelessExpression, CategoryExpression> u;
};
// An assignment is either intrinsic (with lhs and rhs) or user-defined,
// represented as a ProcedureRef.
class Assignment {
public:
explicit Assignment(ProcedureRef &&x) : u{std::move(x)} {}
Assignment(Expr<SomeType> &&lhs, Expr<SomeType> &&rhs)
: u{IntrinsicAssignment{std::move(lhs), std::move(rhs)}} {}
struct IntrinsicAssignment {
Expr<SomeType> lhs;
Expr<SomeType> rhs;
};
std::variant<IntrinsicAssignment, ProcedureRef> u;
};
// This wrapper class is used, by means of a forward reference with
// an owning pointer, to cache analyzed expressions in parse tree nodes.
// v is nullopt if an error occurred during expression analysis.
@ -864,6 +879,13 @@ struct GenericExprWrapper {
std::optional<Expr<SomeType>> v;
};
// Like GenericExprWrapper but for analyzed assignments
struct GenericAssignmentWrapper {
GenericAssignmentWrapper(std::optional<Assignment> &&x) : v{std::move(x)} {}
~GenericAssignmentWrapper();
std::optional<Assignment> v;
};
FOR_EACH_CATEGORY_TYPE(extern template class Expr, )
FOR_EACH_TYPE_AND_KIND(extern template class ExpressionBase, )
FOR_EACH_INTRINSIC_KIND(extern template class ArrayConstructorValues, )

View File

@ -23,6 +23,9 @@ namespace Fortran::evaluate {
struct GenericExprWrapper {
~GenericExprWrapper();
};
struct GenericAssignmentWrapper {
~GenericAssignmentWrapper();
};
}
namespace Fortran::parser {
@ -248,3 +251,4 @@ std::ostream &operator<<(std::ostream &os, const Name &x) {
}
template class std::unique_ptr<Fortran::evaluate::GenericExprWrapper>;
template class std::unique_ptr<Fortran::evaluate::GenericAssignmentWrapper>;

View File

@ -70,6 +70,7 @@ class DerivedTypeSpec;
// type-checked generic expression representations by semantic analysis.
namespace Fortran::evaluate {
struct GenericExprWrapper; // forward definition, wraps Expr<SomeType>
struct GenericAssignmentWrapper; // forward definition, represent assignment
}
// Most non-template classes in this file use these default definitions
@ -1918,6 +1919,9 @@ struct DeallocateStmt {
// R1032 assignment-stmt -> variable = expr
struct AssignmentStmt {
TUPLE_CLASS_BOILERPLATE(AssignmentStmt);
using TypedAssignment = std::unique_ptr<evaluate::GenericAssignmentWrapper,
common::Deleter<evaluate::GenericAssignmentWrapper>>;
mutable TypedAssignment typedAssignment;
std::tuple<Variable, Expr> t;
};

View File

@ -315,6 +315,11 @@ bool ExprTypeKindIsDefault(
dynamicType->kind() == context.GetDefaultKind(dynamicType->category());
}
const evaluate::Assignment *GetAssignment(const parser::AssignmentStmt &x) {
const auto &typed{x.typedAssignment};
return typed && typed->v ? &*typed->v : nullptr;
}
const Symbol *FindInterface(const Symbol &symbol) {
return std::visit(
common::visitors{

View File

@ -241,6 +241,8 @@ template<typename T> const SomeExpr *GetExpr(const T &x) {
return GetExprHelper{}.Get(x);
}
const evaluate::Assignment *GetAssignment(const parser::AssignmentStmt &);
template<typename T> std::optional<std::int64_t> GetIntValue(const T &x) {
if (const auto *expr{GetExpr(x)}) {
return evaluate::ToInt64(*expr);

View File

@ -24,6 +24,11 @@ struct GenericExprWrapper {
~GenericExprWrapper();
};
GenericExprWrapper::~GenericExprWrapper() = default;
struct GenericAssignmentWrapper {
~GenericAssignmentWrapper();
};
GenericAssignmentWrapper::~GenericAssignmentWrapper() = default;
}
DEFINE_DELETER(Fortran::evaluate::GenericExprWrapper)
DEFINE_DELETER(Fortran::evaluate::GenericAssignmentWrapper)