Skip to content

Commit 22ed61e

Browse files
committed
[flang] Emit errors on vector subscripts with duplicated elements when object must be definable
When the left-hand side of an assignment, or any other context demanding definability, comprises a designator with a vector subscript that is known at compilation time to have one or more duplicated elements, emit an error message. Differential Revision: https://reviews.llvm.org/D155492
1 parent 0bb3260 commit 22ed61e

File tree

4 files changed

+69
-2
lines changed

4 files changed

+69
-2
lines changed

flang/lib/Semantics/check-call.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
448448
}
449449

450450
// Definability
451+
bool actualIsVariable{evaluate::IsVariable(actual)};
451452
const char *reason{nullptr};
452453
if (dummy.intent == common::Intent::Out) {
453454
reason = "INTENT(OUT)";
@@ -457,7 +458,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
457458
if (reason && scope) {
458459
// Problems with polymorphism are caught in the callee's definition.
459460
DefinabilityFlags flags{DefinabilityFlag::PolymorphicOkInPure};
460-
if (isElemental || dummyIsValue) { // 15.5.2.4(21)
461+
if (isElemental) { // 15.5.2.4(21)
461462
flags.set(DefinabilityFlag::VectorSubscriptIsOk);
462463
}
463464
if (actualIsPointer && dummyIsPointer) { // 19.6.8
@@ -475,7 +476,6 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
475476
// technically legal but worth emitting a warning
476477
// llvm-project issue #58973: constant actual argument passed in where dummy
477478
// argument is marked volatile
478-
bool actualIsVariable{evaluate::IsVariable(actual)};
479479
if (dummyIsVolatile && !actualIsVariable &&
480480
context.ShouldWarn(common::UsageWarning::ExprPassedToVolatile)) {
481481
messages.Say(

flang/lib/Semantics/definable.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,47 @@ std::optional<parser::Message> WhyNotDefinable(parser::CharBlock at,
244244
return WhyNotDefinableLast(at, scope, flags, original);
245245
}
246246

247+
class DuplicatedSubscriptFinder
248+
: public evaluate::AnyTraverse<DuplicatedSubscriptFinder, bool> {
249+
using Base = evaluate::AnyTraverse<DuplicatedSubscriptFinder, bool>;
250+
251+
public:
252+
explicit DuplicatedSubscriptFinder(evaluate::FoldingContext &foldingContext)
253+
: Base{*this}, foldingContext_{foldingContext} {}
254+
using Base::operator();
255+
bool operator()(const evaluate::ActualArgument &) {
256+
return false; // don't descend into argument expressions
257+
}
258+
bool operator()(const evaluate::ArrayRef &aRef) {
259+
bool anyVector{false};
260+
for (const auto &ss : aRef.subscript()) {
261+
if (ss.Rank() > 0) {
262+
anyVector = true;
263+
if (const auto *vecExpr{
264+
std::get_if<evaluate::IndirectSubscriptIntegerExpr>(&ss.u)}) {
265+
auto folded{evaluate::Fold(foldingContext_,
266+
evaluate::Expr<evaluate::SubscriptInteger>{vecExpr->value()})};
267+
if (const auto *con{
268+
evaluate::UnwrapConstantValue<evaluate::SubscriptInteger>(
269+
folded)}) {
270+
std::set<std::int64_t> values;
271+
for (const auto &j : con->values()) {
272+
if (auto pair{values.emplace(j.ToInt64())}; !pair.second) {
273+
return true; // duplicate
274+
}
275+
}
276+
}
277+
return false;
278+
}
279+
}
280+
}
281+
return anyVector ? false : (*this)(aRef.base());
282+
}
283+
284+
private:
285+
evaluate::FoldingContext &foldingContext_;
286+
};
287+
247288
std::optional<parser::Message> WhyNotDefinable(parser::CharBlock at,
248289
const Scope &scope, DefinabilityFlags flags,
249290
const evaluate::Expr<evaluate::SomeType> &expr) {
@@ -288,6 +329,11 @@ std::optional<parser::Message> WhyNotDefinable(parser::CharBlock at,
288329
}
289330
}
290331
}
332+
if (!flags.test(DefinabilityFlag::DuplicatesAreOk) &&
333+
DuplicatedSubscriptFinder{scope.context().foldingContext()}(expr)) {
334+
return parser::Message{at,
335+
"Variable has a vector subscript with a duplicated element"_because_en_US};
336+
}
291337
} else {
292338
return parser::Message{at,
293339
"Variable '%s' has a vector subscript"_because_en_US,

flang/lib/Semantics/definable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class Scope;
2727

2828
ENUM_CLASS(DefinabilityFlag,
2929
VectorSubscriptIsOk, // a vector subscript may appear (i.e., assignment)
30+
DuplicatesAreOk, // vector subscript may have duplicates
3031
PointerDefinition, // a pointer is being defined, not its target
3132
AcceptAllocatable, // treat allocatable as if it were a pointer
3233
PolymorphicOkInPure) // don't check for polymorphic type in pure subprogram

flang/test/Semantics/definable06.f90

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
! RUN: %python %S/test_errors.py %s %flang_fc1
2+
module m
3+
contains
4+
elemental subroutine inout(x)
5+
integer, intent(inout) :: x
6+
end
7+
subroutine test
8+
integer :: x(2)
9+
!ERROR: Left-hand side of assignment is not definable
10+
!BECAUSE: Variable has a vector subscript with a duplicated element
11+
x([1,1]) = 0
12+
!ERROR: Actual argument associated with INTENT(IN OUT) dummy argument 'x=' is not definable
13+
!BECAUSE: Variable has a vector subscript with a duplicated element
14+
call inout(x([(mod(j-1,2)+1,j=1,10)]))
15+
!ERROR: Input variable 'x' is not definable
16+
!BECAUSE: Variable has a vector subscript with a duplicated element
17+
read (*,*) x([2,2])
18+
end
19+
end
20+

0 commit comments

Comments
 (0)