Skip to content

Commit 90828d6

Browse files
authored
[flang] Weird restrictions on index variables (llvm#77019)
There are some very odd (even for Fortran) rules in F'2023 subclause 19.4 (paras 6 & 8) pertaining to the index variables of FORALL and DO CONCURRENT constructs/statements, and they are not currently implemented correctly. Although these index variables are construct entities, they have restrictions in the standard that would essentially allow them to also be variables in their enclosing scopes. If their names are present in the enclosing scope, and the construct does not have an explicit type specification for its indices, then the names in the enclosing scope must either be scalar variables or COMMON blocks, and their type must be integer. Reimplement these restrictions largely with portability warnings rather than hard errors. Retain the semantic interpretation that the type of an untyped index variable be taken from the type of a variable of the same name in the enclosing scope, if it exists, although that bit of the standard could be interpreted otherwise. Fixes llvm#76978.
1 parent c0944f5 commit 90828d6

File tree

8 files changed

+72
-42
lines changed

8 files changed

+72
-42
lines changed

flang/docs/Extensions.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ end
9696
* `NULL()` without `MOLD=` is not allowed to be associated as an
9797
actual argument corresponding to an assumed-rank dummy argument;
9898
its rank in the called procedure would not be well-defined.
99+
* When an index variable of a `FORALL` or `DO CONCURRENT` is present
100+
in the enclosing scope, and the construct does not have an explicit
101+
type specification for its index variables, some weird restrictions
102+
in F'2023 subclause 19.4 paragraphs 6 & 8 should apply. Since this
103+
compiler properly scopes these names, violations of these restrictions
104+
elicit only portability warnings by default.
99105

100106
## Extensions, deletions, and legacy features supported by default
101107

flang/include/flang/Common/Fortran-features.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
4545
MiscSourceExtensions, AllocateToOtherLength, LongNames, IntrinsicAsSpecific,
4646
BenignNameClash, BenignRedundancy, NullMoldAllocatableComponentValue,
4747
NopassScalarBase, MiscUseExtensions, ImpliedDoIndexScope,
48-
DistinctCommonSizes)
48+
DistinctCommonSizes, OddIndexVariableRestrictions)
4949

5050
// Portability and suspicious usage warnings for conforming code
5151
ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,

