Skip to content

Commit a0a1f51

Browse files
committed
[flang] Perform definability checks on LHS of assignment
If the pure context check succeeds, call `WhyNotModifiable` to verify the LHS can be modified. Detect assignment to whole assumed-size array. Change `IsVariable` to return false for a parameter or a component or array reference whose base it a parameter. When analyzing an assignment statement, report an error if the LHS is a constant expression. Otherwise it might get folded and when we detect the problem later the error will be confusing. Handle Substring on LHS of assignment. Change ExtractDataRef and IsVariable to work on a Substring. Fix IsImpliedShape and IsAssumedSize predicates in ArraySpec. Fix C709 check in check-declarations.cpp. Original-commit: flang-compiler/f18@f2d2657 Reviewed-on: flang-compiler/f18#1050
1 parent c97e1c0 commit a0a1f51

File tree

9 files changed

+178
-17
lines changed

9 files changed

+178
-17
lines changed

flang/include/flang/Evaluate/tools.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,10 @@ struct IsVariableHelper
6464
IsVariableHelper() : Base{*this} {}
6565
using Base::operator();
6666
Result operator()(const StaticDataObject &) const { return false; }
67-
Result operator()(const Symbol &) const { return true; }
68-
Result operator()(const Component &) const { return true; }
69-
Result operator()(const ArrayRef &) const { return true; }
67+
Result operator()(const Symbol &) const;
68+
Result operator()(const Component &) const;
69+
Result operator()(const ArrayRef &) const;
70+
Result operator()(const Substring &) const;
7071
Result operator()(const CoarrayRef &) const { return true; }
7172
Result operator()(const ComplexPart &) const { return true; }
7273
Result operator()(const ProcedureDesignator &) const;
@@ -218,6 +219,9 @@ std::optional<DataRef> ExtractDataRef(const Designator<T> &d) {
218219
if constexpr (common::HasMember<decltype(x), decltype(DataRef::u)>) {
219220
return DataRef{x};
220221
}
222+
if constexpr (std::is_same_v<std::decay_t<decltype(x)>, Substring>) {
223+
return ExtractDataRef(x);
224+
}
221225
return std::nullopt; // w/o "else" to dodge bogus g++ 8.1 warning
222226
},
223227
d.u);
@@ -234,6 +238,7 @@ std::optional<DataRef> ExtractDataRef(const std::optional<A> &x) {
234238
return std::nullopt;
235239
}
236240
}
241+
std::optional<DataRef> ExtractDataRef(const Substring &);
237242

238243
// Predicate: is an expression is an array element reference?
239244
template<typename T> bool IsArrayElement(const Expr<T> &expr) {

flang/lib/Evaluate/tools.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "flang/Evaluate/characteristics.h"
1212
#include "flang/Evaluate/traverse.h"
1313
#include "flang/Parser/message.h"
14+
#include "flang/Semantics/tools.h"
1415
#include <algorithm>
1516
#include <variant>
1617

@@ -37,7 +38,31 @@ Expr<SomeType> Parenthesize(Expr<SomeType> &&expr) {
3738
std::move(expr.u));
3839
}
3940

41+
std::optional<DataRef> ExtractDataRef(const Substring &substring) {
42+
return std::visit(
43+
common::visitors{
44+
[&](const DataRef &x) -> std::optional<DataRef> { return x; },
45+
[&](const StaticDataObject::Pointer &) -> std::optional<DataRef> {
46+
return std::nullopt;
47+
},
48+
},
49+
substring.parent());
50+
}
51+
4052
// IsVariable()
53+
54+
auto IsVariableHelper::operator()(const Symbol &symbol) const -> Result {
55+
return !symbol.attrs().test(semantics::Attr::PARAMETER);
56+
}
57+
auto IsVariableHelper::operator()(const Component &x) const -> Result {
58+
return (*this)(x.base());
59+
}
60+
auto IsVariableHelper::operator()(const ArrayRef &x) const -> Result {
61+
return (*this)(x.base());
62+
}
63+
auto IsVariableHelper::operator()(const Substring &x) const -> Result {
64+
return (*this)(x.GetBaseObject());
65+
}
4166
auto IsVariableHelper::operator()(const ProcedureDesignator &x) const
4267
-> Result {
4368
const Symbol *symbol{x.GetSymbol()};

flang/lib/Semantics/assignment.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,23 @@ void AssignmentContext::Analyze(const parser::AssignmentStmt &stmt) {
6666
const SomeExpr &rhs{assignment->rhs};
6767
auto lhsLoc{std::get<parser::Variable>(stmt.t).GetSource()};
6868
auto rhsLoc{std::get<parser::Expr>(stmt.t).source};
69+
auto shape{evaluate::GetShape(foldingContext(), lhs)};
70+
if (shape && !shape->empty() && !shape->back().has_value()) { // C1014
71+
Say(lhsLoc,
72+
"Left-hand side of assignment may not be a whole assumed-size array"_err_en_US);
73+
}
74+
if (CheckForPureContext(lhs, rhs, rhsLoc, false)) {
75+
const Scope &scope{context_.FindScope(lhsLoc)};
76+
if (auto whyNot{WhyNotModifiable(lhsLoc, lhs, scope)}) {
77+
if (auto *msg{Say(lhsLoc,
78+
"Left-hand side of assignment is not modifiable"_err_en_US)}) {
79+
msg->Attach(*whyNot);
80+
}
81+
}
82+
}
6983
if (whereDepth_ > 0) {
7084
CheckShape(lhsLoc, &lhs);
7185
}
72-
CheckForPureContext(lhs, rhs, rhsLoc, false);
7386
}
7487
}
7588

