diff options
Diffstat (limited to 'gcc/tree-cfg.c')
-rw-r--r-- | gcc/tree-cfg.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index bd6940f6fa7..964a537266f 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -7370,3 +7370,100 @@ struct gimple_opt_pass pass_warn_function_noreturn = 0 /* todo_flags_finish */ } }; + + +/* Walk a gimplified function and warn for functions whose return value is + ignored and attribute((warn_unused_result)) is set. This is done before + inlining, so we don't have to worry about that. */ + +static void +do_warn_unused_result (gimple_seq seq) +{ + tree fdecl, ftype; + gimple_stmt_iterator i; + + for (i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i)) + { + gimple g = gsi_stmt (i); + + switch (gimple_code (g)) + { + case GIMPLE_BIND: + do_warn_unused_result (gimple_bind_body (g)); + break; + case GIMPLE_TRY: + do_warn_unused_result (gimple_try_eval (g)); + do_warn_unused_result (gimple_try_cleanup (g)); + break; + case GIMPLE_CATCH: + do_warn_unused_result (gimple_catch_handler (g)); + break; + case GIMPLE_EH_FILTER: + do_warn_unused_result (gimple_eh_filter_failure (g)); + break; + + case GIMPLE_CALL: + if (gimple_call_lhs (g)) + break; + + /* This is a naked call, as opposed to a GIMPLE_CALL with an + LHS. All calls whose value is ignored should be + represented like this. Look for the attribute. */ + fdecl = gimple_call_fndecl (g); + ftype = TREE_TYPE (TREE_TYPE (gimple_call_fn (g))); + + if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (ftype))) + { + location_t loc = gimple_location (g); + + if (fdecl) + warning_at (loc, OPT_Wunused_result, + "ignoring return value of %qD, " + "declared with attribute warn_unused_result", + fdecl); + else + warning_at (loc, OPT_Wunused_result, + "ignoring return value of function " + "declared with attribute warn_unused_result"); + } + break; + + default: + /* Not a container, not a call, or a call whose value is used. */ + break; + } + } +} + +static unsigned int +run_warn_unused_result (void) +{ + do_warn_unused_result (gimple_body (current_function_decl)); + return 0; +} + +static bool +gate_warn_unused_result (void) +{ + return flag_warn_unused_result; +} + +struct gimple_opt_pass pass_warn_unused_result = +{ + { + GIMPLE_PASS, + "warn_unused_result", /* name */ + gate_warn_unused_result, /* gate */ + run_warn_unused_result, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_NONE, /* tv_id */ + PROP_gimple_any, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ + } +}; + |