Revised patch for noreturn warnings

Zack Weinberg zack@wolery.cumb.org
Tue Apr 4 14:30:00 GMT 2000


This is a slightly revised version of the patch I sent yesterday,
which doesn't break anything.  I don't know why deducing that
functions are noreturn on the fly breaks things, but not doing it is
safe.

zw

	* flags.h (has_sibcall): New global.
	* rtl.h (NORETURN_CALL_PLACEHOLDER_P): New macro.
	* sibcall.c (optimize_sibling_and_tail_recursive_calls): Set
	has_sibcall if the function makes at least one sibcall to a
	function that does return.  Use NORETURN_CALL_PLACEHOLDER_P to
	detect sibcalls to functions that don't return.
	* calls.c (expand_call): Set NORETURN_CALL_PLACEHOLDER_P on
	generated CALL_PLACEHOLDERS to match is_volatile.

	* c-decl.c (finish_function): If has_sibcall is set, set
	current_function_returns_null or current_function_returns_value
	as appropriate.  Tweak error messages.
	* noreturn-1.c: Tweak regexps to match error messages.

===================================================================
Index: flags.h
--- flags.h	2000/03/29 09:54:30	1.41
+++ flags.h	2000/04/04 21:25:25
@@ -522,6 +522,12 @@ extern int frame_pointer_needed;
 
 extern int can_reach_end;
 
+/* Set nonzero if optimize_sibling_and_tail_recursive_calls finds that
+   this function makes a sibling call which returns (to this function's
+   caller).  Unlike can_reach_end, the front end need not clear this.  */
+
+extern int has_sibcall;
+
 /* Nonzero if GCC must add code to check memory access (used by Checker).  */
 
 extern int flag_check_memory_usage;
==================================================================
Index: rtl.h
--- rtl.h	2000/03/31 16:24:30	1.183
+++ rtl.h	2000/04/04 21:25:26
@@ -142,6 +142,7 @@ typedef struct rtx_def
      if it is deleted.
      1 in a REG expression if corresponds to a variable declared by the user.
      0 for an internally generated temporary.
+     In a CALL_PLACEHOLDER, 1 if the call does not return.
      In a SYMBOL_REF, this flag is used for machine-specific purposes.
      In a LABEL_REF or in a REG_LABEL note, this is LABEL_REF_NONLOCAL_P.  */
   unsigned int volatil : 1;
@@ -387,6 +388,9 @@ extern void rtvec_check_failed_bounds PA
 
 /* 1 if insn (assumed to be a CALL_INSN) is a sibling call.  */
 #define SIBLING_CALL_P(INSN) ((INSN)->jump)
+
+/* 1 if pattern is a noreturn CALL_PLACEHOLDER.  */
+#define NORETURN_CALL_PLACEHOLDER_P(PATTERN) ((PATTERN)->volatil)
 
 /* 1 if insn is a branch that should not unconditionally execute its
    delay slots, i.e., it is an annulled branch.   */
===================================================================
Index: sibcall.c
--- sibcall.c	2000/03/28 21:03:37	1.4
+++ sibcall.c	2000/04/04 21:25:26
@@ -364,6 +364,11 @@ replace_call_placeholder (insn, use)
   NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
 }
 
+/* optimize_sibling_and_tail_recursive_calls sets this flag if the
+   current function exits by making a sibcall.  */
+
+int has_sibcall;
+
 /* Given a (possibly empty) set of potential sibling or tail recursion call
    sites, determine if optimization is possible.
 
@@ -380,6 +385,7 @@ optimize_sibling_and_tail_recursive_call
   basic_block alternate_exit = EXIT_BLOCK_PTR;
   int current_function_uses_addressof;
   int successful_sibling_call = 0;
+  int sibcall_returns = 0;
   int replaced_call_placeholder = 0;
   edge e;
 
@@ -553,7 +559,11 @@ success:
 	     a tail/sibling call.  */
   
 	  if (sibcall)
-	    successful_sibling_call = 1;
+	    {
+	      successful_sibling_call = 1;
+	      if (! NORETURN_CALL_PLACEHOLDER_P (PATTERN (insn)))
+		sibcall_returns = 1;
+	    }
 	  replaced_call_placeholder = 1;
 	  replace_call_placeholder (insn, 
 				    tailrecursion != 0 
@@ -563,6 +573,8 @@ success:
 					 : sibcall_use_normal);
 	}
     }
+
+  has_sibcall = successful_sibling_call && sibcall_returns;
 
   /* A sibling call sequence invalidates any REG_EQUIV notes made for
      this function's incoming arguments. 
===================================================================
Index: calls.c
--- calls.c	2000/04/04 17:19:29	1.113
+++ calls.c	2000/04/04 21:25:27
@@ -2234,8 +2234,8 @@ expand_call (exp, target, ignore)
 	 recursion "call".  That way we know any adjustment after the tail
 	 recursion call can be ignored if we indeed use the tail recursion
 	 call expansion.  */
