[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