* gimple-low.c (struct lower_data): Add cannot_fallthru field.
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 19 Oct 2009 18:15:49 +0000 (18:15 +0000)
committerebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 19 Oct 2009 18:15:49 +0000 (18:15 +0000)
(lower_stmt) <GIMPLE_BIND>: Add comment.
<GIMPLE_COND, GIMPLE_GOTO, GIMPLE_SWITCH>: Set cannot_fallthru to true
and return.
<GIMPLE_RETURN>: Remove the statement if cannot_fallthru is set.
Otherwise lower it and set cannot_fallthru to true.
<GIMPLE_TRY>: Update cannot_fallthru for GIMPLE_TRY_FINALLY and return.
<GIMPLE_CATCH, GIMPLE_EH_FILTER>; Set cannot_fallthru to false.
<GIMPLE_CALL>: Set cannot_fallthru to false for BUILT_IN_SETJMP and
to true for a noreturn call.  Do not remove statements.
<GIMPLE_OMP_PARALLEL, GIMPLE_OMP_TASK>: Set cannot_fallthru to false.
Set cannot_fallthru to false on function exit.
(gimple_stmt_may_fallthru) <GIMPLE_SWITCH>: Really return false.
<GIMPLE_ASSIGN>: Remove.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@152984 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/gimple-low.c
gcc/testsuite/ChangeLog
gcc/testsuite/gnat.dg/noreturn2.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/noreturn2.ads [new file with mode: 0644]

index c4048a5..9b85462 100644 (file)
@@ -1,3 +1,20 @@
+2009-10-19  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gimple-low.c (struct lower_data): Add cannot_fallthru field.
+       (lower_stmt) <GIMPLE_BIND>: Add comment.
+       <GIMPLE_COND, GIMPLE_GOTO, GIMPLE_SWITCH>: Set cannot_fallthru to true
+       and return.
+       <GIMPLE_RETURN>: Remove the statement if cannot_fallthru is set.
+       Otherwise lower it and set cannot_fallthru to true.
+       <GIMPLE_TRY>: Update cannot_fallthru for GIMPLE_TRY_FINALLY and return.
+       <GIMPLE_CATCH, GIMPLE_EH_FILTER>; Set cannot_fallthru to false.
+       <GIMPLE_CALL>: Set cannot_fallthru to false for BUILT_IN_SETJMP and
+       to true for a noreturn call.  Do not remove statements.
+       <GIMPLE_OMP_PARALLEL, GIMPLE_OMP_TASK>: Set cannot_fallthru to false.
+       Set cannot_fallthru to false on function exit.
+       (gimple_stmt_may_fallthru) <GIMPLE_SWITCH>: Really return false.
+       <GIMPLE_ASSIGN>: Remove.
+
 2009-10-19  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>
 
        * config/s390/s390.c (s390_z10_optimize_cmp): Don't touch FP compares.
index 39c7351..cce31e9 100644 (file)
@@ -76,6 +76,9 @@ struct lower_data
      of the function.  */
   VEC(return_statements_t,heap) *return_statements;
 
+  /* True if the current statement cannot fall through.  */
+  bool cannot_fallthru;
+
   /* True if the function calls __builtin_setjmp.  */
   bool calls_builtin_setjmp;
 };
@@ -317,7 +320,12 @@ lower_omp_directive (gimple_stmt_iterator *gsi, struct lower_data *data)
 }
 
 
-/* Lower statement GSI.  DATA is passed through the recursion.  */
+/* Lower statement GSI.  DATA is passed through the recursion.  We try to
+   track the fallthruness of statements and get rid of unreachable return
+   statements in order to prevent the EH lowering pass from adding useless
+   edges that can cause bogus warnings to be issued later; this guess need
+   not be 100% accurate, simply be conservative and reset cannot_fallthru
+   to false if we don't know.  */
 
 static void
 lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
@@ -330,36 +338,61 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
     {
     case GIMPLE_BIND:
       lower_gimple_bind (gsi, data);
+      /* Propagate fallthruness.  */
       return;
 
     case GIMPLE_COND:
-      /* The gimplifier has already lowered this into gotos.  */
-      break;
+    case GIMPLE_GOTO:
+    case GIMPLE_SWITCH:
+      data->cannot_fallthru = true;
+      gsi_next (gsi);
+      return;
 
     case GIMPLE_RETURN:
-      lower_gimple_return (gsi, data);
+      if (data->cannot_fallthru)
+       {
+         gsi_remove (gsi, false);
+         /* Propagate fallthruness.  */
+       }
+      else
+       {
+         lower_gimple_return (gsi, data);
+         data->cannot_fallthru = true;
+       }
       return;
 
     case GIMPLE_TRY:
-      lower_sequence (gimple_try_eval (stmt), data);
-      lower_sequence (gimple_try_cleanup (stmt), data);
+      {
+       bool try_cannot_fallthru;
+       lower_sequence (gimple_try_eval (stmt), data);
+       try_cannot_fallthru = data->cannot_fallthru;
+       data->cannot_fallthru = false;
+       lower_sequence (gimple_try_cleanup (stmt), data);
+       /* See gimple_stmt_may_fallthru for the rationale.  */
+       if (gimple_try_kind (stmt) == GIMPLE_TRY_FINALLY)
+         {
+           data->cannot_fallthru |= try_cannot_fallthru;
+           gsi_next (gsi);
+           return;
+         }
+      }
       break;
 
     case GIMPLE_CATCH:
+      data->cannot_fallthru = false;
       lower_sequence (gimple_catch_handler (stmt), data);
       break;
 
     case GIMPLE_EH_FILTER:
+      data->cannot_fallthru = false;
       lower_sequence (gimple_eh_filter_failure (stmt), data);
       break;
 
     case GIMPLE_NOP:
     case GIMPLE_ASM:
     case GIMPLE_ASSIGN:
-    case GIMPLE_GOTO:
     case GIMPLE_PREDICT:
     case GIMPLE_LABEL:
-    case GIMPLE_SWITCH:
     case GIMPLE_EH_MUST_NOT_THROW:
     case GIMPLE_OMP_FOR:
     case GIMPLE_OMP_SECTIONS:
@@ -383,21 +416,16 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
            && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
            && DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP)
          {
-           data->calls_builtin_setjmp = true;
            lower_builtin_setjmp (gsi);
+           data->cannot_fallthru = false;
+           data->calls_builtin_setjmp = true;
            return;
          }
 
