From 20f18c3ce14154eb477226aa48a12ebd32f9ead4 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 23 Jan 2014 13:54:08 -0500 Subject: 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 --- gcc/cp/ChangeLog | 14 +++++++++++ gcc/cp/cp-tree.h | 11 +++++++++ gcc/cp/decl.c | 3 +++ gcc/cp/parser.c | 2 ++ gcc/cp/pt.c | 4 +++ gcc/cp/semantics.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 103 insertions(+), 2 deletions(-) (limited to 'gcc/cp') 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 + 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 *x_local_names; + /* Tracking possibly infinite loops. This is a vec only because + vec doesn't work with gtype. */ + vec *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); -- cgit v1.1