[flang-commits] [flang] [flang] Compile-time checking of substring bounds (PR #71453)
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Mon Nov 6 14:42:51 PST 2023
https://github.com/klausler created https://github.com/llvm/llvm-project/pull/71453
When the bounds of a substring reference are known during compilation, and are outside the valid range for the character base object, issue an error message.
>From 1b69b50a4b09bad6e6cebb903cd038b344263d2a Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Mon, 6 Nov 2023 13:57:37 -0800
Subject: [PATCH] [flang] Compile-time checking of substring bounds
When the bounds of a substring reference are known during
compilation, and are outside the valid range for the character
base object, issue an error message.
---
flang/lib/Semantics/expression.cpp | 26 ++++++++++++++++++++++++--
flang/test/Semantics/data17.f90 | 8 +++++---
2 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 367414a2b4465ce..498a480c5649425 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -1059,13 +1059,35 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Substring &ss) {
const parser::SubstringRange &range{
std::get<parser::SubstringRange>(ss.t)};
std::optional<Expr<SubscriptInteger>> first{
- GetSubstringBound(std::get<0>(range.t))};
+ Fold(GetSubstringBound(std::get<0>(range.t)))};
std::optional<Expr<SubscriptInteger>> last{
- GetSubstringBound(std::get<1>(range.t))};
+ Fold(GetSubstringBound(std::get<1>(range.t)))};
const Symbol &symbol{checked->GetLastSymbol()};
if (std::optional<DynamicType> dynamicType{
DynamicType::From(symbol)}) {
if (dynamicType->category() == TypeCategory::Character) {
+ auto lbValue{ToInt64(first)};
+ if (!lbValue) {
+ lbValue = 1;
+ }
+ auto ubValue{ToInt64(last)};
+ auto len{dynamicType->knownLength()};
+ if (!ubValue) {
+ ubValue = len;
+ }
+ if (lbValue && ubValue && *lbValue > *ubValue) {
+ // valid, substring is empty
+ } else if (lbValue && *lbValue < 1 && (ubValue || !last)) {
+ Say("Substring must begin at 1 or later, not %jd"_err_en_US,
+ static_cast<std::intmax_t>(*lbValue));
+ return std::nullopt;
+ } else if (ubValue && len && *ubValue > *len &&
+ (lbValue || !first)) {
+ Say("Substring must end at %zd or earlier, not %jd"_err_en_US,
+ static_cast<std::intmax_t>(*len),
+ static_cast<std::intmax_t>(*ubValue));
+ return std::nullopt;
+ }
return WrapperHelper<TypeCategory::Character, Designator,
Substring>(dynamicType->kind(),
Substring{std::move(checked.value()), std::move(first),
diff --git a/flang/test/Semantics/data17.f90 b/flang/test/Semantics/data17.f90
index 8ea9d785a96fb83..86f1c4c6c126950 100644
--- a/flang/test/Semantics/data17.f90
+++ b/flang/test/Semantics/data17.f90
@@ -1,11 +1,13 @@
! RUN: %python %S/test_errors.py %s %flang_fc1
-character(4) a, b, c, d, e
+character(4) a, b, c, d, e, f
!WARNING: DATA statement value '"abcde"' for 'a' has the wrong length
data a(1:4)/'abcde'/
!WARNING: DATA statement value '"abc"' for 'b' has the wrong length
data b(1:4)/'abc'/
data c/'abcde'/ ! not a substring, conforms
data d/'abc'/ ! not a substring, conforms
-!ERROR: DATA statement designator 'e(1_8:5_8)' is out of range
-data e(1:5)/'xyz'/
+!ERROR: Substring must end at 4 or earlier, not 5
+data e(1:5)/'abcde'/
+!ERROR: Substring must begin at 1 or later, not 0
+data f(0:4)/'abcde'/
end
More information about the flang-commits
mailing list