[flang-commits] [flang] 48a8262 - [flang] Allow GOTO to containing END IF after ELSE

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Tue Aug 29 10:18:56 PDT 2023


Author: Peter Klausler
Date: 2023-08-29T10:14:41-07:00
New Revision: 48a8262cb8dce16b0e64cb1aec1d74dc96e5d551

URL: https://github.com/llvm/llvm-project/commit/48a8262cb8dce16b0e64cb1aec1d74dc96e5d551
DIFF: https://github.com/llvm/llvm-project/commit/48a8262cb8dce16b0e64cb1aec1d74dc96e5d551.diff

LOG: [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 https://github.com/llvm/llvm-project/issues/64654 for
llvm-test-suite/Fortran/gfortran/regression/goto_5.f90.

Differential Revision: https://reviews.llvm.org/D159040

Added: 
    flang/test/Semantics/label18.f90

Modified: 
    flang/lib/Semantics/resolve-labels.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/resolve-labels.cpp b/flang/lib/Semantics/resolve-labels.cpp
index f849b2238b0855..ac028019993cc6 100644
--- a/flang/lib/Semantics/resolve-labels.cpp
+++ b/flang/lib/Semantics/resolve-labels.cpp
@@ -239,8 +239,9 @@ class ParseTreeAnalyzer {
     auto targetFlags{ConstructBranchTargetFlags(statement)};
     if constexpr (common::HasMember<A, LabeledConstructStmts>) {
       AddTargetLabelDefinition(label.value(), targetFlags, ParentScope());
-    } else if constexpr (std::is_same_v<A, parser::EndSelectStmt>) {
-      // the label on an END SELECT is not in the last case
+    } else if constexpr (std::is_same_v<A, parser::EndIfStmt> ||
+        std::is_same_v<A, parser::EndSelectStmt>) {
+      // the label on an END IF/SELECT is not in the last part/case
       AddTargetLabelDefinition(label.value(), targetFlags, ParentScope(), true);
     } else if constexpr (common::HasMember<A, LabeledConstructEndStmts>) {
       constexpr bool isExecutableConstructEndStmt{true};
@@ -279,12 +280,17 @@ class ParseTreeAnalyzer {
   bool Pre(const parser::IfConstruct &ifConstruct) {
     return PushConstructName(ifConstruct);
   }
+  void Post(const parser::IfThenStmt &) { PushScope(); }
   bool Pre(const parser::IfConstruct::ElseIfBlock &) {
     return SwitchToNewScope();
   }
   bool Pre(const parser::IfConstruct::ElseBlock &) {
     return SwitchToNewScope();
   }
+  bool Pre(const parser::EndIfStmt &) {
+    PopScope();
+    return true;
+  }
   bool Pre(const parser::CaseConstruct &caseConstruct) {
     return PushConstructName(caseConstruct);
   }
@@ -1008,15 +1014,18 @@ void CheckScopeConstraints(const SourceStmtList &stmts,
       }
       bool isFatal{false};
       ProxyForScope fromScope{scope};
-      for (ProxyForScope toScope{target.proxyForScope}; fromScope != toScope;
+      for (ProxyForScope toScope{target.proxyForScope}; HasScope(toScope);
            toScope = scopes[toScope].parent) {
+        while (scopes[fromScope].depth > scopes[toScope].depth) {
+          fromScope = scopes[fromScope].parent;
+        }
+        if (toScope == fromScope) {
+          break;
+        }
         if (scopes[toScope].isExteriorGotoFatal) {
           isFatal = true;
           break;
         }
-        if (scopes[toScope].depth == scopes[fromScope].depth) {
-          fromScope = scopes[fromScope].parent;
-        }
       }
       context.Say(position,
           isFatal

diff  --git a/flang/test/Semantics/label18.f90 b/flang/test/Semantics/label18.f90
new file mode 100644
index 00000000000000..a9f3e50237f982
--- /dev/null
+++ b/flang/test/Semantics/label18.f90
@@ -0,0 +1,18 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -Werror
+program main
+  if (.true.) then
+    do j = 1, 2
+      goto 1 ! ok; used to cause looping in label resolution
+    end do
+  else
+    goto 1 ! ok
+1 end if
+  if (.true.) then
+    do j = 1, 2
+      !WARNING: Label '1' is in a construct that should not be used as a branch target here
+      goto 1
+    end do
+  end if
+  !WARNING: Label '1' is in a construct that should not be used as a branch target here
+  goto 1
+end


        


More information about the flang-commits mailing list