[flang-commits] [flang] 13893a0 - [flang] Compile-time checking of substring bounds (#71453)

via flang-commits flang-commits at lists.llvm.org
Mon Nov 13 15:03:21 PST 2023


Author: Peter Klausler
Date: 2023-11-13T15:03:17-08:00
New Revision: 13893a08d91313900857be494ee4702a4f0847af

URL: https://github.com/llvm/llvm-project/commit/13893a08d91313900857be494ee4702a4f0847af
DIFF: https://github.com/llvm/llvm-project/commit/13893a08d91313900857be494ee4702a4f0847af.diff

LOG: [flang] Compile-time checking of substring bounds (#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.

Added: 
    

Modified: 
    flang/lib/Semantics/expression.cpp
    flang/test/Semantics/data17.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index eead0f4787f923c..9aec60304a26c8d 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