[flang] Accommodate unknowable CHARACTER length in evaluate::ArrayConstructor<>

The internal representation for array constructors in expressions during semantic
analysis needs to be able to accommodate circumstances (e.g. TRIM(), substrings)
in which the length of the elements in the array is either unknown or cannot be
represented as a context-free integer expression.

Differential Revision: https://reviews.llvm.org/D139041
This commit is contained in:
Peter Klausler 2022-10-24 10:14:03 -07:00
parent 4d6483e91b
commit 01688ee9df
5 changed files with 42 additions and 23 deletions

View File

@ -473,20 +473,20 @@ class ArrayConstructor<Type<TypeCategory::Character, KIND>>
public:
using Result = Type<TypeCategory::Character, KIND>;
using Base = ArrayConstructorValues<Result>;
CLASS_BOILERPLATE(ArrayConstructor)
ArrayConstructor(Expr<SubscriptInteger> &&len, Base &&v)
: Base{std::move(v)}, length_{std::move(len)} {}
template <typename A>
explicit ArrayConstructor(const A &prototype)
: length_{prototype.LEN().value()} {}
DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ArrayConstructor)
explicit ArrayConstructor(Base &&values) : Base{std::move(values)} {}
template <typename T> explicit ArrayConstructor(const Expr<T> &) {}
ArrayConstructor &set_LEN(Expr<SubscriptInteger> &&);
bool operator==(const ArrayConstructor &) const;
static constexpr Result result() { return Result{}; }
static constexpr DynamicType GetType() { return Result::GetType(); }
llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
const Expr<SubscriptInteger> &LEN() const { return length_.value(); }
const Expr<SubscriptInteger> *LEN() const {
return length_ ? &length_->value() : nullptr;
}
private:
common::CopyableIndirection<Expr<SubscriptInteger>> length_;
std::optional<common::CopyableIndirection<Expr<SubscriptInteger>>> length_;
};
template <>

View File

@ -35,7 +35,13 @@ Expr<Type<TypeCategory::Character, KIND>>::LEN() const {
[](const Constant<Result> &c) -> T {
return AsExpr(Constant<SubscriptInteger>{c.LEN()});
},
[](const ArrayConstructor<Result> &a) -> T { return a.LEN(); },
[](const ArrayConstructor<Result> &a) -> T {
if (const auto *len{a.LEN()}) {
return T{*len};
} else {
return std::nullopt;
}
},
[](const Parentheses<Result> &x) { return x.left().LEN(); },
[](const Convert<Result> &x) {
return common::visit(
@ -142,6 +148,13 @@ bool ArrayConstructorValues<R>::operator==(
return values_ == that.values_;
}
template <int KIND>
auto ArrayConstructor<Type<TypeCategory::Character, KIND>>::set_LEN(
Expr<SubscriptInteger> &&len) -> ArrayConstructor & {
length_.emplace(std::move(len));
return *this;
}
template <int KIND>
bool ArrayConstructor<Type<TypeCategory::Character, KIND>>::operator==(
const ArrayConstructor &that) const {

View File

@ -1171,10 +1171,12 @@ public:
return Expr<T>{Constant<T>{array.GetType().GetDerivedTypeSpec(),
std::move(elements_), ConstantSubscripts{n}}};
} else if constexpr (T::category == TypeCategory::Character) {
auto length{Fold(context_, common::Clone(array.LEN()))};
if (std::optional<ConstantSubscript> lengthValue{ToInt64(length)}) {
return Expr<T>{Constant<T>{
*lengthValue, std::move(elements_), ConstantSubscripts{n}}};
if (const auto *len{array.LEN()}) {
auto length{Fold(context_, common::Clone(*len))};
if (std::optional<ConstantSubscript> lengthValue{ToInt64(length)}) {
return Expr<T>{Constant<T>{
*lengthValue, std::move(elements_), ConstantSubscripts{n}}};
}
}
} else {
return Expr<T>{
@ -1371,12 +1373,13 @@ std::optional<Expr<RESULT>> MapOperation(FoldingContext &context,
template <typename RESULT, typename A>
ArrayConstructor<RESULT> ArrayConstructorFromMold(
const A &prototype, std::optional<Expr<SubscriptInteger>> &&length) {
ArrayConstructor<RESULT> result{prototype};
if constexpr (RESULT::category == TypeCategory::Character) {
return ArrayConstructor<RESULT>{
std::move(length.value()), ArrayConstructorValues<RESULT>{}};
} else {
return ArrayConstructor<RESULT>{prototype};
if (length) {
result.set_LEN(std::move(*length));
}
}
return result;
}
// array * array case

View File

@ -421,7 +421,10 @@ template <int KIND>
llvm::raw_ostream &
ArrayConstructor<Type<TypeCategory::Character, KIND>>::AsFortran(
llvm::raw_ostream &o) const {
o << '[' << GetType().AsFortran(LEN().AsFortran()) << "::";
o << '[';
if (const auto *len{LEN()}) {
o << GetType().AsFortran(len->AsFortran()) << "::";
}
EmitArray(o, *this);
return o << ']';
}

View File

@ -1343,15 +1343,15 @@ public:
MakeSpecific<T>(std::move(values_))});
}
} else if (type_->kind() == T::kind) {
ArrayConstructor<T> result{MakeSpecific<T>(std::move(values_))};
if constexpr (T::category == TypeCategory::Character) {
if (auto len{type_->LEN()}) {
return AsMaybeExpr(ArrayConstructor<T>{
*std::move(len), MakeSpecific<T>(std::move(values_))});
if (IsConstantExpr(*len)) {
result.set_LEN(std::move(*len));
}
}
} else {
return AsMaybeExpr(
ArrayConstructor<T>{MakeSpecific<T>(std::move(values_))});
}
return AsMaybeExpr(std::move(result));
}
}
return std::nullopt;