-       /* After a noreturn call, remove a subsequent GOTO or RETURN that might
-          have been mechanically added; this will prevent the EH lowering pass
-          from adding useless edges and thus complicating the initial CFG.  */
        if (decl && (flags_from_decl_or_type (decl) & ECF_NORETURN))
          {
+           data->cannot_fallthru = true;
            gsi_next (gsi);
-           if (!gsi_end_p (*gsi)
-               && (gimple_code (gsi_stmt (*gsi)) == GIMPLE_GOTO
-                   || gimple_code (gsi_stmt (*gsi)) == GIMPLE_RETURN))
-             gsi_remove (gsi, false);
            return;
          }
       }
@@ -405,13 +433,16 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
 
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
+      data->cannot_fallthru = false;
       lower_omp_directive (gsi, data);
+      data->cannot_fallthru = false;
       return;
 
     default:
       gcc_unreachable ();
     }
 
+  data->cannot_fallthru = false;
   gsi_next (gsi);
 }
 
@@ -660,9 +691,9 @@ gimple_stmt_may_fallthru (gimple stmt)
       return false;
 
     case GIMPLE_SWITCH:
-      /* Switch has already been lowered and represents a
-        branch to a selected label and hence can not fall through.  */
-      return true;
+      /* Switch has already been lowered and represents a branch
+        to a selected label and hence can't fall through.  */
+      return false;
 
     case GIMPLE_COND:
       /* GIMPLE_COND's are already lowered into a two-way branch.  They
@@ -688,13 +719,10 @@ gimple_stmt_may_fallthru (gimple stmt)
       return (gimple_seq_may_fallthru (gimple_try_eval (stmt))
              && gimple_seq_may_fallthru (gimple_try_cleanup (stmt)));
 
-    case GIMPLE_ASSIGN:
-      return true;
-
     case GIMPLE_CALL:
       /* Functions that do not return do not fall through.  */
       return (gimple_call_flags (stmt) & ECF_NORETURN) == 0;
-    
+
     default:
       return true;
     }
@@ -744,7 +772,7 @@ lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data)
   gsi_remove (gsi, false);
 }
 
-/* Lower a __builtin_setjmp TSI.
+/* Lower a __builtin_setjmp GSI.
 
    __builtin_setjmp is passed a pointer to an array of five words (not
    all will be used on all machines).  It operates similarly to the C
index bce4d7c..1437ce6 100644 (file)
@@ -1,3 +1,7 @@
+2009-10-19  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gnat.dg/noreturn2.ad[sb]: New test.
+
 2009-10-19  Tobias Burnus  <burnus@net-b.de>
 
        PR fortran/41755
diff --git a/gcc/testsuite/gnat.dg/noreturn2.adb b/gcc/testsuite/gnat.dg/noreturn2.adb
new file mode 100644 (file)
index 0000000..5caf222
--- /dev/null
@@ -0,0 +1,23 @@
+-- { dg-do compile }
+
+package body Noreturn2 is
+
+   procedure Raise_Exception_No_Defer (Message : String);
+   pragma No_Return (Raise_Exception_No_Defer);
+
+   procedure Raise_From (X : Exception_Occurrence) is
+      Occurrence_Message : constant String := Exception_Message (X);
+   begin
+      if Occurrence_Message = "$" then
+         Raise_Exception_No_Defer (Occurrence_Message);
+      else
+         Raise_Exception_No_Defer ("::" & Occurrence_Message);
+      end if;
+   end;
+
+   procedure Raise_Exception_No_Defer (Message : String) is
+   begin
+     raise Program_Error;
+   end;
+
+end Noreturn2;
diff --git a/gcc/testsuite/gnat.dg/noreturn2.ads b/gcc/testsuite/gnat.dg/noreturn2.ads
new file mode 100644 (file)
index 0000000..1aaf4e9
--- /dev/null
@@ -0,0 +1,8 @@
+with Ada.Exceptions; use Ada.Exceptions;
+
+package Noreturn2 is
+
+   procedure Raise_From (X : Exception_Occurrence);
+   pragma No_Return (Raise_From);
+
+end Noreturn2;