[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