+2014-07-31 Marc Glisse <marc.glisse@inria.fr>
+
+ PR c++/60517
+ * common.opt (-Wreturn-local-addr): Moved from c.opt.
+ * gimple-ssa-isolate-paths.c: Include diagnostic-core.h and intl.h.
+ (isolate_path): New argument to avoid inserting a trap.
+ (find_implicit_erroneous_behaviour): Handle returning the address
+ of a local variable.
+ (find_explicit_erroneous_behaviour): Likewise.
+
2014-07-31 Bingfeng Mei <bmei@broadcom.com>
PR lto/61868
+2014-07-31 Marc Glisse <marc.glisse@inria.fr>
+
+ PR c++/60517
+ * c.opt (-Wreturn-local-addr): Move to common.opt.
+
2014-07-30 Jason Merrill <jason@redhat.com>
PR c++/61659
C++ ObjC++ Var(warn_reorder) Warning LangEnabledBy(C++ ObjC++,Wall)
Warn when the compiler reorders code
-Wreturn-local-addr
-C ObjC C++ ObjC++ Var(warn_return_local_addr) Init(1) Warning
-Warn about returning a pointer/reference to a local or temporary variable.
-
Wreturn-type
C ObjC C++ ObjC++ Var(warn_return_type) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
Warn whenever a function's return type defaults to \"int\" (C), or about inconsistent return types (C++)
+2014-07-31 Marc Glisse <marc.glisse@inria.fr>
+
+ PR c++/60517
+ * c-typeck.c (c_finish_return): Return 0 instead of the address of
+ a local variable.
+
2014-07-30 Tom Tromey <tromey@redhat.com>
* c-typeck.c (struct constructor_stack) <designator_depth>: New
warning_at (loc, OPT_Wreturn_local_addr,
"function returns address of label");
else
- warning_at (loc, OPT_Wreturn_local_addr,
- "function returns address of local variable");
+ {
+ warning_at (loc, OPT_Wreturn_local_addr,
+ "function returns address of local variable");
+ tree zero = build_zero_cst (TREE_TYPE (res));
+ t = build2 (COMPOUND_EXPR, TREE_TYPE (res), t, zero);
+ }
}
break;
Common Var(pedantic) Warning
Issue warnings needed for strict compliance to the standard
+Wreturn-local-addr
+Common Var(warn_return_local_addr) Init(1) Warning
+Warn about returning a pointer/reference to a local or temporary variable.
+
Wshadow
Common Var(warn_shadow) Warning
Warn when one local variable shadows another
+2014-07-31 Marc Glisse <marc.glisse@inria.fr>
+
+ PR c++/60517
+ * typeck.c (maybe_warn_about_returning_address_of_local): Return
+ whether it is returning the address of a local variable.
+ (check_return_expr): Return 0 instead of the address of a local
+ variable.
+
2014-07-30 Jason Merrill <jason@redhat.com>
PR lto/53808
static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
static void casts_away_constness_r (tree *, tree *, tsubst_flags_t);
static bool casts_away_constness (tree, tree, tsubst_flags_t);
-static void maybe_warn_about_returning_address_of_local (tree);
+static bool maybe_warn_about_returning_address_of_local (tree);
static tree lookup_destructor (tree, tree, tree, tsubst_flags_t);
static void warn_args_num (location_t, tree, bool);
static int convert_arguments (tree, vec<tree, va_gc> **, tree, int,
}
\f
/* If RETVAL is the address of, or a reference to, a local variable or
- temporary give an appropriate warning. */
+ temporary give an appropriate warning and return true. */
-static void
+static bool
maybe_warn_about_returning_address_of_local (tree retval)
{
tree valtype = TREE_TYPE (DECL_RESULT (current_function_decl));
}
if (TREE_CODE (whats_returned) != ADDR_EXPR)
- return;
+ return false;
whats_returned = TREE_OPERAND (whats_returned, 0);
while (TREE_CODE (whats_returned) == COMPONENT_REF
|| TREE_CODE (whats_returned) == TARGET_EXPR)
{
warning (OPT_Wreturn_local_addr, "returning reference to temporary");
- return;
+ return true;
}
if (VAR_P (whats_returned)
&& DECL_NAME (whats_returned)
&& TEMP_NAME_P (DECL_NAME (whats_returned)))
{
warning (OPT_Wreturn_local_addr, "reference to non-lvalue returned");
- return;
+ return true;
}
}
else
warning (OPT_Wreturn_local_addr, "address of local variable %q+D "
"returned", whats_returned);
- return;
+ return true;
}
+
+ return false;
}
/* Check that returning RETVAL from the current function is valid.
&& TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR)
retval = build2 (COMPOUND_EXPR, TREE_TYPE (retval), retval,
TREE_OPERAND (retval, 0));
- else
- maybe_warn_about_returning_address_of_local (retval);
+ else if (maybe_warn_about_returning_address_of_local (retval))
+ retval = build2 (COMPOUND_EXPR, TREE_TYPE (retval), retval,
+ build_zero_cst (TREE_TYPE (retval)));
}
/* Actually copy the value returned into the appropriate location. */
#include "cfgloop.h"
#include "tree-pass.h"
#include "tree-cfg.h"
+#include "diagnostic-core.h"
+#include "intl.h"
static bool cfg_altered;
Optimization is simple as well. Replace STMT in BB' with an
unconditional trap and remove all outgoing edges from BB'.
+ If RET_ZERO, do not trap, only return NULL.
+
DUPLICATE is a pre-existing duplicate, use it as BB' if it exists.
Return BB'. */
basic_block
isolate_path (basic_block bb, basic_block duplicate,
- edge e, gimple stmt, tree op)
+ edge e, gimple stmt, tree op, bool ret_zero)
{
gimple_stmt_iterator si, si2;
edge_iterator ei;
if (!duplicate)
{
duplicate = duplicate_block (bb, NULL, NULL);
- for (ei = ei_start (duplicate->succs); (e2 = ei_safe_edge (ei)); )
- remove_edge (e2);
+ if (!ret_zero)
+ for (ei = ei_start (duplicate->succs); (e2 = ei_safe_edge (ei)); )
+ remove_edge (e2);
}
/* Complete the isolation step by redirecting E to reach DUPLICATE. */
SI2 points to the duplicate of STMT in DUPLICATE. Insert a trap
before SI2 and remove SI2 and all trailing statements. */
if (!gsi_end_p (si2))
- insert_trap_and_remove_trailing_statements (&si2, op);
+ {
+ if (ret_zero)
+ {
+ gimple ret = gsi_stmt (si2);
+ tree zero = build_zero_cst (TREE_TYPE (gimple_return_retval (ret)));
+ gimple_return_set_retval (ret, zero);
+ update_stmt (ret);
+ }
+ else
+ insert_trap_and_remove_trailing_statements (&si2, op);
+ }
return duplicate;
}
i = next_i)
{
tree op = gimple_phi_arg_def (phi, i);
+ edge e = gimple_phi_arg_edge (phi, i);
+ imm_use_iterator iter;
+ gimple use_stmt;
next_i = i + 1;
+ if (TREE_CODE (op) == ADDR_EXPR)
+ {
+ tree valbase = get_base_address (TREE_OPERAND (op, 0));
+ if ((TREE_CODE (valbase) == VAR_DECL
+ && !is_global_var (valbase))
+ || TREE_CODE (valbase) == PARM_DECL)
+ {
+ FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
+ {
+ if (gimple_code (use_stmt) != GIMPLE_RETURN
+ || gimple_return_retval (use_stmt) != lhs)
+ continue;
+
+ if (warning_at (gimple_location (use_stmt),
+ OPT_Wreturn_local_addr,
+ "function may return address "
+ "of local variable"))
+ inform (DECL_SOURCE_LOCATION(valbase),
+ "declared here");
+
+ if (gimple_bb (use_stmt) == bb)
+ {
+ duplicate = isolate_path (bb, duplicate, e,
+ use_stmt, lhs, true);
+
+ /* When we remove an incoming edge, we need to
+ reprocess the Ith element. */
+ next_i = i;
+ cfg_altered = true;
+ }
+ }
+ }
+ }
+
if (!integer_zerop (op))
continue;
- edge e = gimple_phi_arg_edge (phi, i);
- imm_use_iterator iter;
- gimple use_stmt;
-
/* We've got a NULL PHI argument. Now see if the
PHI's result is dereferenced within BB. */
FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
flag_isolate_erroneous_paths_attribute))
{
- duplicate = isolate_path (bb, duplicate,
- e, use_stmt, lhs);
+ duplicate = isolate_path (bb, duplicate, e,
+ use_stmt, lhs, false);
/* When we remove an incoming edge, we need to
reprocess the Ith element. */
cfg_altered = true;
break;
}
+
+ /* Detect returning the address of a local variable. This only
+ becomes undefined behavior if the result is used, so we do not
+ insert a trap and only return NULL instead. */
+ if (gimple_code (stmt) == GIMPLE_RETURN)
+ {
+ tree val = gimple_return_retval (stmt);
+ if (val && TREE_CODE (val) == ADDR_EXPR)
+ {
+ tree valbase = get_base_address (TREE_OPERAND (val, 0));
+ if ((TREE_CODE (valbase) == VAR_DECL
+ && !is_global_var (valbase))
+ || TREE_CODE (valbase) == PARM_DECL)
+ {
+ /* We only need it for this particular case. */
+ calculate_dominance_info (CDI_POST_DOMINATORS);
+ const char* msg;
+ bool always_executed = dominated_by_p
+ (CDI_POST_DOMINATORS,
+ single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)), bb);
+ if (always_executed)
+ msg = N_("function returns address of local variable");
+ else
+ msg = N_("function may return address of "
+ "local variable");
+
+ if (warning_at (gimple_location (stmt),
+ OPT_Wreturn_local_addr, msg))
+ inform (DECL_SOURCE_LOCATION(valbase), "declared here");
+ tree zero = build_zero_cst (TREE_TYPE (val));
+ gimple_return_set_retval (stmt, zero);
+ update_stmt (stmt);
+ }
+ }
+ }
}
}
}
+
/* Search the function for statements which, if executed, would cause
the program to fault such as a dereference of a NULL pointer.
+2014-07-31 Marc Glisse <marc.glisse@inria.fr>
+
+ PR c++/60517
+ * c-c++-common/addrtmp.c: New file.
+ * c-c++-common/uninit-G.c: Adapt.
+
2014-07-31 Bingfeng Mei <bmei@broadcom.com>
PR lto/61868
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef struct A { int a,b; } A;
+int*g(int*x){return x;}
+int*f1(){
+ A x[2]={{1,2},{3,4}};
+ return g(&x[1].a); // { dg-warning "returns address of local variable" }
+}
+int*f2(int n){
+ A x[2]={{1,2},{3,4}};
+ return n?0:g(&x[1].a); // { dg-warning "may return address of local variable" }
+}
+A y[2]={{1,2},{3,4}};
+int*h(){
+ return g(&y[1].a);
+}
+int*j(int n){
+ A x[2]={{1,2},{3,4}};
+ int*p=g(&y[1].a);
+ if(n==1)p=g(&x[1].a);
+ if(n==2)p=g(&x[0].b);
+ return p; // { dg-warning "may return address of local variable" }
+}
+int*s()
+{
+ static int i;
+ return &i;
+}
/* { dg-do compile } */
/* { dg-options "-O -Wuninitialized" } */
-void *f()
+void g(void*);
+void f()
{
void *i = &i;
- return i;
+ g(i);
}