Patchwork Fix spurious 'noreturn' function does return warning at -O0 (2)

login
register
mail settings
Submitter Eric Botcazou
Date July 18, 2012, 12:48 p.m.
Message ID <201207181448.31656.ebotcazou@adacore.com>
Download mbox | patch
Permalink /patch/171662/
State New
Headers show

Comments

Eric Botcazou - July 18, 2012, 12:48 p.m.
This fixes a spurious 'noreturn' function does return warning at -O0 on code 
involving an exception block.  I overlooked this case when I implemented the 
mechanism in gimple-low.c during the 4.5 development phase.

Tested on x86_64-suse-linux, OK for the mainline?


2012-07-18  Eric Botcazou  <ebotcazou@adacore.com>

	* gimple-low.c (lower_try_catch): New function.
	(lower_stmt) <GIMPLE_TRY>: Use it to lower GIMPLE_TRY_CATCH.
	<GIMPLE_CATCH>: Delete.
	<GIMPLE_EH_FILTER>: Likewise.


2012-07-18  Eric Botcazou  <ebotcazou@adacore.com>

	* gnat.dg/noreturn5.ad[sb]: New test.
Richard Henderson - July 25, 2012, 6:24 p.m.
On 07/18/2012 05:48 AM, Eric Botcazou wrote:
> 2012-07-18  Eric Botcazou  <ebotcazou@adacore.com>
> 
> 	* gimple-low.c (lower_try_catch): New function.
> 	(lower_stmt) <GIMPLE_TRY>: Use it to lower GIMPLE_TRY_CATCH.
> 	<GIMPLE_CATCH>: Delete.
> 	<GIMPLE_EH_FILTER>: Likewise.
> 
> 
> 2012-07-18  Eric Botcazou  <ebotcazou@adacore.com>
> 
> 	* gnat.dg/noreturn5.ad[sb]: New test.


Ok.


r~

Patch

Index: gimple-low.c
===================================================================
--- gimple-low.c	(revision 189525)
+++ gimple-low.c	(working copy)
@@ -76,6 +76,7 @@  struct lower_data
 
 static void lower_stmt (gimple_stmt_iterator *, struct lower_data *);
 static void lower_gimple_bind (gimple_stmt_iterator *, struct lower_data *);
+static void lower_try_catch (gimple_stmt_iterator *, struct lower_data *);
 static void lower_gimple_return (gimple_stmt_iterator *, struct lower_data *);
 static void lower_builtin_setjmp (gimple_stmt_iterator *);
 
@@ -373,31 +374,28 @@  lower_stmt (gimple_stmt_iterator *gsi, s
       return;
 
     case GIMPLE_TRY:
-      {
-	bool try_cannot_fallthru;
-	lower_sequence (gimple_try_eval_ptr (stmt), data);
-	try_cannot_fallthru = data->cannot_fallthru;
-	data->cannot_fallthru = false;
-	lower_sequence (gimple_try_cleanup_ptr (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_ptr (stmt), data);
-      break;
-
-    case GIMPLE_EH_FILTER:
-      data->cannot_fallthru = false;
-      lower_sequence (gimple_eh_filter_failure_ptr (stmt), data);
-      break;
+      if (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH)
+	lower_try_catch (gsi, data);
+      else
+	{
+	  /* It must be a GIMPLE_TRY_FINALLY.  */
+	  bool cannot_fallthru;
+	  lower_sequence (gimple_try_eval_ptr (stmt), data);
+	  cannot_fallthru = data->cannot_fallthru;
+
+	  /* The finally clause is always executed after the try clause,
+	     so if it does not fall through, then the try-finally will not
+	     fall through.  Otherwise, if the try clause does not fall
+	     through, then when the finally clause falls through it will
+	     resume execution wherever the try clause was going.  So the
+	     whole try-finally will only fall through if both the try
+	     clause and the finally clause fall through.  */
+	  data->cannot_fallthru = false;
+	  lower_sequence (gimple_try_cleanup_ptr (stmt), data);
+	  data->cannot_fallthru |= cannot_fallthru;
+	  gsi_next (gsi);
+	}
+      return;
 
     case GIMPLE_EH_ELSE:
       lower_sequence (gimple_eh_else_n_body_ptr (stmt), data);
@@ -520,6 +518,67 @@  lower_gimple_bind (gimple_stmt_iterator
   gsi_remove (gsi, false);
 }
 
+/* Same as above, but for a GIMPLE_TRY_CATCH.  */
+
+static void
+lower_try_catch (gimple_stmt_iterator *gsi, struct lower_data *data)
+{
+  bool cannot_fallthru;
+  gimple stmt = gsi_stmt (*gsi);
+  gimple_stmt_iterator i;
+
+  /* We don't handle GIMPLE_TRY_FINALLY.  */
+  gcc_assert (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH);
+
+  lower_sequence (gimple_try_eval_ptr (stmt), data);
+  cannot_fallthru = data->cannot_fallthru;
+
+  i = gsi_start (*gimple_try_cleanup_ptr (stmt));
+  switch (gimple_code (gsi_stmt (i)))
+    {
+    case GIMPLE_CATCH:
+      /* We expect to see a sequence of GIMPLE_CATCH stmts, each with a
+	 catch expression and a body.  The whole try/catch may fall
+	 through iff any of the catch bodies falls through.  */
+      for (; !gsi_end_p (i); gsi_next (&i))
+	{
+	  data->cannot_fallthru = false;
+	  lower_sequence (gimple_catch_handler_ptr (gsi_stmt (i)), data);
+	  if (!data->cannot_fallthru)
+	    cannot_fallthru = false;
+	}
+      break;
+
+    case GIMPLE_EH_FILTER:
+      /* The exception filter expression only matters if there is an
+	 exception.  If the exception does not match EH_FILTER_TYPES,
+	 we will execute EH_FILTER_FAILURE, and we will fall through
+	 if that falls through.  If the exception does match
+	 EH_FILTER_TYPES, the stack unwinder will continue up the
+	 stack, so we will not fall through.  We don't know whether we
+	 will throw an exception which matches EH_FILTER_TYPES or not,
+	 so we just ignore EH_FILTER_TYPES and assume that we might
+	 throw an exception which doesn't match.  */
+      data->cannot_fallthru = false;
+      lower_sequence (gimple_eh_filter_failure_ptr (gsi_stmt (i)), data);
+      if (!data->cannot_fallthru)
+	cannot_fallthru = false;
+      break;
+
+    default:
+      /* This case represents statements to be executed when an
+	 exception occurs.  Those statements are implicitly followed
+	 by a GIMPLE_RESX to resume execution after the exception.  So
+	 in this case the try/catch never falls through.  */
+      data->cannot_fallthru = false;
+      lower_sequence (gimple_try_cleanup_ptr (stmt), data);
+      break;
+    }
+
+  data->cannot_fallthru = cannot_fallthru;
+  gsi_next (gsi);
+}
+
 /* Try to determine whether a TRY_CATCH expression can fall through.
    This is a subroutine of block_may_fallthru.  */