-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[flang] Fold character array constructor with unknown length #123983
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
When a character array constructor does not have an explicit type with a constant length, the compiler can still fold it if all of its elements are constants. These array constructors will have been wrapped up in the internal %SET_LENGTH operation, which will determine the final length of the folded value, so use the maximum length of the constant elements as the length of the folded array constructor. Fixes llvm#123766.
@llvm/pr-subscribers-flang-semantics Author: Peter Klausler (klausler) ChangesWhen a character array constructor does not have an explicit type with a constant length, the compiler can still fold it if all of its elements are constants. These array constructors will have been wrapped up in the internal %SET_LENGTH operation, which will determine the final length of the folded value, so use the maximum length of the constant elements as the length of the folded array constructor. Fixes #123766. Full diff: https://github.com/llvm/llvm-project/pull/123983.diff 2 Files Affected:
diff --git a/flang/lib/Evaluate/fold-implementation.h b/flang/lib/Evaluate/fold-implementation.h
index 31d043f490fd85..56b36504c1dffd 100644
--- a/flang/lib/Evaluate/fold-implementation.h
+++ b/flang/lib/Evaluate/fold-implementation.h
@@ -1263,6 +1263,12 @@ template <typename T> class ArrayConstructorFolder {
explicit ArrayConstructorFolder(FoldingContext &c) : context_{c} {}
Expr<T> FoldArray(ArrayConstructor<T> &&array) {
+ if constexpr (T::category == TypeCategory::Character) {
+ if (const auto *len{array.LEN()}) {
+ charLength_ = ToInt64(Fold(context_, common::Clone(*len)));
+ knownCharLength_ = charLength_.has_value();
+ }
+ }
// Calls FoldArray(const ArrayConstructorValues<T> &) below
if (FoldArray(array)) {
auto n{static_cast<ConstantSubscript>(elements_.size())};
@@ -1270,12 +1276,9 @@ template <typename T> class ArrayConstructorFolder {
return Expr<T>{Constant<T>{array.GetType().GetDerivedTypeSpec(),
std::move(elements_), ConstantSubscripts{n}}};
} else if constexpr (T::category == TypeCategory::Character) {
- 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}}};
- }
+ if (charLength_) {
+ return Expr<T>{Constant<T>{
+ *charLength_, std::move(elements_), ConstantSubscripts{n}}};
}
} else {
return Expr<T>{
@@ -1296,6 +1299,11 @@ template <typename T> class ArrayConstructorFolder {
elements_.emplace_back(c->At(index));
} while (c->IncrementSubscripts(index));
}
+ if constexpr (T::category == TypeCategory::Character) {
+ if (!knownCharLength_) {
+ charLength_ = std::max(c->LEN(), charLength_.value_or(-1));
+ }
+ }
return true;
} else {
return false;
@@ -1345,6 +1353,8 @@ template <typename T> class ArrayConstructorFolder {
FoldingContext &context_;
std::vector<Scalar<T>> elements_;
+ std::optional<ConstantSubscript> charLength_;
+ bool knownCharLength_{false};
};
template <typename T>
diff --git a/flang/test/Evaluate/bug123766.f90 b/flang/test/Evaluate/bug123766.f90
new file mode 100644
index 00000000000000..b58989e6c26d85
--- /dev/null
+++ b/flang/test/Evaluate/bug123766.f90
@@ -0,0 +1,5 @@
+! RUN: %python %S/test_folding.py %s %flang_fc1
+character(10), parameter :: a = '0123456789'
+character(3), parameter :: arr(3) = [(a(1:i), i=1,3)]
+logical, parameter :: test1 = all(arr == ["0", "01", "012"])
+end
|
@@ -1345,6 +1353,8 @@ template <typename T> class ArrayConstructorFolder { | |||
|
|||
FoldingContext &context_; | |||
std::vector<Scalar<T>> elements_; | |||
std::optional<ConstantSubscript> charLength_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be the case, when knownCharLength_
is false, but charLengh_
has value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
knownCharLength_
is set true if and only if the character array constructor has an explicit length (from an explicit type specifier); in this case, the known length is dispositive and the element lengths don't matter. Otherwise, charLength_
can change when longer elements are encountered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Thanks for the quick fix!
When a character array constructor does not have an explicit type with a constant length, the compiler can still fold it if all of its elements are constants. These array constructors will have been wrapped up in the internal %SET_LENGTH operation, which will determine the final length of the folded value, so use the maximum length of the constant elements as the length of the folded array constructor.
Fixes #123766.