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