aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2014-01-23 13:54:08 -0500
committerJason Merrill <jason@gcc.gnu.org>2014-01-23 13:54:08 -0500
commit20f18c3ce14154eb477226aa48a12ebd32f9ead4 (patch)
treeb80e9c1dd9cea4b9e0fd4dafbb7b382397e04a7d /gcc/cp
parent928d850fcd999ed82cf5f2cfb4e24779f973e2d4 (diff)
downloadgcc-20f18c3ce14154eb477226aa48a12ebd32f9ead4.zip
gcc-20f18c3ce14154eb477226aa48a12ebd32f9ead4.tar.gz
gcc-20f18c3ce14154eb477226aa48a12ebd32f9ead4.tar.bz2
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
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog14
-rw-r--r--gcc/cp/cp-tree.h11
-rw-r--r--gcc/cp/decl.c3
-rw-r--r--gcc/cp/parser.c2
-rw-r--r--gcc/cp/pt.c4
-rw-r--r--gcc/cp/semantics.c71
6 files changed, 103 insertions, 2 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index c9145e6..2428204 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,19 @@
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.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 96af562f..ab75db8 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 9918416..f4819a6 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c02de3b..e12a528 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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");
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index a91df4c..930ca29 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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. */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index bba00f4..3a8daca 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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);