flang/lib/Semantics/resolve-names.cpp

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6638,10 +6638,14 @@ void ConstructVisitor::ResolveIndexName(
66386638
const parser::Name &name{std::get<parser::Name>(control.t)};
66396639
auto *prev{FindSymbol(name)};
66406640
if (prev) {
6641-
if (prev->owner().kind() == Scope::Kind::Forall ||
6642-
prev->owner() == currScope()) {
6641+
if (prev->owner() == currScope()) {
66436642
SayAlreadyDeclared(name, *prev);
66446643
return;
6644+
} else if (prev->owner().kind() == Scope::Kind::Forall &&
6645+
context().ShouldWarn(
6646+
common::LanguageFeature::OddIndexVariableRestrictions)) {
6647+
SayWithDecl(name, *prev,
6648+
"Index variable '%s' should not also be an index in an enclosing FORALL or DO CONCURRENT"_port_en_US);
66456649
}
66466650
name.symbol = nullptr;
66476651
}
@@ -6651,22 +6655,26 @@ void ConstructVisitor::ResolveIndexName(
66516655
} else if (!prev) {
66526656
ApplyImplicitRules(symbol);
66536657
} else {
6654-
const Symbol &prevRoot{prev->GetUltimate()};
6655-
// prev could be host- use- or construct-associated with another symbol
6656-
if (!prevRoot.has<ObjectEntityDetails>() &&
6657-
!prevRoot.has<AssocEntityDetails>()) {
6658-
Say2(name, "Index name '%s' conflicts with existing identifier"_err_en_US,
6659-
*prev, "Previous declaration of '%s'"_en_US);
6660-
context().SetError(symbol);
6661-
return;
6658+
// Odd rules in F'2023 19.4 paras 6 & 8.
6659+
Symbol &prevRoot{prev->GetUltimate()};
6660+
if (const auto *type{prevRoot.GetType()}) {
6661+
symbol.SetType(*type);
66626662
} else {
6663-
if (const auto *type{prevRoot.GetType()}) {
6664-
symbol.SetType(*type);
6665-
}
6666-
if (prevRoot.IsObjectArray()) {
6667-
SayWithDecl(name, *prev, "Index variable '%s' is not scalar"_err_en_US);
6668-
return;
6663+
ApplyImplicitRules(symbol);
6664+
}
6665+
if (prevRoot.has<ObjectEntityDetails>() ||
6666+
ConvertToObjectEntity(prevRoot)) {
6667+
if (prevRoot.IsObjectArray() &&
6668+
context().ShouldWarn(
6669+
common::LanguageFeature::OddIndexVariableRestrictions)) {
6670+
SayWithDecl(name, *prev,
6671+
"Index variable '%s' should be scalar in the enclosing scope"_port_en_US);
66696672
}
6673+
} else if (!prevRoot.has<CommonBlockDetails>() &&
6674+
context().ShouldWarn(
6675+
common::LanguageFeature::OddIndexVariableRestrictions)) {
6676+
SayWithDecl(name, *prev,
6677+
"Index variable '%s' should be a scalar object or common block if it is present in the enclosing scope"_port_en_US);
66706678
}
66716679
}
66726680
EvaluateExpr(parser::Scalar{parser::Integer{common::Clone(name)}});
@@ -6839,7 +6847,10 @@ bool ConstructVisitor::Pre(const parser::DataStmtValue &x) {
68396847

68406848
bool ConstructVisitor::Pre(const parser::DoConstruct &x) {
68416849
if (x.IsDoConcurrent()) {
6842-
PushScope(Scope::Kind::OtherConstruct, nullptr);
6850+
// The new scope has Kind::Forall for index variable name conflict
6851+
// detection with nested FORALL/DO CONCURRENT constructs in
6852+
// ResolveIndexName().
6853+
PushScope(Scope::Kind::Forall, nullptr);
68436854
}
68446855
return true;
68456856
}

flang/test/Semantics/dosemantics12.f90

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
! RUN: %python %S/test_errors.py %s %flang_fc1
1+
! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic
22
! Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
33
!
44
! Licensed under the Apache License, Version 2.0 (the "License");
@@ -313,10 +313,10 @@ subroutine s9()
313313
end do
314314
end do
315315

316-
! OK since the DO CONCURRENT index-name exists only in the scope of the
317-
! DO CONCURRENT construct
316+
! Technically non-conformant (F'2023 19.4 p8)
318317
do concurrent (ivar = 1:10)
319318
print *, "hello"
319+
!PORTABILITY: Index variable 'ivar' should not also be an index in an enclosing FORALL or DO CONCURRENT
320320
do concurrent (ivar = 1:10)
321321
print *, "hello"
322322
end do

flang/test/Semantics/forall01.f90

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
! RUN: %python %S/test_errors.py %s %flang_fc1
1+
! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic
22
subroutine forall1
33
real :: a(9)
44
!ERROR: 'i' is already declared in this scoping unit
@@ -10,8 +10,7 @@ subroutine forall1
1010
a(i) = i
1111
end forall
1212
forall (j=1:8)
13-
!ERROR: 'j' is already declared in this scoping unit
14-
!ERROR: Cannot redefine FORALL variable 'j'
13+
!PORTABILITY: Index variable 'j' should not also be an index in an enclosing FORALL or DO CONCURRENT
1514
forall (j=1:9)
1615
end forall
1716
end forall
@@ -75,7 +74,6 @@ subroutine forall4
7574
forall(i=1:10:zero) a(i) = i
7675
end
7776

78-
! Note: this gets warnings but not errors
7977
subroutine forall5
8078
real, target :: x(10), y(10)
8179
forall(i=1:10)
@@ -93,6 +91,8 @@ subroutine forall5
9391
endforall
9492
do concurrent(i=1:10)
9593
x = y
94+
!Odd rule from F'2023 19.4 p8
95+
!PORTABILITY: Index variable 'i' should not also be an index in an enclosing FORALL or DO CONCURRENT
9696
!WARNING: FORALL index variable 'i' not used on left-hand side of assignment
9797
forall(i=1:10) x = y
9898
end do
@@ -116,17 +116,20 @@ subroutine forall7(x)
116116
real :: a(10)
117117
class(*) :: x
118118
associate (j => iarr(1))
119+
!PORTABILITY: Index variable 'j' should be a scalar object or common block if it is present in the enclosing scope
119120
forall (j=1:size(a))
120121
a(j) = a(j) + 1
121122
end forall
122123
end associate
123124
associate (j => iarr(1) + 1)
125+
!PORTABILITY: Index variable 'j' should be a scalar object or common block if it is present in the enclosing scope
124126
forall (j=1:size(a))
125127
a(j) = a(j) + 1
126128
end forall
127129
end associate
128130
select type (j => x)
129131
type is (integer)
132+
!PORTABILITY: Index variable 'j' should be a scalar object or common block if it is present in the enclosing scope
130133
forall (j=1:size(a))
131134
a(j) = a(j) + 1
132135
end forall

flang/test/Semantics/resolve35.f90

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
! RUN: %python %S/test_errors.py %s %flang_fc1
1+
! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic
22
! Construct names
33

44
subroutine s1
@@ -21,11 +21,17 @@ subroutine s3
2121
real :: a(10,10), b(10,10)
2222
type y; end type
2323
integer(8) :: x
24-
!ERROR: Index name 'y' conflicts with existing identifier
24+
!PORTABILITY: Index variable 'y' should be a scalar object or common block if it is present in the enclosing scope
25+
!ERROR: Must have INTEGER type, but is REAL(4)
2526
forall(x=1:10, y=1:10)
27+
!ERROR: Must have INTEGER type, but is REAL(4)
28+
!ERROR: Must have INTEGER type, but is REAL(4)
2629
a(x, y) = b(x, y)
2730
end forall
28-
!ERROR: Index name 'y' conflicts with existing identifier
31+
!PORTABILITY: Index variable 'y' should be a scalar object or common block if it is present in the enclosing scope
32+
!ERROR: Must have INTEGER type, but is REAL(4)
33+
!ERROR: Must have INTEGER type, but is REAL(4)
34+
!ERROR: Must have INTEGER type, but is REAL(4)
2935
forall(x=1:10, y=1:10) a(x, y) = b(x, y)
3036
end
3137

@@ -45,7 +51,7 @@ subroutine s4
4551
!ERROR: Must have INTEGER type, but is REAL(4)
4652
a(y) = b(y)
4753
end forall
48-
!ERROR: Index variable 'i' is not scalar
54+
!PORTABILITY: Index variable 'i' should be scalar in the enclosing scope
4955
forall(i=1:10)
5056
a(i) = b(i)
5157
end forall
@@ -55,7 +61,9 @@ subroutine s6
5561
integer, parameter :: n = 4
5662
real, dimension(n) :: x
5763
data(x(i), i=1, n) / n * 0.0 /
58-
!ERROR: Index name 't' conflicts with existing identifier
64+
!PORTABILITY: Index variable 't' should be a scalar object or common block if it is present in the enclosing scope
65+
!ERROR: Must have INTEGER type, but is REAL(4)
66+
!ERROR: Must have INTEGER type, but is REAL(4)
5967
forall(t=1:n) x(t) = 0.0
6068
contains
6169
subroutine t

flang/test/Semantics/resolve99.f90

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
! RUN: %python %S/test_errors.py %s %flang_fc1
1+
! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic
22
! Tests for the index-name of a FORALL statement
33

44
module m1
@@ -31,7 +31,7 @@ subroutine constructAssoc()
3131
integer, dimension(4) :: table
3232
integer :: localVar
3333
associate (assocVar => localVar)
34-
! assocVar is construct associated with localVar
34+
!PORTABILITY: Index variable 'assocvar' should be a scalar object or common block if it is present in the enclosing scope
3535
FORALL (assocVar=1:4) table(assocVar) = 343
3636
end associate
3737
end subroutine constructAssoc
@@ -44,7 +44,9 @@ end subroutine commonSub
4444

4545
subroutine mismatch()
4646
integer, dimension(4) :: table
47-
!ERROR: Index name 'typename' conflicts with existing identifier
47+
!PORTABILITY: Index variable 'typename' should be a scalar object or common block if it is present in the enclosing scope
48+
!ERROR: Must have INTEGER type, but is REAL(4)
49+
!ERROR: Must have INTEGER type, but is REAL(4)
4850
FORALL (typeName=1:4) table(typeName) = 343
4951
end subroutine mismatch
5052
end program indexName

flang/test/Semantics/symbol09.f90

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ subroutine s2
2525
real a(10)
2626
!DEF: /s2/i ObjectEntity INTEGER(4)
2727
integer i
28-
!DEF: /s2/OtherConstruct1/i ObjectEntity INTEGER(4)
28+
!DEF: /s2/Forall1/i ObjectEntity INTEGER(4)
2929
do concurrent(i=1:10)
3030
!REF: /s2/a
31-
!REF: /s2/OtherConstruct1/i
31+
!REF: /s2/Forall1/i
3232
a(i) = i
3333
end do
3434
!REF: /s2/i
@@ -104,14 +104,14 @@ subroutine s6
104104
integer(kind=8) j
105105
!DEF: /s6/a ObjectEntity INTEGER(4)
106106
integer :: a(5) = 1
107-
!DEF: /s6/OtherConstruct1/i ObjectEntity INTEGER(4)
108-
!DEF: /s6/OtherConstruct1/j (LocalityLocal) HostAssoc INTEGER(8)
109-
!DEF: /s6/OtherConstruct1/k (Implicit, LocalityLocalInit) HostAssoc INTEGER(4)
110-
!DEF: /s6/OtherConstruct1/a (LocalityShared) HostAssoc INTEGER(4)
107+
!DEF: /s6/Forall1/i ObjectEntity INTEGER(4)
108+
!DEF: /s6/Forall1/j (LocalityLocal) HostAssoc INTEGER(8)
109+
!DEF: /s6/Forall1/k (Implicit, LocalityLocalInit) HostAssoc INTEGER(4)
110+
!DEF: /s6/Forall1/a (LocalityShared) HostAssoc INTEGER(4)
111111
do concurrent(integer::i=1:5)local(j)local_init(k)shared(a)
112-
!REF: /s6/OtherConstruct1/a
113-
!REF: /s6/OtherConstruct1/i
114-
!REF: /s6/OtherConstruct1/j
112+
!REF: /s6/Forall1/a
113+
!REF: /s6/Forall1/i
114+
!REF: /s6/Forall1/j
115115
a(i) = j+1
116116
end do
117117
end subroutine

0 commit comments

Comments
 (0)