Re: [patch] Fix spurious 'noreturn' function does return warning at -O0 (2)

2012-07-25 Thread Richard Henderson
On 07/18/2012 05:48 AM, Eric Botcazou wrote:
 2012-07-18  Eric Botcazou  ebotca...@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  ebotca...@adacore.com
 
   * gnat.dg/noreturn5.ad[sb]: New test.


Ok.


r~


[patch] Fix spurious 'noreturn' function does return warning at -O0 (2)

2012-07-18 Thread Eric Botcazou
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  ebotca...@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  ebotca...@adacore.com

* gnat.dg/noreturn5.ad[sb]: New test.


-- 
Eric Botcazou
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