Commit 20f18c3c by Jason Merrill Committed by Jason Merrill

re PR c++/55189 (enable -Wreturn-type by default)

	PR c++/55189
	* cp-tree.h (struct language_function): Add infinite_loop and
	infinite_loops.
	(current_function_infinite_loop): New.
	* semantics.c (begin_maybe_infinite_loop, end_maybe_infinite_loop)
	(break_maybe_infinite_loop): New.
	(finish_while_stmt_cond, finish_while_stmt, begin_do_stmt)
	(finish_do_stmt, finish_for_cond, finish_for_stmt)
	(begin_range_for_stmt): Use them.
	* decl.c (finish_function): Don't warn about missing return
	if current_function_infinite_loop.
	* pt.c (instantiate_decl): Copy current_function_infinite_loop.
	* parser.c (cp_parser_jump_statement): Call break_maybe_infinite_loop.

From-SVN: r207001
parent 928d850f
2014-01-23 Jason Merrill <jason@redhat.com>
PR c++/55189
* cp-tree.h (struct language_function): Add infinite_loop and
infinite_loops.
(current_function_infinite_loop): New.
* semantics.c (begin_maybe_infinite_loop, end_maybe_infinite_loop)
(break_maybe_infinite_loop): New.
(finish_while_stmt_cond, finish_while_stmt, begin_do_stmt)
(finish_do_stmt, finish_for_cond, finish_for_stmt)
(begin_range_for_stmt): Use them.
* decl.c (finish_function): Don't warn about missing return
if current_function_infinite_loop.
* pt.c (instantiate_decl): Copy current_function_infinite_loop.
* parser.c (cp_parser_jump_statement): Call break_maybe_infinite_loop.
* call.c (build_op_delete_call): Use make_tree_vector and
release_tree_vector.
......
......@@ -1127,6 +1127,7 @@ struct GTY(()) language_function {
BOOL_BITFIELD returns_value : 1;
BOOL_BITFIELD returns_null : 1;
BOOL_BITFIELD returns_abnormally : 1;
BOOL_BITFIELD infinite_loop: 1;
BOOL_BITFIELD x_in_function_try_handler : 1;
BOOL_BITFIELD x_in_base_initializer : 1;
......@@ -1136,6 +1137,9 @@ struct GTY(()) language_function {
htab_t GTY((param_is(struct named_label_entry))) x_named_labels;
cp_binding_level *bindings;
vec<tree, va_gc> *x_local_names;
/* Tracking possibly infinite loops. This is a vec<tree> only because
vec<bool> doesn't work with gtype. */
vec<tree, va_gc> *infinite_loops;
htab_t GTY((param_is (struct cxx_int_tree_map))) extern_decl_map;
};
......@@ -1194,6 +1198,12 @@ struct GTY(()) language_function {
#define current_function_returns_abnormally \
cp_function_chain->returns_abnormally
/* Set to 0 at beginning of a function definition, set to 1 if we see an
obvious infinite loop. This can have false positives and false
negatives, so it should only be used as a heuristic. */
#define current_function_infinite_loop cp_function_chain->infinite_loop
/* Nonzero if we are processing a base initializer. Zero elsewhere. */
#define in_base_initializer cp_function_chain->x_in_base_initializer
......@@ -5671,6 +5681,7 @@ extern bool perform_or_defer_access_check (tree, tree, tree,
extern int stmts_are_full_exprs_p (void);
extern void init_cp_semantics (void);
extern tree do_poplevel (tree);
extern void break_maybe_infinite_loop (void);
extern void add_decl_expr (tree);
extern tree maybe_cleanup_point_expr_void (tree);
extern tree finish_expr_stmt (tree);
......
......@@ -14000,6 +14000,8 @@ finish_function (int flags)
&& !current_function_returns_value && !current_function_returns_null
/* Don't complain if we abort or throw. */
&& !current_function_returns_abnormally
/* Don't complain if there's an infinite loop. */
&& !current_function_infinite_loop
/* Don't complain if we are declared noreturn. */
&& !TREE_THIS_VOLATILE (fndecl)
&& !DECL_NAME (DECL_RESULT (fndecl))
......@@ -14064,6 +14066,7 @@ finish_function (int flags)
f->x_return_value = NULL;
f->bindings = NULL;
f->extern_decl_map = NULL;
f->infinite_loops = NULL;
}
/* Clear out the bits we don't need. */
local_names = NULL;
......
......@@ -10641,6 +10641,8 @@ cp_parser_jump_statement (cp_parser* parser)
gcc_assert ((in_statement & IN_SWITCH_STMT)
|| in_statement == IN_ITERATION_STMT);
statement = finish_break_stmt ();
if (in_statement == IN_ITERATION_STMT)
break_maybe_infinite_loop ();
break;
case IN_OMP_BLOCK:
error_at (token->location, "invalid exit from OpenMP structured block");
......
......@@ -19670,6 +19670,10 @@ instantiate_decl (tree d, int defer_ok,
so that finish_function knows where we are. */
input_location
= DECL_STRUCT_FUNCTION (code_pattern)->function_end_locus;
/* Remember if we saw an infinite loop in the template. */
current_function_infinite_loop
= DECL_STRUCT_FUNCTION (code_pattern)->language->infinite_loop;
}
/* We don't need the local specializations any more. */
......
......@@ -486,6 +486,62 @@ push_cleanup (tree decl, tree cleanup, bool eh_only)
CLEANUP_BODY (stmt) = push_stmt_list ();
}
/* Simple infinite loop tracking for -Wreturn-type. We keep a stack of all
the current loops, represented by 'NULL_TREE' if we've seen a possible
exit, and 'error_mark_node' if not. This is currently used only to
suppress the warning about a function with no return statements, and
therefore we don't bother noting returns as possible exits. We also
don't bother with gotos. */
static void
begin_maybe_infinite_loop (tree cond)
{
/* Only track this while parsing a function, not during instantiation. */
if (!cfun || (DECL_TEMPLATE_INSTANTIATION (current_function_decl)
&& !processing_template_decl))
return;
bool maybe_infinite = true;
if (cond)
{
cond = fold_non_dependent_expr (cond);
cond = maybe_constant_value (cond);
maybe_infinite = integer_nonzerop (cond);
}
vec_safe_push (cp_function_chain->infinite_loops,
maybe_infinite ? error_mark_node : NULL_TREE);
}
/* A break is a possible exit for the current loop. */
void
break_maybe_infinite_loop (void)
{
if (!cfun)
return;
cp_function_chain->infinite_loops->last() = NULL_TREE;
}
/* If we reach the end of the loop without seeing a possible exit, we have
an infinite loop. */
static void
end_maybe_infinite_loop (tree cond)
{
if (!cfun || (DECL_TEMPLATE_INSTANTIATION (current_function_decl)
&& !processing_template_decl))
return;
tree current = cp_function_chain->infinite_loops->pop();
if (current != NULL_TREE)
{
cond = fold_non_dependent_expr (cond);
cond = maybe_constant_value (cond);
if (integer_nonzerop (cond))
current_function_infinite_loop = 1;
}
}
/* Begin a conditional that might contain a declaration. When generating
normal code, we want the declaration to appear before the statement
containing the conditional. When generating template code, we want the
......@@ -732,7 +788,9 @@ begin_while_stmt (void)
void
finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep)
{
finish_cond (&WHILE_COND (while_stmt), maybe_convert_cond (cond));
cond = maybe_convert_cond (cond);
finish_cond (&WHILE_COND (while_stmt), cond);
begin_maybe_infinite_loop (cond);
if (ivdep && cond != error_mark_node)
WHILE_COND (while_stmt) = build2 (ANNOTATE_EXPR,
TREE_TYPE (WHILE_COND (while_stmt)),
......@@ -747,6 +805,7 @@ finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep)
void
finish_while_stmt (tree while_stmt)
{
end_maybe_infinite_loop (boolean_true_node);
WHILE_BODY (while_stmt) = do_poplevel (WHILE_BODY (while_stmt));
}
......@@ -757,6 +816,7 @@ tree
begin_do_stmt (void)
{
tree r = build_stmt (input_location, DO_STMT, NULL_TREE, NULL_TREE);
begin_maybe_infinite_loop (boolean_true_node);
add_stmt (r);
DO_BODY (r) = push_stmt_list ();
return r;
......@@ -784,6 +844,7 @@ void
finish_do_stmt (tree cond, tree do_stmt, bool ivdep)
{
cond = maybe_convert_cond (cond);
end_maybe_infinite_loop (cond);
if (ivdep && cond != error_mark_node)
cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
build_int_cst (integer_type_node, annot_expr_ivdep_kind));
......@@ -891,7 +952,9 @@ finish_for_init_stmt (tree for_stmt)
void
finish_for_cond (tree cond, tree for_stmt, bool ivdep)
{
finish_cond (&FOR_COND (for_stmt), maybe_convert_cond (cond));
cond = maybe_convert_cond (cond);
finish_cond (&FOR_COND (for_stmt), cond);
begin_maybe_infinite_loop (cond);
if (ivdep && cond != error_mark_node)
FOR_COND (for_stmt) = build2 (ANNOTATE_EXPR,
TREE_TYPE (FOR_COND (for_stmt)),
......@@ -940,6 +1003,8 @@ finish_for_expr (tree expr, tree for_stmt)
void
finish_for_stmt (tree for_stmt)
{
end_maybe_infinite_loop (boolean_true_node);
if (TREE_CODE (for_stmt) == RANGE_FOR_STMT)
RANGE_FOR_BODY (for_stmt) = do_poplevel (RANGE_FOR_BODY (for_stmt));
else
......@@ -968,6 +1033,8 @@ begin_range_for_stmt (tree scope, tree init)
{
tree r;
begin_maybe_infinite_loop (boolean_false_node);
r = build_stmt (input_location, RANGE_FOR_STMT,
NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
......
// related to PR c++/55189
// { dg-options "-Wreturn-type" }
int f1()
{
while (true) { }
}
int f2()
{
while (true) { break; }
} // { dg-warning "no return statement" }
int f3()
{
for (;;) {}
}
int f4()
{
for (;;) {break;}
} // { dg-warning "no return statement" }
int f5()
{
do {} while(true);
}
int f6()
{
do {break;} while(true);
} // { dg-warning "no return statement" }
int f7()
{
for(;;)
while (true) {break;}
}
int f8()
{
for(;;)
{
while (true) {}
break;
}
}
template <class T>
T f9()
{
for(;;) { }
}
template int f9();
template <class T>
T f10()
{
for(;;) { break; }
} // { dg-warning "no return statement" }
template int f10();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment