Skip to content

Commit 48a8262

Browse files
committed
[flang] Allow GOTO to containing END IF after ELSE
Label resolution gets into an infinite loop trying to emit an inappropriate error or warning for a GOTO whose target is on an enclosing END IF statement with an intervening ELSE or ELSE IF. The scope tracking mechanism viewed the END IF as being part of the ELSE block's scope. Fix with the same means that was used to fix a similar bogus error on GOTOs to END SELECT in SELECT CASE blocks: nest the THEN/ELSE IF/ELSE blocks one level deeper than before, so that the END IF is in the IF block but not in any of its parts. Fixes llvm#64654 for llvm-test-suite/Fortran/gfortran/regression/goto_5.f90. Differential Revision: https://reviews.llvm.org/D159040
1 parent 3c28ce6 commit 48a8262

File tree

2 files changed

+33
-6
lines changed

2 files changed

+33
-6
lines changed

flang/lib/Semantics/resolve-labels.cpp

+15-6
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,9 @@ class ParseTreeAnalyzer {
239239
auto targetFlags{ConstructBranchTargetFlags(statement)};
240240
if constexpr (common::HasMember<A, LabeledConstructStmts>) {
241241
AddTargetLabelDefinition(label.value(), targetFlags, ParentScope());
242-
} else if constexpr (std::is_same_v<A, parser::EndSelectStmt>) {
243-
// the label on an END SELECT is not in the last case
242+
} else if constexpr (std::is_same_v<A, parser::EndIfStmt> ||
243+
std::is_same_v<A, parser::EndSelectStmt>) {
244+
// the label on an END IF/SELECT is not in the last part/case
244245
AddTargetLabelDefinition(label.value(), targetFlags, ParentScope(), true);
245246
} else if constexpr (common::HasMember<A, LabeledConstructEndStmts>) {
246247
constexpr bool isExecutableConstructEndStmt{true};
@@ -279,12 +280,17 @@ class ParseTreeAnalyzer {
279280
bool Pre(const parser::IfConstruct &ifConstruct) {
280281
return PushConstructName(ifConstruct);
281282
}
283+
void Post(const parser::IfThenStmt &) { PushScope(); }
282284
bool Pre(const parser::IfConstruct::ElseIfBlock &) {
283285
return SwitchToNewScope();
284286
}
285287
bool Pre(const parser::IfConstruct::ElseBlock &) {
286288
return SwitchToNewScope();
287289
}
290+
bool Pre(const parser::EndIfStmt &) {
291+
PopScope();
292+
return true;
293+
}
288294
bool Pre(const parser::CaseConstruct &caseConstruct) {
289295
return PushConstructName(caseConstruct);
290296
}
@@ -1008,15 +1014,18 @@ void CheckScopeConstraints(const SourceStmtList &stmts,
10081014
}
10091015
bool isFatal{false};
10101016
ProxyForScope fromScope{scope};
1011-
for (ProxyForScope toScope{target.proxyForScope}; fromScope != toScope;
1017+
for (ProxyForScope toScope{target.proxyForScope}; HasScope(toScope);
10121018
toScope = scopes[toScope].parent) {
1019+
while (scopes[fromScope].depth > scopes[toScope].depth) {
1020+
fromScope = scopes[fromScope].parent;
1021+
}
1022+
if (toScope == fromScope) {
1023+
break;
1024+
}
10131025
if (scopes[toScope].isExteriorGotoFatal) {
10141026
isFatal = true;
10151027
break;
10161028
}
1017-
if (scopes[toScope].depth == scopes[fromScope].depth) {
1018-
fromScope = scopes[fromScope].parent;
1019-
}
10201029
}
10211030
context.Say(position,
10221031
isFatal

flang/test/Semantics/label18.f90

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
! RUN: %python %S/test_errors.py %s %flang_fc1 -Werror
2+
program main
3+
if (.true.) then
4+
do j = 1, 2
5+
goto 1 ! ok; used to cause looping in label resolution
6+
end do
7+
else
8+
goto 1 ! ok
9+
1 end if
10+
if (.true.) then
11+
do j = 1, 2
12+
!WARNING: Label '1' is in a construct that should not be used as a branch target here
13+
goto 1
14+
end do
15+
end if
16+
!WARNING: Label '1' is in a construct that should not be used as a branch target here
17+
goto 1
18+
end

0 commit comments

Comments
 (0)