@@ -28,6 +28,12 @@ using IndexList = std::vector<std::pair<parser::CharBlock, parser::CharBlock>>;
28
28
// A ProxyForScope is an integral proxy for a Fortran scope. This is required
29
29
// because the parse tree does not actually have the scopes required.
30
30
using ProxyForScope = unsigned ;
31
+ // Minimal scope information
32
+ struct ScopeInfo {
33
+ ProxyForScope parent{};
34
+ bool isExteriorGotoFatal{false };
35
+ int depth{0 };
36
+ };
31
37
struct LabeledStatementInfoTuplePOD {
32
38
ProxyForScope proxyForScope;
33
39
parser::CharBlock parserCharBlock;
@@ -153,14 +159,14 @@ static unsigned SayLabel(parser::Label label) {
153
159
}
154
160
155
161
struct UnitAnalysis {
156
- UnitAnalysis () { scopeModel.push_back ( 0 ); }
162
+ UnitAnalysis () { scopeModel.emplace_back ( ); }
157
163
158
164
SourceStmtList doStmtSources;
159
165
SourceStmtList formatStmtSources;
160
166
SourceStmtList otherStmtSources;
161
167
SourceStmtList assignStmtSources;
162
168
TargetStmtMap targetStmts;
163
- std::vector<ProxyForScope > scopeModel;
169
+ std::vector<ScopeInfo > scopeModel;
164
170
};
165
171
166
172
// Some parse tree record for statements simply wrap construct names;
@@ -532,33 +538,48 @@ class ParseTreeAnalyzer {
532
538
SemanticsContext &ErrorHandler () { return context_; }
533
539
534
540
private:
535
- bool PushSubscope () {
536
- programUnits_.back ().scopeModel .push_back (currentScope_);
537
- currentScope_ = programUnits_.back ().scopeModel .size () - 1 ;
538
- return true ;
541
+ ScopeInfo &PushScope () {
542
+ auto &model{programUnits_.back ().scopeModel };
543
+ int newDepth{model.empty () ? 1 : model[currentScope_].depth + 1 };
544
+ ScopeInfo &result{model.emplace_back ()};
545
+ result.parent = currentScope_;
546
+ result.depth = newDepth;
547
+ currentScope_ = model.size () - 1 ;
548
+ return result;
539
549
}
540
550
bool InitializeNewScopeContext () {
541
551
programUnits_.emplace_back (UnitAnalysis{});
542
552
currentScope_ = 0u ;
543
- return PushSubscope ();
553
+ PushScope ();
554
+ return true ;
544
555
}
545
- void PopScope () {
546
- currentScope_ = programUnits_.back ().scopeModel [currentScope_];
556
+ ScopeInfo &PopScope () {
557
+ ScopeInfo &result{programUnits_.back ().scopeModel [currentScope_]};
558
+ currentScope_ = result.parent ;
559
+ return result;
547
560
}
548
561
ProxyForScope ParentScope () {
549
- return programUnits_.back ().scopeModel [currentScope_];
562
+ return programUnits_.back ().scopeModel [currentScope_]. parent ;
550
563
}
551
564
bool SwitchToNewScope () {
552
- PopScope ();
553
- return PushSubscope ();
565
+ ScopeInfo &oldScope{PopScope ()};
566
+ bool isExteriorGotoFatal{oldScope.isExteriorGotoFatal };
567
+ PushScope ().isExteriorGotoFatal = isExteriorGotoFatal;
568
+ return true ;
554
569
}
555
570
556
571
template <typename A> bool PushConstructName (const A &a) {
557
572
const auto &optionalName{std::get<0 >(std::get<0 >(a.t ).statement .t )};
558
573
if (optionalName) {
559
574
constructNames_.emplace_back (optionalName->ToString ());
560
575
}
561
- return PushSubscope ();
576
+ // Gotos into this construct from outside it are diagnosed, and
577
+ // are fatal unless the construct is a DO, IF, or SELECT CASE.
578
+ PushScope ().isExteriorGotoFatal =
579
+ !(std::is_same_v<A, parser::DoConstruct> ||
580
+ std::is_same_v<A, parser::IfConstruct> ||
581
+ std::is_same_v<A, parser::CaseConstruct>);
582
+ return true ;
562
583
}
563
584
bool PushConstructName (const parser::BlockConstruct &blockConstruct) {
564
585
const auto &optionalName{
@@ -567,7 +588,8 @@ class ParseTreeAnalyzer {
567
588
if (optionalName) {
568
589
constructNames_.emplace_back (optionalName->ToString ());
569
590
}
570
- return PushSubscope ();
591
+ PushScope ().isExteriorGotoFatal = true ;
592
+ return true ;
571
593
}
572
594
template <typename A> void PopConstructNameIfPresent (const A &a) {
573
595
const auto &optionalName{std::get<0 >(std::get<0 >(a.t ).statement .t )};
@@ -796,9 +818,9 @@ class ParseTreeAnalyzer {
796
818
std::vector<std::string> constructNames_;
797
819
};
798
820
799
- bool InInclusiveScope (const std::vector<ProxyForScope > &scopes,
800
- ProxyForScope tail, ProxyForScope head) {
801
- for (; tail != head; tail = scopes[tail]) {
821
+ bool InInclusiveScope (const std::vector<ScopeInfo > &scopes, ProxyForScope tail ,
822
+ ProxyForScope head) {
823
+ for (; tail != head; tail = scopes[tail]. parent ) {
802
824
if (!HasScope (tail)) {
803
825
return false ;
804
826
}
@@ -881,13 +903,13 @@ parser::CharBlock SkipLabel(const parser::CharBlock &position) {
881
903
}
882
904
883
905
ProxyForScope ParentScope (
884
- const std::vector<ProxyForScope > &scopes, ProxyForScope scope) {
885
- return scopes[scope];
906
+ const std::vector<ScopeInfo > &scopes, ProxyForScope scope) {
907
+ return scopes[scope]. parent ;
886
908
}
887
909
888
910
void CheckLabelDoConstraints (const SourceStmtList &dos,
889
911
const SourceStmtList &branches, const TargetStmtMap &labels,
890
- const std::vector<ProxyForScope > &scopes, SemanticsContext &context) {
912
+ const std::vector<ScopeInfo > &scopes, SemanticsContext &context) {
891
913
IndexList loopBodies;
892
914
for (const auto &stmt : dos) {
893
915
const auto &label{stmt.parserLabel };
@@ -936,7 +958,7 @@ void CheckLabelDoConstraints(const SourceStmtList &dos,
936
958
937
959
// 6.2.5
938
960
void CheckScopeConstraints (const SourceStmtList &stmts,
939
- const TargetStmtMap &labels, const std::vector<ProxyForScope > &scopes,
961
+ const TargetStmtMap &labels, const std::vector<ScopeInfo > &scopes,
940
962
SemanticsContext &context) {
941
963
for (const auto &stmt : stmts) {
942
964
const auto &label{stmt.parserLabel };
@@ -955,8 +977,22 @@ void CheckScopeConstraints(const SourceStmtList &stmts,
955
977
TargetStatementEnum::Format)) {
956
978
continue ;
957
979
}
980
+ bool isFatal{false };
981
+ ProxyForScope fromScope{scope};
982
+ for (ProxyForScope toScope{target.proxyForScope }; fromScope != toScope;
983
+ toScope = scopes[toScope].parent ) {
984
+ if (scopes[toScope].isExteriorGotoFatal ) {
985
+ isFatal = true ;
986
+ break ;
987
+ }
988
+ if (scopes[toScope].depth == scopes[fromScope].depth ) {
989
+ fromScope = scopes[fromScope].parent ;
990
+ }
991
+ }
958
992
context.Say (position,
959
- " Label '%u' is in a construct that prevents its use as a branch target here" _en_US,
993
+ isFatal
994
+ ? " Label '%u' is in a construct that prevents its use as a branch target here" _err_en_US
995
+ : " Label '%u' is in a construct that prevents its use as a branch target here" _en_US,
960
996
SayLabel (label));
961
997
}
962
998
}
@@ -990,7 +1026,7 @@ void CheckBranchTargetConstraints(const SourceStmtList &stmts,
990
1026
}
991
1027
992
1028
void CheckBranchConstraints (const SourceStmtList &branches,
993
- const TargetStmtMap &labels, const std::vector<ProxyForScope > &scopes,
1029
+ const TargetStmtMap &labels, const std::vector<ScopeInfo > &scopes,
994
1030
SemanticsContext &context) {
995
1031
CheckScopeConstraints (branches, labels, scopes, context);
996
1032
CheckBranchTargetConstraints (branches, labels, context);
@@ -1015,7 +1051,7 @@ void CheckDataXferTargetConstraints(const SourceStmtList &stmts,
1015
1051
}
1016
1052
1017
1053
void CheckDataTransferConstraints (const SourceStmtList &dataTransfers,
1018
- const TargetStmtMap &labels, const std::vector<ProxyForScope > &scopes,
1054
+ const TargetStmtMap &labels, const std::vector<ScopeInfo > &scopes,
1019
1055
SemanticsContext &context) {
1020
1056
CheckScopeConstraints (dataTransfers, labels, scopes, context);
1021
1057
CheckDataXferTargetConstraints (dataTransfers, labels, context);
@@ -1045,7 +1081,7 @@ void CheckAssignTargetConstraints(const SourceStmtList &stmts,
1045
1081
}
1046
1082
1047
1083
void CheckAssignConstraints (const SourceStmtList &assigns,
1048
- const TargetStmtMap &labels, const std::vector<ProxyForScope > &scopes,
1084
+ const TargetStmtMap &labels, const std::vector<ScopeInfo > &scopes,
1049
1085
SemanticsContext &context) {
1050
1086
CheckScopeConstraints (assigns, labels, scopes, context);
1051
1087
CheckAssignTargetConstraints (assigns, labels, context);
0 commit comments