Skip to content

Commit 9eab0da

Browse files
committed
[flang] Catch branching into FORALL/WHERE constructs
Enforce constraints C1034 & C1038, which disallow the use of otherwise valid statements as branch targets when they appear in FORALL &/or WHERE constructs. (And make the diagnostic message somewhat more user-friendly.) Differential Revision: https://reviews.llvm.org/D109936
1 parent e90b512 commit 9eab0da

File tree

5 files changed

+44
-33
lines changed

5 files changed

+44
-33
lines changed

flang/lib/Semantics/resolve-labels.cpp

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ constexpr Legality IsLegalDoTerm(const parser::Statement<A> &) {
6060
std::is_same_v<A, parser::EndWhereStmt>) {
6161
// Executable construct end statements are also supported as
6262
// an extension but they need special care because the associated
63-
// construct create there own scope.
63+
// construct create their own scope.
6464
return Legality::formerly;
6565
} else {
6666
return Legality::never;
@@ -224,10 +224,10 @@ class ParseTreeAnalyzer {
224224
parser::BlockStmt, parser::ChangeTeamStmt, parser::CriticalStmt,
225225
parser::IfThenStmt, parser::NonLabelDoStmt, parser::SelectCaseStmt,
226226
parser::SelectRankStmt, parser::SelectTypeStmt>;
227-
using LabeledConstructEndStmts =
228-
std::tuple<parser::EndAssociateStmt, parser::EndBlockStmt,
229-
parser::EndChangeTeamStmt, parser::EndCriticalStmt,
230-
parser::EndDoStmt, parser::EndIfStmt, parser::EndSelectStmt>;
227+
using LabeledConstructEndStmts = std::tuple<parser::EndAssociateStmt,
228+
parser::EndBlockStmt, parser::EndChangeTeamStmt,
229+
parser::EndCriticalStmt, parser::EndDoStmt, parser::EndForallStmt,
230+
parser::EndIfStmt, parser::EndSelectStmt, parser::EndWhereStmt>;
231231
using LabeledProgramUnitEndStmts =
232232
std::tuple<parser::EndFunctionStmt, parser::EndMpSubprogramStmt,
233233
parser::EndProgramStmt, parser::EndSubroutineStmt>;
@@ -294,10 +294,10 @@ class ParseTreeAnalyzer {
294294
return SwitchToNewScope();
295295
}
296296
bool Pre(const parser::WhereConstruct &whereConstruct) {
297-
return PushConstructNameWithoutBlock(whereConstruct);
297+
return PushConstructName(whereConstruct);
298298
}
299299
bool Pre(const parser::ForallConstruct &forallConstruct) {
300-
return PushConstructNameWithoutBlock(forallConstruct);
300+
return PushConstructName(forallConstruct);
301301
}
302302

303303
void Post(const parser::AssociateConstruct &associateConstruct) {
@@ -327,12 +327,11 @@ class ParseTreeAnalyzer {
327327
void Post(const parser::SelectTypeConstruct &selectTypeConstruct) {
328328
PopConstructName(selectTypeConstruct);
329329
}
330-
331330
void Post(const parser::WhereConstruct &whereConstruct) {
332-
PopConstructNameWithoutBlock(whereConstruct);
331+
PopConstructName(whereConstruct);
333332
}
334333
void Post(const parser::ForallConstruct &forallConstruct) {
335-
PopConstructNameWithoutBlock(forallConstruct);
334+
PopConstructName(forallConstruct);
336335
}
337336

338337
// Checks for missing or mismatching names on various constructs (e.g., IF)
@@ -570,18 +569,6 @@ class ParseTreeAnalyzer {
570569
}
571570
return PushSubscope();
572571
}
573-
template <typename A> bool PushConstructNameWithoutBlock(const A &a) {
574-
const auto &optionalName{std::get<0>(std::get<0>(a.t).statement.t)};
575-
if (optionalName) {
576-
constructNames_.emplace_back(optionalName->ToString());
577-
}
578-
return true;
579-
}
580-
581-
template <typename A> void PopConstructNameWithoutBlock(const A &a) {
582-
CheckName(a);
583-
PopConstructNameIfPresent(a);
584-
}
585572
template <typename A> void PopConstructNameIfPresent(const A &a) {
586573
const auto &optionalName{std::get<0>(std::get<0>(a.t).statement.t)};
587574
if (optionalName) {
@@ -962,12 +949,15 @@ void CheckScopeConstraints(const SourceStmtList &stmts,
962949
} else if (!InInclusiveScope(scopes, scope, target.proxyForScope)) {
963950
// Clause 11.1.2.1 prohibits transfer of control to the interior of a
964951
// block from outside the block, but this does not apply to formats.
952+
// C1038 and C1034 forbid statements in FORALL and WHERE constructs
953+
// (resp.) from being branch targets.
965954
if (target.labeledStmtClassificationSet.test(
966955
TargetStatementEnum::Format)) {
967956
continue;
968957
}
969-
context.Say(
970-
position, "Label '%u' is not in scope"_en_US, SayLabel(label));
958+
context.Say(position,
959+
"Label '%u' is in a construct that prevents its use as a branch target here"_en_US,
960+
SayLabel(label));
971961
}
972962
}
973963
}

flang/test/Semantics/label05.f90

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
21
! RUN: not %flang_fc1 -fdebug-unparse-with-symbols %s 2>&1 | FileCheck %s
32
! CHECK: Label '50' was not found
4-
! CHECK: Label '55' is not in scope
3+
! CHECK: Label '55' is in a construct that prevents its use as a branch target here
54
! CHECK: Label '70' is not a branch target
65
! CHECK: Control flow use of '70'
6+
! CHECK: Label '80' is in a construct that prevents its use as a branch target here
7+
! CHECK: Label '90' is in a construct that prevents its use as a branch target here
8+
! CHECK: Label '91' is in a construct that prevents its use as a branch target here
9+
! CHECK: Label '92' is in a construct that prevents its use as a branch target here
710

811
subroutine sub00(a,b,n,m)
912
real a(n,m)
@@ -35,3 +38,23 @@ subroutine sub02(a,b,n,m)
3538
end if
3639
70 FORMAT (1x,i6)
3740
end subroutine sub02
41+
42+
subroutine sub03(a,n)
43+
real a(n)
44+
forall (j=1:n)
45+
80 a(n) = j
46+
end forall
47+
go to 80
48+
end subroutine sub03
49+
50+
subroutine sub04(a,n)
51+
real a(n)
52+
where (a > 0)
53+
90 a = 1
54+
elsewhere (a < 0)
55+
91 a = 2
56+
elsewhere
57+
92 a = 3
58+
end where
59+
if (n - 3) 90, 91, 92
60+
end subroutine sub04

flang/test/Semantics/label06.f90

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
21
! RUN: not %flang_fc1 -fdebug-unparse-with-symbols %s 2>&1 | FileCheck %s
3-
! CHECK: Label '10' is not in scope
2+
! CHECK: Label '10' is in a construct that prevents its use as a branch target here
43
! CHECK: Label '20' was not found
54
! CHECK: Label '30' is not a branch target
65
! CHECK: Control flow use of '30'
7-
! CHECK: Label '40' is not in scope
8-
! CHECK: Label '50' is not in scope
6+
! CHECK: Label '40' is in a construct that prevents its use as a branch target here
7+
! CHECK: Label '50' is in a construct that prevents its use as a branch target here
98

109
subroutine sub00(n)
1110
GOTO (10,20,30) n

flang/test/Semantics/label07.f90

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
21
! RUN: not %flang_fc1 -fdebug-unparse-with-symbols %s 2>&1 | FileCheck %s
32
! CHECK: Label '30' is not a branch target
43
! CHECK: Control flow use of '30'
5-
! CHECK: Label '10' is not in scope
4+
! CHECK: Label '10' is in a construct that prevents its use as a branch target here
65
! CHECK: Label '20' was not found
76
! CHECK: Label '60' was not found
87

flang/test/Semantics/label14.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
! Block Construct
44

55
! RUN: %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s
6-
! CHECK: Label '20' is not in scope
6+
! CHECK: Label '20' is in a construct that prevents its use as a branch target here
77

88
subroutine s1
99
block

0 commit comments

Comments
 (0)