@@ -169,7 +182,8 @@ bool AssignmentContext::CheckForPureContext(const SomeExpr &lhs,
169182
// ASSOCIATE(a=>x) -- check x, not a, for "a=..."
170183
base = dataRef ? &dataRef->GetFirstSymbol() : nullptr;
171184
}
172-
if (!CheckDefinabilityInPureScope(messages, *base, scope, *pure)) {
185+
if (base &&
186+
!CheckDefinabilityInPureScope(messages, *base, scope, *pure)) {
173187
return false;
174188
}
175189
}

flang/lib/Semantics/check-declarations.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,10 @@ void CheckHelper::CheckAssumedTypeEntity( // C709
333333
"Assumed-type argument '%s' cannot be a coarray"_err_en_US,
334334
symbol.name());
335335
}
336-
if (details.IsArray() &&
337-
!(details.IsAssumedShape() || details.IsAssumedSize())) {
338-
messages_.Say("Assumed-type argument '%s' must be assumed shape"
339-
" or assumed size array"_err_en_US,
336+
if (details.IsArray() && details.shape().IsExplicitShape()) {
337+
messages_.Say(
338+
"Assumed-type array argument 'arg8' must be assumed shape,"
339+
" assumed size, or assumed rank"_err_en_US,
340340
symbol.name());
341341
}
342342
}

flang/lib/Semantics/expression.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2588,10 +2588,16 @@ MaybeExpr ExpressionAnalyzer::MakeFunctionRef(
25882588
void ArgumentAnalyzer::Analyze(const parser::Variable &x) {
25892589
source_.ExtendToCover(x.GetSource());
25902590
if (MaybeExpr expr{context_.Analyze(x)}) {
2591-
actuals_.emplace_back(std::move(*expr));
2592-
} else {
2593-
fatalErrors_ = true;
2591+
if (!IsConstantExpr(*expr)) {
2592+
actuals_.emplace_back(std::move(*expr));
2593+
return;
2594+
}
2595+
const Symbol *symbol{GetFirstSymbol(*expr)};
2596+
context_.Say(x.GetSource(),
2597+
"Assignment to constant '%s' is not allowed"_err_en_US,
2598+
symbol ? symbol->name() : x.GetSource());
25942599
}
2600+
fatalErrors_ = true;
25952601
}
25962602

25972603
void ArgumentAnalyzer::Analyze(

flang/lib/Semantics/type.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -353,13 +353,13 @@ bool ArraySpec::IsDeferredShape() const {
353353
});
354354
}
355355
bool ArraySpec::IsImpliedShape() const {
356-
return CheckAll([](const ShapeSpec &x) { return x.ubound().isAssumed(); });
356+
return !IsAssumedRank() &&
357+
CheckAll([](const ShapeSpec &x) { return x.ubound().isAssumed(); });
357358
}
358359
bool ArraySpec::IsAssumedSize() const {
359-
return !empty() &&
360+
return !empty() && !IsAssumedRank() && back().ubound().isAssumed() &&
360361
std::all_of(begin(), end() - 1,
361-
[](const ShapeSpec &x) { return x.ubound().isExplicit(); }) &&
362-
back().ubound().isAssumed();
362+
[](const ShapeSpec &x) { return x.ubound().isExplicit(); });
363363
}
364364
bool ArraySpec::IsAssumedRank() const {
365365
return Rank() == 1 && front().lbound().isAssumed();

flang/test/Semantics/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ set(ERROR_TESTS
115115
assign01.f90
116116
assign02.f90
117117
assign03.f90
118+
assign04.f90
118119
if_arith02.f90
119120
if_arith03.f90
120121
if_arith04.f90

flang/test/Semantics/assign04.f90

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
! 9.4.5
2+
subroutine s1
3+
type :: t(k, l)
4+
integer, kind :: k
5+
integer, len :: l
6+
end type
7+
type(t(1, 2)) :: x
8+
!ERROR: Assignment to constant 'x%k' is not allowed
9+
x%k = 4
10+
!ERROR: Left-hand side of assignment is not modifiable
11+
x%l = 3
12+
end
13+
14+
! C901
15+
subroutine s2(x)
16+
real, parameter :: x = 0.0
17+
real, parameter :: a(*) = [1, 2, 3]
18+
character, parameter :: c(2) = "ab"
19+
integer :: i
20+
!ERROR: Assignment to constant 'x' is not allowed
21+
x = 2.0
22+
i = 2
23+
!ERROR: Left-hand side of assignment is not modifiable
24+
a(i) = 3.0
25+
!ERROR: Left-hand side of assignment is not modifiable
26+
a(i:i+1) = [4, 5]
27+
!ERROR: Left-hand side of assignment is not modifiable
28+
c(i:2) = "cd"
29+
end
30+
31+
! C901
32+
subroutine s3
33+
type :: t
34+
integer :: a(2)
35+
integer :: b
36+
end type
37+
type(t) :: x
38+
type(t), parameter :: y = t([1,2], 3)
39+
integer :: i = 1
40+
x%a(i) = 1
41+
!ERROR: Left-hand side of assignment is not modifiable
42+
y%a(i) = 2
43+
x%b = 4
44+
!ERROR: Left-hand side of assignment is not modifiable
45+
y%b = 5
46+
end
47+
48+
! C844
49+
subroutine s4
50+
type :: t
51+
integer :: a(2)
52+
end type
53+
contains
54+
subroutine s(x, c)
55+
type(t), intent(in) :: x
56+
character(10), intent(in) :: c
57+
type(t) :: y
58+
!ERROR: Left-hand side of assignment is not modifiable
59+
x = y
60+
!ERROR: Left-hand side of assignment is not modifiable
61+
x%a(1) = 2
62+
!ERROR: Left-hand side of assignment is not modifiable
63+
c(2:3) = "ab"
64+
end
65+
end
66+
67+
! 8.5.15(2)
68+
module m5
69+
real :: x
70+
real, protected :: y
71+
real, private :: z
72+
type :: t
73+
real :: a
74+
end type
75+
type(t), protected :: b
76+
end
77+
subroutine s5()
78+
use m5
79+
implicit none
80+
x = 1.0
81+
!ERROR: Left-hand side of assignment is not modifiable
82+
y = 2.0
83+
!ERROR: No explicit type declared for 'z'
84+
z = 3.0
85+
!ERROR: Left-hand side of assignment is not modifiable
86+
b%a = 1.0
87+
end
88+
89+
subroutine s6(x)
90+
integer :: x(*)
91+
x(1:3) = [1, 2, 3]
92+
x(:3) = [1, 2, 3]
93+
!ERROR: Assumed-size array 'x' must have explicit final subscript upper bound value
94+
x(:) = [1, 2, 3]
95+
!ERROR: Left-hand side of assignment may not be a whole assumed-size array
96+
x = [1, 2, 3]
97+
end
98+
99+
module m7
100+
type :: t
101+
integer :: i
102+
end type
103+
contains
104+
subroutine s7(x)
105+
type(t) :: x(*)
106+
x(:3)%i = [1, 2, 3]
107+
!ERROR: Left-hand side of assignment may not be a whole assumed-size array
108+
x%i = [1, 2, 3]
109+
end
110+
end

flang/test/Semantics/resolve72.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ subroutine inner1(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
1919
type(*), pointer :: arg6
2020
!ERROR: Assumed-type argument 'arg7' cannot have the VALUE attribute
2121
type(*), value :: arg7
22-
!ERROR: Assumed-type argument 'arg8' must be assumed shape or assumed size array
22+
!ERROR: Assumed-type array argument 'arg8' must be assumed shape, assumed size, or assumed rank
2323
type(*), dimension(3) :: arg8
2424
end subroutine inner1
2525
end subroutine s

0 commit comments

Comments
 (0)