[flang-commits] [flang] 80f0bb5 - [flang] Distinguish error/warning cases for bad jumps into constructs
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Mon Nov 8 11:52:09 PST 2021
Author: Peter Klausler
Date: 2021-11-08T11:52:01-08:00
New Revision: 80f0bb5971e9a778e025d2bb91cbcb8b84a56d07
URL: https://github.com/llvm/llvm-project/commit/80f0bb5971e9a778e025d2bb91cbcb8b84a56d07
DIFF: https://github.com/llvm/llvm-project/commit/80f0bb5971e9a778e025d2bb91cbcb8b84a56d07.diff
LOG: [flang] Distinguish error/warning cases for bad jumps into constructs
Previously, jumps to labels in constructs from exterior statements
would elicit only a warning. Upgrade these to errors unless the
branch into the construct would enter into only DO, IF, and SELECT CASE
constructs, whose interiors don't scope variables or have other
set-up/tear-down semantics. Branches into these "safe" constructs
are still errors if they're nested in an unsafe construct that doesn't
also enclose the exterior branch statement.
Differential Revision: https://reviews.llvm.org/D113310
Added:
Modified:
flang/lib/Semantics/resolve-labels.cpp
flang/test/Semantics/label05.f90
flang/test/Semantics/label14.f90
Removed:
################################################################################
diff --git a/flang/lib/Semantics/resolve-labels.cpp b/flang/lib/Semantics/resolve-labels.cpp
index ff6105aa3a768..2363c832e1ec3 100644
--- a/flang/lib/Semantics/resolve-labels.cpp
+++ b/flang/lib/Semantics/resolve-labels.cpp
@@ -28,6 +28,12 @@ using IndexList = std::vector<std::pair<parser::CharBlock, parser::CharBlock>>;
// A ProxyForScope is an integral proxy for a Fortran scope. This is required
// because the parse tree does not actually have the scopes required.
using ProxyForScope = unsigned;
+// Minimal scope information
+struct ScopeInfo {
+ ProxyForScope parent{};
+ bool isExteriorGotoFatal{false};
+ int depth{0};
+};
struct LabeledStatementInfoTuplePOD {
ProxyForScope proxyForScope;
parser::CharBlock parserCharBlock;
@@ -153,14 +159,14 @@ static unsigned SayLabel(parser::Label label) {
}
struct UnitAnalysis {
- UnitAnalysis() { scopeModel.push_back(0); }
+ UnitAnalysis() { scopeModel.emplace_back(); }
SourceStmtList doStmtSources;
SourceStmtList formatStmtSources;
SourceStmtList otherStmtSources;
SourceStmtList assignStmtSources;
TargetStmtMap targetStmts;
- std::vector<ProxyForScope> scopeModel;
+ std::vector<ScopeInfo> scopeModel;
};
// Some parse tree record for statements simply wrap construct names;
@@ -532,25 +538,34 @@ class ParseTreeAnalyzer {
SemanticsContext &ErrorHandler() { return context_; }
private:
- bool PushSubscope() {
- programUnits_.back().scopeModel.push_back(currentScope_);
- currentScope_ = programUnits_.back().scopeModel.size() - 1;
- return true;
+ ScopeInfo &PushScope() {
+ auto &model{programUnits_.back().scopeModel};
+ int newDepth{model.empty() ? 1 : model[currentScope_].depth + 1};
+ ScopeInfo &result{model.emplace_back()};
+ result.parent = currentScope_;
+ result.depth = newDepth;
+ currentScope_ = model.size() - 1;
+ return result;
}
bool InitializeNewScopeContext() {
programUnits_.emplace_back(UnitAnalysis{});
currentScope_ = 0u;
- return PushSubscope();
+ PushScope();
+ return true;
}
- void PopScope() {
- currentScope_ = programUnits_.back().scopeModel[currentScope_];
+ ScopeInfo &PopScope() {
+ ScopeInfo &result{programUnits_.back().scopeModel[currentScope_]};
+ currentScope_ = result.parent;
+ return result;
}
ProxyForScope ParentScope() {
- return programUnits_.back().scopeModel[currentScope_];
+ return programUnits_.back().scopeModel[currentScope_].parent;
}
bool SwitchToNewScope() {
- PopScope();
- return PushSubscope();
+ ScopeInfo &oldScope{PopScope()};
+ bool isExteriorGotoFatal{oldScope.isExteriorGotoFatal};
+ PushScope().isExteriorGotoFatal = isExteriorGotoFatal;
+ return true;
}
template <typename A> bool PushConstructName(const A &a) {
@@ -558,7 +573,13 @@ class ParseTreeAnalyzer {
if (optionalName) {
constructNames_.emplace_back(optionalName->ToString());
}
- return PushSubscope();
+ // Gotos into this construct from outside it are diagnosed, and
+ // are fatal unless the construct is a DO, IF, or SELECT CASE.
+ PushScope().isExteriorGotoFatal =
+ !(std::is_same_v<A, parser::DoConstruct> ||
+ std::is_same_v<A, parser::IfConstruct> ||
+ std::is_same_v<A, parser::CaseConstruct>);
+ return true;
}
bool PushConstructName(const parser::BlockConstruct &blockConstruct) {
const auto &optionalName{
@@ -567,7 +588,8 @@ class ParseTreeAnalyzer {
if (optionalName) {
constructNames_.emplace_back(optionalName->ToString());
}
- return PushSubscope();
+ PushScope().isExteriorGotoFatal = true;
+ return true;
}
template <typename A> void PopConstructNameIfPresent(const A &a) {
const auto &optionalName{std::get<0>(std::get<0>(a.t).statement.t)};
@@ -796,9 +818,9 @@ class ParseTreeAnalyzer {
std::vector<std::string> constructNames_;
};
-bool InInclusiveScope(const std::vector<ProxyForScope> &scopes,
- ProxyForScope tail, ProxyForScope head) {
- for (; tail != head; tail = scopes[tail]) {
+bool InInclusiveScope(const std::vector<ScopeInfo> &scopes, ProxyForScope tail,
+ ProxyForScope head) {
+ for (; tail != head; tail = scopes[tail].parent) {
if (!HasScope(tail)) {
return false;
}
@@ -881,13 +903,13 @@ parser::CharBlock SkipLabel(const parser::CharBlock &position) {
}
ProxyForScope ParentScope(
- const std::vector<ProxyForScope> &scopes, ProxyForScope scope) {
- return scopes[scope];
+ const std::vector<ScopeInfo> &scopes, ProxyForScope scope) {
+ return scopes[scope].parent;
}
void CheckLabelDoConstraints(const SourceStmtList &dos,
const SourceStmtList &branches, const TargetStmtMap &labels,
- const std::vector<ProxyForScope> &scopes, SemanticsContext &context) {
+ const std::vector<ScopeInfo> &scopes, SemanticsContext &context) {
IndexList loopBodies;
for (const auto &stmt : dos) {
const auto &label{stmt.parserLabel};
@@ -936,7 +958,7 @@ void CheckLabelDoConstraints(const SourceStmtList &dos,
// 6.2.5
void CheckScopeConstraints(const SourceStmtList &stmts,
- const TargetStmtMap &labels, const std::vector<ProxyForScope> &scopes,
+ const TargetStmtMap &labels, const std::vector<ScopeInfo> &scopes,
SemanticsContext &context) {
for (const auto &stmt : stmts) {
const auto &label{stmt.parserLabel};
@@ -955,8 +977,22 @@ void CheckScopeConstraints(const SourceStmtList &stmts,
TargetStatementEnum::Format)) {
continue;
}
+ bool isFatal{false};
+ ProxyForScope fromScope{scope};
+ for (ProxyForScope toScope{target.proxyForScope}; fromScope != toScope;
+ toScope = scopes[toScope].parent) {
+ if (scopes[toScope].isExteriorGotoFatal) {
+ isFatal = true;
+ break;
+ }
+ if (scopes[toScope].depth == scopes[fromScope].depth) {
+ fromScope = scopes[fromScope].parent;
+ }
+ }
context.Say(position,
- "Label '%u' is in a construct that prevents its use as a branch target here"_en_US,
+ isFatal
+ ? "Label '%u' is in a construct that prevents its use as a branch target here"_err_en_US
+ : "Label '%u' is in a construct that prevents its use as a branch target here"_en_US,
SayLabel(label));
}
}
@@ -990,7 +1026,7 @@ void CheckBranchTargetConstraints(const SourceStmtList &stmts,
}
void CheckBranchConstraints(const SourceStmtList &branches,
- const TargetStmtMap &labels, const std::vector<ProxyForScope> &scopes,
+ const TargetStmtMap &labels, const std::vector<ScopeInfo> &scopes,
SemanticsContext &context) {
CheckScopeConstraints(branches, labels, scopes, context);
CheckBranchTargetConstraints(branches, labels, context);
@@ -1015,7 +1051,7 @@ void CheckDataXferTargetConstraints(const SourceStmtList &stmts,
}
void CheckDataTransferConstraints(const SourceStmtList &dataTransfers,
- const TargetStmtMap &labels, const std::vector<ProxyForScope> &scopes,
+ const TargetStmtMap &labels, const std::vector<ScopeInfo> &scopes,
SemanticsContext &context) {
CheckScopeConstraints(dataTransfers, labels, scopes, context);
CheckDataXferTargetConstraints(dataTransfers, labels, context);
@@ -1045,7 +1081,7 @@ void CheckAssignTargetConstraints(const SourceStmtList &stmts,
}
void CheckAssignConstraints(const SourceStmtList &assigns,
- const TargetStmtMap &labels, const std::vector<ProxyForScope> &scopes,
+ const TargetStmtMap &labels, const std::vector<ScopeInfo> &scopes,
SemanticsContext &context) {
CheckScopeConstraints(assigns, labels, scopes, context);
CheckAssignTargetConstraints(assigns, labels, context);
diff --git a/flang/test/Semantics/label05.f90 b/flang/test/Semantics/label05.f90
index 7084574a5790c..51fd90263911c 100644
--- a/flang/test/Semantics/label05.f90
+++ b/flang/test/Semantics/label05.f90
@@ -1,12 +1,13 @@
! RUN: not %flang_fc1 -fdebug-unparse-with-symbols %s 2>&1 | FileCheck %s
! CHECK: Label '50' was not found
+! CHECK-NOT: error: Label '55' is in a construct that prevents its use as a branch target here
! CHECK: Label '55' is in a construct that prevents its use as a branch target here
! CHECK: Label '70' is not a branch target
! CHECK: Control flow use of '70'
-! CHECK: Label '80' is in a construct that prevents its use as a branch target here
-! CHECK: Label '90' is in a construct that prevents its use as a branch target here
-! CHECK: Label '91' is in a construct that prevents its use as a branch target here
-! CHECK: Label '92' is in a construct that prevents its use as a branch target here
+! CHECK: error: Label '80' is in a construct that prevents its use as a branch target here
+! CHECK: error: Label '90' is in a construct that prevents its use as a branch target here
+! CHECK: error: Label '91' is in a construct that prevents its use as a branch target here
+! CHECK: error: Label '92' is in a construct that prevents its use as a branch target here
subroutine sub00(a,b,n,m)
real a(n,m)
diff --git a/flang/test/Semantics/label14.f90 b/flang/test/Semantics/label14.f90
index f310913f26283..7f03d829d88aa 100644
--- a/flang/test/Semantics/label14.f90
+++ b/flang/test/Semantics/label14.f90
@@ -1,8 +1,8 @@
! Tests implemented for this standard
-! 11.1.4 - 4 It is permissible to branch to and end-block-stmt only withinh its
+! 11.1.4 - 4 It is permissible to branch to an end-block-stmt only within its
! Block Construct
-! RUN: %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s
+! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s
! CHECK: Label '20' is in a construct that prevents its use as a branch target here
subroutine s1
More information about the flang-commits
mailing list