-      int save_pending_stack_adjust;
-      int save_stack_pointer_delta;
+      int save_pending_stack_adjust = 0;
+      int save_stack_pointer_delta = 0;
       rtx insns;
       rtx before_call, next_arg_reg;
 
@@ -2245,8 +2245,6 @@ expand_call (exp, target, ignore)
 	  if (! try_tail_call 
 #ifdef HAVE_sibcall_epilogue
 	      || ! HAVE_sibcall_epilogue
-#else
-	      || 1
 #endif
 	      /* The structure value address is used and modified in the
 		 loop below.  It does not seem worth the effort to save and
@@ -3126,6 +3124,7 @@ expand_call (exp, target, ignore)
      One of them will be selected later.  */
   if (tail_recursion_insns || tail_call_insns)
     {
+      rtx callplace;
       /* The tail recursion label must be kept around.  We could expose
 	 its use in the CALL_PLACEHOLDER, but that creates unwanted edges
 	 and makes determining true tail recursion sites difficult.
@@ -3134,10 +3133,12 @@ expand_call (exp, target, ignore)
 	 one of the call sequences after rtl generation is complete.  */
       if (tail_recursion_insns)
 	LABEL_PRESERVE_P (tail_recursion_label) = 1;
-      emit_call_insn (gen_rtx_CALL_PLACEHOLDER (VOIDmode, normal_call_insns,
-						tail_call_insns,
-						tail_recursion_insns,
-						tail_recursion_label));
+      callplace = gen_rtx_CALL_PLACEHOLDER (VOIDmode, normal_call_insns,
+					    tail_call_insns,
+					    tail_recursion_insns,
+					    tail_recursion_label);
+      NORETURN_CALL_PLACEHOLDER_P (callplace) = is_volatile;
+      emit_call_insn (callplace);
     }
   else
     emit_insns (normal_call_insns);
===================================================================
Index: c-decl.c
--- c-decl.c	2000/03/27 01:26:16	1.105
+++ c-decl.c	2000/04/04 21:25:28
@@ -6504,16 +6504,25 @@ finish_function (nested)
 
   current_function_returns_null |= can_reach_end;
 
-  if (warn_missing_noreturn
-      && !TREE_THIS_VOLATILE (fndecl)
-      && !current_function_returns_null
-      && !current_function_returns_value)
-    warning ("function might be possible candidate for attribute `noreturn'");
+  /* If the current function makes a sibcall, that means it returns
+     what it's supposed to return - either null or value.  */
+  if (has_sibcall)
+    {
+      if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))) == void_type_node)
+	current_function_returns_null = 1;
+      else
+	current_function_returns_value = 1;
+    }
 
+  if (!current_function_returns_null && !current_function_returns_value
+      && warn_missing_noreturn && !TREE_THIS_VOLATILE (fndecl))
+    warning ("function might be a candidate for the noreturn attribute");
+
   if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null)
-    warning ("`noreturn' function does return");
+    warning ("noreturn function does return");
   else if (warn_return_type && can_reach_end
-	   && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))) != void_type_node)
+	   && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl)))
+	       != void_type_node))
     /* If this function returns non-void and control can drop through,
        complain.  */
     warning ("control reaches end of non-void function");
===================================================================
Index: testsuite/gcc.dg/noreturn-1.c
--- testsuite/gcc.dg/noreturn-1.c	2000/03/21 19:08:19	1.4
+++ testsuite/gcc.dg/noreturn-1.c	2000/04/04 21:29:51
@@ -6,7 +6,7 @@ extern void foo1(void) __attribute__ ((_
 void
 foo1(void)
 {
-} /* { dg-warning "`noreturn' function does return" "detect falling off end of noreturn" } */
+} /* { dg-warning "noreturn function does return" "detect falling off end of noreturn" } */
 
 extern void foo2(void) __attribute__ ((__noreturn__));
 void
@@ -26,14 +26,14 @@ void
 foo4(void)
 {
   exit(0);
-} /* { dg-warning "candidate for attribute `noreturn'" "detect noreturn candidate" } */
+} /* { dg-warning "candidate for the noreturn attribute" "detect noreturn candidate" } */
 
 extern void foo5(void) __attribute__ ((__noreturn__));
 void
 foo5(void)
 {
   return; /* { dg-warning "`noreturn' has a `return' statement" "detect invalid return" } */
-} /* { dg-warning "`noreturn' function does return" "detect return from noreturn" } */
+} /* { dg-warning "noreturn function does return" "detect return from noreturn" } */
 
 extern void foo6(void);
 void
@@ -54,4 +54,4 @@ void
 foo8(void)
 {
   foo7();
-} /* { dg-warning "`noreturn' function does return" "detect return from tail call" } */
+} /* { dg-warning "noreturn function does return" "detect return from tail call" } */


More information about the Gcc-patches mailing list