Skip to content

Commit a4bc44a

Browse files
authored
[flang] Disallow branches into SELECT TYPE/RANK cases (llvm#93893)
Ensure that a branch cannot be made into a case of a SELECT TYPE or SELECT RANK construct.
1 parent a8f2d18 commit a4bc44a

File tree

2 files changed

+45
-15
lines changed

2 files changed

+45
-15
lines changed

flang/lib/Semantics/resolve-labels.cpp

+13-15
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ class ParseTreeAnalyzer {
282282
constructNames_.emplace_back(optionalName->ToString());
283283
}
284284
// Allow FORTRAN '66 extended DO ranges
285-
PushScope().isExteriorGotoFatal = false;
285+
PushScope(false);
286286
// Process labels of the DO and END DO statements, but not the
287287
// statements themselves, so that a non-construct END DO
288288
// can be distinguished (below).
@@ -302,7 +302,7 @@ class ParseTreeAnalyzer {
302302
bool Pre(const parser::IfConstruct &ifConstruct) {
303303
return PushConstructName(ifConstruct);
304304
}
305-
void Post(const parser::IfThenStmt &) { PushScope(); }
305+
void Post(const parser::IfThenStmt &) { PushScope(false); }
306306
bool Pre(const parser::IfConstruct::ElseIfBlock &) {
307307
return SwitchToNewScope();
308308
}
@@ -316,19 +316,19 @@ class ParseTreeAnalyzer {
316316
bool Pre(const parser::CaseConstruct &caseConstruct) {
317317
return PushConstructName(caseConstruct);
318318
}
319-
void Post(const parser::SelectCaseStmt &) { PushScope(); }
319+
void Post(const parser::SelectCaseStmt &) { PushScope(false); }
320320
bool Pre(const parser::CaseConstruct::Case &) { return SwitchToNewScope(); }
321321
bool Pre(const parser::SelectRankConstruct &selectRankConstruct) {
322322
return PushConstructName(selectRankConstruct);
323323
}
324-
void Post(const parser::SelectRankStmt &) { PushScope(); }
324+
void Post(const parser::SelectRankStmt &) { PushScope(true); }
325325
bool Pre(const parser::SelectRankConstruct::RankCase &) {
326326
return SwitchToNewScope();
327327
}
328328
bool Pre(const parser::SelectTypeConstruct &selectTypeConstruct) {
329329
return PushConstructName(selectTypeConstruct);
330330
}
331-
void Post(const parser::SelectTypeStmt &) { PushScope(); }
331+
void Post(const parser::SelectTypeStmt &) { PushScope(true); }
332332
bool Pre(const parser::SelectTypeConstruct::TypeCase &) {
333333
return SwitchToNewScope();
334334
}
@@ -580,19 +580,20 @@ class ParseTreeAnalyzer {
580580
SemanticsContext &ErrorHandler() { return context_; }
581581

582582
private:
583-
ScopeInfo &PushScope() {
583+
ScopeInfo &PushScope(bool isExteriorGotoFatal) {
584584
auto &model{programUnits_.back().scopeModel};
585585
int newDepth{model.empty() ? 1 : model[currentScope_].depth + 1};
586586
ScopeInfo &result{model.emplace_back()};
587587
result.parent = currentScope_;
588588
result.depth = newDepth;
589+
result.isExteriorGotoFatal = isExteriorGotoFatal;
589590
currentScope_ = model.size() - 1;
590591
return result;
591592
}
592593
bool InitializeNewScopeContext() {
593594
programUnits_.emplace_back(UnitAnalysis{});
594595
currentScope_ = 0u;
595-
PushScope();
596+
PushScope(false);
596597
return true;
597598
}
598599
ScopeInfo &PopScope() {
@@ -604,9 +605,7 @@ class ParseTreeAnalyzer {
604605
return programUnits_.back().scopeModel[currentScope_].parent;
605606
}
606607
bool SwitchToNewScope() {
607-
ScopeInfo &oldScope{PopScope()};
608-
bool isExteriorGotoFatal{oldScope.isExteriorGotoFatal};
609-
PushScope().isExteriorGotoFatal = isExteriorGotoFatal;
608+
PushScope(PopScope().isExteriorGotoFatal);
610609
return true;
611610
}
612611

@@ -617,10 +616,9 @@ class ParseTreeAnalyzer {
617616
}
618617
// Gotos into this construct from outside it are diagnosed, and
619618
// are fatal unless the construct is a DO, IF, or SELECT CASE.
620-
PushScope().isExteriorGotoFatal =
621-
!(std::is_same_v<A, parser::DoConstruct> ||
622-
std::is_same_v<A, parser::IfConstruct> ||
623-
std::is_same_v<A, parser::CaseConstruct>);
619+
PushScope(!(std::is_same_v<A, parser::DoConstruct> ||
620+
std::is_same_v<A, parser::IfConstruct> ||
621+
std::is_same_v<A, parser::CaseConstruct>));
624622
return true;
625623
}
626624
bool PushConstructName(const parser::BlockConstruct &blockConstruct) {
@@ -630,7 +628,7 @@ class ParseTreeAnalyzer {
630628
if (optionalName) {
631629
constructNames_.emplace_back(optionalName->ToString());
632630
}
633-
PushScope().isExteriorGotoFatal = true;
631+
PushScope(true);
634632
return true;
635633
}
636634
template <typename A> void PopConstructNameIfPresent(const A &a) {

flang/test/Semantics/label05.f90

+32
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
! CHECK: error: Label '90' is in a construct that prevents its use as a branch target here
88
! CHECK: error: Label '91' is in a construct that prevents its use as a branch target here
99
! CHECK: error: Label '92' is in a construct that prevents its use as a branch target here
10+
! CHECK: error: Label '30' is in a construct that prevents its use as a branch target here
11+
! CHECK: error: Label '31' is in a construct that prevents its use as a branch target here
12+
! CHECK-NOT: error: Label '32' is in a construct that prevents its use as a branch target here
13+
! CHECK: error: Label '40' is in a construct that prevents its use as a branch target here
14+
! CHECK: error: Label '41' is in a construct that prevents its use as a branch target here
15+
! CHECK-NOT: error: Label '42' is in a construct that prevents its use as a branch target here
1016

1117
subroutine sub00(a,b,n,m)
1218
real a(n,m)
@@ -58,3 +64,29 @@ subroutine sub04(a,n)
5864
end where
5965
if (n - 3) 90, 91, 92
6066
end subroutine sub04
67+
68+
subroutine sub05(a)
69+
real a(..)
70+
select rank (a)
71+
rank(1)
72+
31 goto 30
73+
rank(2)
74+
goto 32
75+
32 continue
76+
30 continue
77+
end select
78+
goto 31
79+
end
80+
81+
subroutine sub06(a)
82+
class(*) a
83+
select type (a)
84+
type is (integer)
85+
41 goto 40
86+
type is (real)
87+
goto 42
88+
42 continue
89+
40 continue
90+
end select
91+
goto 41
92+
end

0 commit comments

Comments
 (0)