Skip to content

Commit 13893a0

Browse files
authored
[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.
1 parent ec4ba0f commit 13893a0

File tree

2 files changed

+29
-5
lines changed

2 files changed

+29
-5
lines changed

flang/lib/Semantics/expression.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,13 +1059,35 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Substring &ss) {
10591059
const parser::SubstringRange &range{
10601060
std::get<parser::SubstringRange>(ss.t)};
10611061
std::optional<Expr<SubscriptInteger>> first{
1062-
GetSubstringBound(std::get<0>(range.t))};
1062+
Fold(GetSubstringBound(std::get<0>(range.t)))};
10631063
std::optional<Expr<SubscriptInteger>> last{
1064-
GetSubstringBound(std::get<1>(range.t))};
1064+
Fold(GetSubstringBound(std::get<1>(range.t)))};
10651065
const Symbol &symbol{checked->GetLastSymbol()};
10661066
if (std::optional<DynamicType> dynamicType{
10671067
DynamicType::From(symbol)}) {
10681068
if (dynamicType->category() == TypeCategory::Character) {
1069+
auto lbValue{ToInt64(first)};
1070+
if (!lbValue) {
1071+
lbValue = 1;
1072+
}
1073+
auto ubValue{ToInt64(last)};
1074+
auto len{dynamicType->knownLength()};
1075+
if (!ubValue) {
1076+
ubValue = len;
1077+
}
1078+
if (lbValue && ubValue && *lbValue > *ubValue) {
1079+
// valid, substring is empty
1080+
} else if (lbValue && *lbValue < 1 && (ubValue || !last)) {
1081+
Say("Substring must begin at 1 or later, not %jd"_err_en_US,
1082+
static_cast<std::intmax_t>(*lbValue));
1083+
return std::nullopt;
1084+
} else if (ubValue && len && *ubValue > *len &&
1085+
(lbValue || !first)) {
1086+
Say("Substring must end at %zd or earlier, not %jd"_err_en_US,
1087+
static_cast<std::intmax_t>(*len),
1088+
static_cast<std::intmax_t>(*ubValue));
1089+
return std::nullopt;
1090+
}
10691091
return WrapperHelper<TypeCategory::Character, Designator,
10701092
Substring>(dynamicType->kind(),
10711093
Substring{std::move(checked.value()), std::move(first),

flang/test/Semantics/data17.f90

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
! RUN: %python %S/test_errors.py %s %flang_fc1
2-
character(4) a, b, c, d, e
2+
character(4) a, b, c, d, e, f
33
!WARNING: DATA statement value '"abcde"' for 'a' has the wrong length
44
data a(1:4)/'abcde'/
55
!WARNING: DATA statement value '"abc"' for 'b' has the wrong length
66
data b(1:4)/'abc'/
77
data c/'abcde'/ ! not a substring, conforms
88
data d/'abc'/ ! not a substring, conforms
9-
!ERROR: DATA statement designator 'e(1_8:5_8)' is out of range
10-
data e(1:5)/'xyz'/
9+
!ERROR: Substring must end at 4 or earlier, not 5
10+
data e(1:5)/'abcde'/
11+
!ERROR: Substring must begin at 1 or later, not 0
12+
data f(0:4)/'abcde'/
1113
end

0 commit comments

Comments
 (0)