===================================================================
@@ -242,8 +242,7 @@ Objective-C and Objective-C++ Dialects}.
-Wformat-security -Wformat-y2k @gol
-Wframe-larger-than=@var{len} -Wjump-misses-init -Wignored-qualifiers @gol
-Wimplicit -Wimplicit-function-declaration -Wimplicit-int @gol
--Winit-self -Winline @gol
--Wno-int-to-pointer-cast -Wno-invalid-offsetof @gol
+-Winline -Wno-int-to-pointer-cast -Wno-invalid-offsetof @gol
-Winvalid-pch -Wlarger-than=@var{len} -Wunsafe-loop-optimizations @gol
-Wlogical-op -Wlong-long @gol
-Wmain -Wmissing-braces -Wmissing-field-initializers @gol
@@ -254,7 +253,7 @@ Objective-C and Objective-C++ Dialects}.
-Wparentheses -Wpedantic-ms-format -Wno-pedantic-ms-format @gol
-Wpointer-arith -Wno-pointer-to-int-cast @gol
-Wredundant-decls @gol
--Wreturn-type -Wsequence-point -Wshadow @gol
+-Wreturn-type -Wself-assign -Wsequence-point -Wshadow @gol
-Wsign-compare -Wsign-conversion -Wstack-protector @gol
-Wstrict-aliasing -Wstrict-aliasing=n @gol
-Wstrict-overflow -Wstrict-overflow=@var{n} @gol
@@ -2943,6 +2942,7 @@ Options} and @ref{Objective-C and Object
-Wpointer-sign @gol
-Wreorder @gol
-Wreturn-type @gol
+-Wself-assign @r{(only in C/C++)} @gol
-Wsequence-point @gol
-Wsign-compare @r{(only in C++)} @gol
-Wstrict-aliasing @gol
@@ -3143,24 +3143,6 @@ requiring a non-null value by the @code{
@option{-Wnonnull} is included in @option{-Wall} and @option{-Wformat}. It
can be disabled with the @option{-Wno-nonnull} option.
-@item -Winit-self @r{(C, C++, Objective-C and Objective-C++ only)}
-@opindex Winit-self
-@opindex Wno-init-self
-Warn about uninitialized variables which are initialized with themselves.
-Note this option can only be used with the @option{-Wuninitialized} option.
-
-For example, GCC will warn about @code{i} being uninitialized in the
-following snippet only when @option{-Winit-self} has been specified:
-@smallexample
-@group
-int f()
-@{
- int i = i;
- return i;
-@}
-@end group
-@end smallexample
-
@item -Wimplicit-int @r{(C and Objective-C only)}
@opindex Wimplicit-int
@opindex Wno-implicit-int
@@ -3323,6 +3305,53 @@ definitions, may be found on the GCC rea
This warning is enabled by @option{-Wall} for C and C++.
+@item -Wself-assign
+@opindex Wself-assign
+@opindex Wno-self-assign
+Warn about self-assignment and self-initialization. This warning is intended
+for detecting accidental self-assignment due to typos, and therefore does
+not warn on a statement that is semantically a self-assignment after
+constant folding. Here is an example of what will trigger a self-assign
+warning and what will not:
+
+@smallexample
+@group
+void func()
+@{
+ int i = 2;
+ int x = x; /* warn */
+ float f = 5.0;
+ double a[3];
+
+ i = i + 0; /* not warn */
+ f = f / 1; /* not warn */
+ a[1] = a[1]; /* warn */
+ i += 0; /* not warn */
+@}
+@end group
+@end smallexample
+
+There are cases where self-assignment might be intentional. For example,
+a C++ programmers might write code to test whether an overloaded
+@code{operator=} works when the same object is assigned to itself.
+One way to work around the self-assign warning in such case is using
+the functional form @code{object.operator=(object)} instead of the
+assignment form @code{object = object}, as shown in the following example.
+
+@smallexample
+@group
+void test_func()
+@{
+ MyType t;
+
+ t.operator=(t); // not warn
+ t = t; // warn
+@}
+@end group
+@end smallexample
+
+This warning is enabled by @option{-Wall} for C and C++.
+
@item -Wreturn-type
@opindex Wreturn-type
@opindex Wno-return-type
@@ -3446,6 +3475,10 @@ This warning is enabled by @option{-Wall
To suppress this warning use the @samp{unused} attribute
(@pxref{Variable Attributes}).
+Note that a classic way to avoid @option{-Wunused-variable} warning is
+using @code{x = x}, but that does not work with @option{-Wself-assign}.
+Use @code{(void) x} or @code{static_cast<void>(x)} instead.
+
@item -Wunused-value
@opindex Wunused-value
@opindex Wno-unused-value
@@ -3475,9 +3508,6 @@ or if a variable may be clobbered by a @
warn if a non-static reference or non-static @samp{const} member
appears in a class without constructors.
-If you want to warn about code which uses the uninitialized value of the
-variable in its own initializer, use the @option{-Winit-self} option.
-
These warnings occur for individual uninitialized or clobbered
elements of structure, union or array variables as well as for
variables which are uninitialized or clobbered as a whole. They do
===================================================================
@@ -173,18 +173,5 @@ int
c_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED,
gimple_seq *post_p ATTRIBUTE_UNUSED)
{
- enum tree_code code = TREE_CODE (*expr_p);
-
- /* This is handled mostly by gimplify.c, but we have to deal with
- not warning about int x = x; as it is a GCC extension to turn off
- this warning but only if warn_init_self is zero. */
- if (code == DECL_EXPR
- && TREE_CODE (DECL_EXPR_DECL (*expr_p)) == VAR_DECL
- && !DECL_EXTERNAL (DECL_EXPR_DECL (*expr_p))
- && !TREE_STATIC (DECL_EXPR_DECL (*expr_p))
- && (DECL_INITIAL (DECL_EXPR_DECL (*expr_p)) == DECL_EXPR_DECL (*expr_p))
- && !warn_init_self)
- TREE_NO_WARNING (DECL_EXPR_DECL (*expr_p)) = 1;
-
return GS_UNHANDLED;
}
===================================================================
@@ -259,8 +259,8 @@ C C++ Var(warn_ignored_qualifiers) Init(
Warn whenever type qualifiers are ignored.
Winit-self
-C ObjC C++ ObjC++ Var(warn_init_self) Warning
-Warn about variables which are initialized to themselves
+C ObjC C++ ObjC++
+Does nothing. Preserved for backward compatibility.
Wimplicit
C ObjC Var(warn_implicit) Init(-1) Warning
@@ -425,6 +425,10 @@ Wreturn-type
C ObjC C++ ObjC++ Var(warn_return_type) Warning
Warn whenever a function's return type defaults to \"int\" (C), or about inconsistent return types (C++)
+Wself-assign
+C C++ Var(warn_self_assign) Init(0) Warning
+Warn when a variable is assigned to itself
+
Wselector
ObjC ObjC++ Var(warn_selector) Warning
Warn if a selector has multiple methods
===================================================================
@@ -486,6 +486,7 @@ c_common_handle_option (size_t scode, co
warn_unknown_pragmas = value;
warn_uninitialized = value;
+ warn_self_assign = value;
if (!c_dialect_cxx ())
{
===================================================================
@@ -9266,4 +9266,20 @@ make_tree_vector_copy (const VEC(tree,gc
return ret;
}
+/* Check for and warn about self-assignment or self-initialization.
+ LHS and RHS are the tree nodes for the left-hand side and right-hand side
+ of the assignment or initialization we are checking.
+ LOCATION is the source location for RHS. */
+
+void
+check_for_self_assign (location_t location, tree lhs, tree rhs)
+{
+ /* Only emit a warning if RHS is not a folded expression so that we don't
+ warn on something like x = x / 1. */
+ if (!EXPR_FOLDED (rhs)
+ && operand_equal_p (lhs, rhs,
+ OEP_PURE_SAME | OEP_ALLOW_NULL | OEP_ALLOW_NULL_TYPE))
+ warning_at (location, OPT_Wself_assign, "%qE is assigned to itself", lhs);
+}
+
#include "gt-c-family-c-common.h"
===================================================================
@@ -893,6 +893,7 @@ extern VEC(tree,gc) *make_tree_vector (v
extern void release_tree_vector (VEC(tree,gc) *);
extern VEC(tree,gc) *make_tree_vector_single (tree);
extern VEC(tree,gc) *make_tree_vector_copy (const VEC(tree,gc) *);
+extern void check_for_self_assign (location_t, tree, tree);
/* In c-gimplify.c */
extern void c_genericize (tree);
===================================================================
@@ -388,8 +388,9 @@ struct GTY(()) tree_base {
unsigned visited : 1;
unsigned packed_flag : 1;
unsigned user_align : 1;
+ unsigned expr_folded_flag : 1;
- unsigned spare : 13;
+ unsigned spare : 12;
/* This field is only used with type nodes; the only reason it is present
in tree_base instead of tree_type is to save space. The size of the
@@ -627,6 +628,13 @@ struct GTY(()) tree_common {
SSA_NAME_IS_DEFAULT_DEF in
SSA_NAME
+
+ expr_folded_flag:
+
+ EXPR_FOLDED in
+ all expressions
+ all decls
+ all constants
*/
#undef DEFTREESTRUCT
@@ -1363,6 +1371,10 @@ extern void omp_clause_range_check_faile
/* In fixed-point types, means a saturating type. */
#define TYPE_SATURATING(NODE) ((NODE)->base.saturating_flag)
+/* Nonzero in an expression, a decl, or a constant node if the node is
+ the result of a successful constant-folding. */
+#define EXPR_FOLDED(NODE) ((NODE)->base.expr_folded_flag)
+
/* These flags are available for each language front end to use internally. */
#define TREE_LANG_FLAG_0(NODE) ((NODE)->base.lang_flag_0)
#define TREE_LANG_FLAG_1(NODE) ((NODE)->base.lang_flag_1)
@@ -4931,7 +4943,9 @@ extern bool fold_deferring_overflow_warn
enum operand_equal_flag
{
OEP_ONLY_CONST = 1,
- OEP_PURE_SAME = 2
+ OEP_PURE_SAME = 2,
+ OEP_ALLOW_NULL = 4, /* Allow comparison of NULL operands. */
+ OEP_ALLOW_NULL_TYPE = 8 /* Allow comparison of operands without types. */
};
extern int operand_equal_p (const_tree, const_tree, unsigned int);
===================================================================
@@ -2404,22 +2404,45 @@ combine_comparisons (location_t loc,
If OEP_PURE_SAME is set, then pure functions with identical arguments
are considered the same. It is used when the caller has other ways
- to ensure that global memory is unchanged in between. */
+ to ensure that global memory is unchanged in between.
+
+ If OEP_ALLOW_NULL is set, this routine will not crash on NULL operands,
+ and two NULL operands are considered equal. This flag is usually set
+ in the context of frontend when ARG0 and/or ARG1 may be NULL mostly due
+ to recursion on partially built expressions (e.g. a CAST_EXPR on a NULL
+ tree.) In this case, we certainly don't want the compiler to crash and
+ it's OK to consider two NULL operands equal. On the other hand, when
+ called in the context of code generation and optimization, if NULL
+ operands are not expected, silently ignoring them could be dangerous
+ and might cause problems downstream that are hard to find/debug. In that
+ case, the flag should probably not be set. */
int
operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
{
+ /* If either is NULL, they must be both NULL to be equal. We only do this
+ check when OEP_ALLOW_NULL is set. */
+ if ((flags & OEP_ALLOW_NULL) && (!arg0 || !arg1))
+ return arg0 == arg1;
+
+ /* Similar, if either does not have a type (like a released SSA name, or
+ an operand whose type depends on a template parameter), they aren't
+ equal, unless OEP_ALLOW_NULL_TYPE is set, in which case we will continue
+ to compare the operands only when both don't have a type. */
+ if (!TREE_TYPE (arg0) || !TREE_TYPE (arg1))
+ {
+ if (((~flags) & OEP_ALLOW_NULL_TYPE)
+ || ((TREE_TYPE (arg0) && !TREE_TYPE (arg1))
+ || (!TREE_TYPE (arg0) && TREE_TYPE (arg1))))
+ return 0;
+ }
+
/* If either is ERROR_MARK, they aren't equal. */
if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK
|| TREE_TYPE (arg0) == error_mark_node
|| TREE_TYPE (arg1) == error_mark_node)
return 0;
- /* Similar, if either does not have a type (like a released SSA name),
- they aren't equal. */
- if (!TREE_TYPE (arg0) || !TREE_TYPE (arg1))
- return 0;
-
/* Check equality of integer constants before bailing out due to
precision differences. */
if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
@@ -2430,19 +2453,25 @@ operand_equal_p (const_tree arg0, const_
because they may change the signedness of the arguments. As pointers
strictly don't have a signedness, require either two pointers or
two non-pointers as well. */
- if (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1))
- || POINTER_TYPE_P (TREE_TYPE (arg0)) != POINTER_TYPE_P (TREE_TYPE (arg1)))
+ if (TREE_TYPE (arg0)
+ && (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1))
+ || (POINTER_TYPE_P (TREE_TYPE (arg0))
+ != POINTER_TYPE_P (TREE_TYPE (arg1)))))
return 0;
/* We cannot consider pointers to different address space equal. */
- if (POINTER_TYPE_P (TREE_TYPE (arg0)) && POINTER_TYPE_P (TREE_TYPE (arg1))
- && (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0)))
- != TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg1)))))
+ if (TREE_TYPE (arg0)
+ && (POINTER_TYPE_P (TREE_TYPE (arg0))
+ && POINTER_TYPE_P (TREE_TYPE (arg1))
+ && (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0)))
+ != TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg1))))))
return 0;
/* If both types don't have the same precision, then it is not safe
to strip NOPs. */
- if (TYPE_PRECISION (TREE_TYPE (arg0)) != TYPE_PRECISION (TREE_TYPE (arg1)))
+ if (TREE_TYPE (arg0)
+ && (TYPE_PRECISION (TREE_TYPE (arg0))
+ != TYPE_PRECISION (TREE_TYPE (arg1))))
return 0;
STRIP_NOPS (arg0);
@@ -2467,9 +2496,10 @@ operand_equal_p (const_tree arg0, const_
if (TREE_CODE (arg0) != TREE_CODE (arg1)
/* This is needed for conversions and for COMPONENT_REF.
Might as well play it safe and always test this. */
- || TREE_CODE (TREE_TYPE (arg0)) == ERROR_MARK
- || TREE_CODE (TREE_TYPE (arg1)) == ERROR_MARK
- || TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1)))
+ || (TREE_TYPE (arg0)
+ && (TREE_CODE (TREE_TYPE (arg0)) == ERROR_MARK
+ || TREE_CODE (TREE_TYPE (arg1)) == ERROR_MARK
+ || TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1)))))
return 0;
/* If ARG0 and ARG1 are the same SAVE_EXPR, they are necessarily equal.
@@ -2502,7 +2532,8 @@ operand_equal_p (const_tree arg0, const_
return 1;
- if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0))))
+ if (TREE_TYPE (arg0)
+ && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0))))
{
/* If we do not distinguish between signed and unsigned zero,
consider them equal. */
@@ -2570,8 +2601,9 @@ operand_equal_p (const_tree arg0, const_
{
CASE_CONVERT:
case FIX_TRUNC_EXPR:
- if (TYPE_UNSIGNED (TREE_TYPE (arg0))
- != TYPE_UNSIGNED (TREE_TYPE (arg1)))
+ if (TREE_TYPE (arg0)
+ && (TYPE_UNSIGNED (TREE_TYPE (arg0))
+ != TYPE_UNSIGNED (TREE_TYPE (arg1))))
return 0;
break;
default:
@@ -7653,8 +7685,8 @@ build_fold_addr_expr_loc (location_t loc
OP0. Return the folded expression if folding is successful.
Otherwise, return NULL_TREE. */
-tree
-fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
+static tree
+fold_unary_loc_1 (location_t loc, enum tree_code code, tree type, tree op0)
{
tree tem;
tree arg0;
@@ -8302,6 +8334,41 @@ fold_unary_loc (location_t loc, enum tre
} /* switch (code) */
}
+/* Given an expression tree EXP, set the EXPR_FOLDED flag, and if it is
+ a nop, recursively set the EXPR_FOLDED flag of its operand. */
+
+static void
+set_expr_folded_flag (tree exp)
+{
+ EXPR_FOLDED (exp) = 1;
+
+ /* If EXP is a nop (i.e. NON_LVALUE_EXPRs and NOP_EXPRs), we need to
+ recursively set the EXPR_FOLDED flag of its operand because the
+ expression will be stripped later. */
+ while ((CONVERT_EXPR_P (exp)
+ || TREE_CODE (exp) == NON_LVALUE_EXPR)
+ && TREE_OPERAND (exp, 0) != error_mark_node)
+ {
+ exp = TREE_OPERAND (exp, 0);
+ EXPR_FOLDED (exp) = 1;
+ }
+}
+
+/* Fold a unary expression of code CODE and type TYPE with operand
+ OP0. Return the folded expression if folding is successful.
+ Otherwise, return NULL_TREE.
+ This is a wrapper around fold_unary_loc_1 function (which does the
+ actual folding). Set the EXPR_FOLDED flag of the folded expression
+ if folding is successful. */
+
+tree
+fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
+{
+ tree tem = fold_unary_loc_1 (loc, code, type, op0);
+ if (tem)
+ set_expr_folded_flag (tem);
+ return tem;
+}
/* If the operation was a conversion do _not_ mark a resulting constant
with TREE_OVERFLOW if the original constant was not. These conversions
@@ -9394,8 +9461,8 @@ get_pointer_modulus_and_residue (tree ex
Return the folded expression if folding is successful. Otherwise,
return NULL_TREE. */
-tree
-fold_binary_loc (location_t loc,
+static tree
+fold_binary_loc_1 (location_t loc,
enum tree_code code, tree type, tree op0, tree op1)
{
enum tree_code_class kind = TREE_CODE_CLASS (code);
@@ -13066,6 +13133,24 @@ fold_binary_loc (location_t loc,
return tem;
}
+/* Fold a binary expression of code CODE and type TYPE with operands
+ OP0 and OP1. LOC is the location of the resulting expression.
+ Return the folded expression if folding is successful. Otherwise,
+ return NULL_TREE.
+ This is a wrapper around fold_binary_loc_1 function (which does the
+ actual folding). Set the EXPR_FOLDED flag of the folded expression
+ if folding is successful. */
+
+tree
+fold_binary_loc (location_t loc,
+ enum tree_code code, tree type, tree op0, tree op1)
+{
+ tree tem = fold_binary_loc_1 (loc, code, type, op0, op1);
+ if (tem)
+ set_expr_folded_flag (tem);
+ return tem;
+}
+
/* Callback for walk_tree, looking for LABEL_EXPR. Return *TP if it is
a LABEL_EXPR; otherwise return NULL_TREE. Do not check the subtrees
of GOTO_EXPR. */
@@ -13102,8 +13187,8 @@ contains_label_p (tree st)
OP0, OP1, and OP2. Return the folded expression if folding is
successful. Otherwise, return NULL_TREE. */
-tree
-fold_ternary_loc (location_t loc, enum tree_code code, tree type,
+static tree
+fold_ternary_loc_1 (location_t loc, enum tree_code code, tree type,
tree op0, tree op1, tree op2)
{
tree tem;
@@ -13438,6 +13523,23 @@ fold_ternary_loc (location_t loc, enum t
} /* switch (code) */
}
+/* Fold a ternary expression of code CODE and type TYPE with operands
+ OP0, OP1, and OP2. Return the folded expression if folding is
+ successful. Otherwise, return NULL_TREE.
+ This is a wrapper around fold_ternary_loc_1 function (which does the
+ actual folding). Set the EXPR_FOLDED flag of the folded expression
+ if folding is successful. */
+
+tree
+fold_ternary_loc (location_t loc, enum tree_code code, tree type,
+ tree op0, tree op1, tree op2)
+{
+ tree tem = fold_ternary_loc_1 (loc, code, type, op0, op1, op2);
+ if (tem)
+ set_expr_folded_flag (tem);
+ return tem;
+}
+
/* Perform constant folding and related simplification of EXPR.
The related simplifications include x*1 => x, x*0 => 0, etc.,
and application of the associative law.
===================================================================
@@ -2213,7 +2213,9 @@ omega_eliminate_redundant (omega_pb pb,
|| pb->geqs[e3].color == omega_red)
goto nextE3;
- alpha3 = alpha3;
+ /* Dubious self-assignment. */
+ /* alpha3 = alpha3; */
+
/* verify alpha1*v1+alpha2*v2 = alpha3*v3 */
for (k = pb->num_vars; k >= 1; k--)
if (alpha3 * pb->geqs[e3].coef[k]
===================================================================
@@ -2128,7 +2128,7 @@ cgraph_copy_node_for_versioning (struct
new_version->local.local = true;
new_version->local.vtable_method = false;
new_version->global = old_version->global;
- new_version->rtl = new_version->rtl;
+ new_version->rtl = old_version->rtl;
new_version->reachable = true;
new_version->count = old_version->count;
===================================================================
@@ -0,0 +1,9 @@
+/* Test whether -Wself-assign is enabled by -Wall. */
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+int bar() {
+ int i = 0;
+ i = i; /* { dg-warning "assigned to itself" } */
+ return i;
+}
===================================================================
@@ -1,9 +1,9 @@
-/* Test we do not warn about initializing variable with self. */
+/* Test we do warn about initializing variable with self. */
/* { dg-do compile } */
/* { dg-options "-Wuninitialized" } */
int f()
{
- int i = i;
+ int i = i; /* { dg-warning "i" "uninitialized variable warning" } */
return i;
}
===================================================================
@@ -1,9 +1,9 @@
-/* Test we do not warn about initializing variable with self. */
+/* Test we do warn about initializing variable with self. */
/* { dg-do compile } */
/* { dg-options "-O -Wuninitialized" } */
int f()
{
- int i = i;
+ int i = i; /* { dg-warning "i" "uninitialized variable warning" } */
return i;
}
===================================================================
@@ -196,7 +196,7 @@ compare_and_warn (gimple stmt, tree lhs,
/* Check and warn if STMT is a self-assign statement. */
static void
-warn_self_assign (gimple stmt)
+check_self_assign (gimple stmt)
{
tree rhs, lhs;
@@ -251,7 +251,7 @@ execute_warn_self_assign (void)
FOR_EACH_BB (bb)
{
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- warn_self_assign (gsi_stmt (gsi));
+ check_self_assign (gsi_stmt (gsi));
}
return 0;
===================================================================
@@ -0,0 +1,27 @@
+/* Test the self-assignemnt detection and warning. */
+/* { dg-do compile } */
+/* { dg-options "-Wself-assign" } */
+
+struct Bar {
+ int b_;
+ int c_;
+};
+
+int g;
+
+int main()
+{
+ struct Bar *bar;
+ int x = x; /* { dg-warning "assigned to itself" } */
+ static int y;
+ struct Bar b_array[5];
+
+ b_array[x+g].b_ = b_array[x+g].b_; /* { dg-warning "assigned to itself" } */
+ g = g; /* { dg-warning "assigned to itself" } */
+ y = y; /* { dg-warning "assigned to itself" } */
+ bar->b_ = bar->b_; /* { dg-warning "assigned to itself" } */
+ x += 0; /* should not warn */
+ y -= 0; /* should not warn */
+ x /= x; /* should not warn */
+ y *= y; /* should not warn */
+}
===================================================================
@@ -1,4 +1,5 @@
-/* Test we do warn about initializing variable with self when -Winit-self is supplied. */
+/* Test we do warn about initializing variable with self and that -Winit-self
+ is preserved for backward compatibility. */
/* { dg-do compile } */
/* { dg-options "-O -Wuninitialized -Winit-self" } */
===================================================================
@@ -0,0 +1,24 @@
+/* Test how self-assignment detection handles constant-folding happening */
+/* when parsing the RHS or the initializer. */
+/* { dg-do compile } */
+/* { dg-options "-Wself-assign" } */
+
+struct Bar {
+ int b_;
+ float c_;
+};
+
+int g;
+
+int main()
+{
+ struct Bar *bar;
+ int x = x - 0; /* should not warn */
+ static int y;
+ struct Bar b_array[5];
+
+ b_array[x+g].b_ = b_array[x+g].b_ * 1; /* should no warn */
+ g = g + 0; /* should not warn */
+ y = y / 1; /* should not warn */
+ bar->b_ = bar->b_ - 0; /* should not warn */
+}
===================================================================
@@ -1,4 +1,5 @@
-/* Test we do warn about initializing variable with self when -Winit-self is supplied. */
+/* Test we do warn about initializing variable with self and that -Winit-self
+ is preserved for backward compatibility. */
/* { dg-do compile } */
/* { dg-options "-Wuninitialized -Winit-self" } */
===================================================================
@@ -196,7 +196,7 @@ compare_and_warn (gimple stmt, tree lhs,
/* Check and warn if STMT is a self-assign statement. */
static void
-warn_self_assign (gimple stmt)
+check_self_assign (gimple stmt)
{
tree rhs, lhs;
@@ -251,7 +251,7 @@ execute_warn_self_assign (void)
FOR_EACH_BB (bb)
{
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- warn_self_assign (gsi_stmt (gsi));
+ check_self_assign (gsi_stmt (gsi));
}
return 0;
===================================================================
@@ -0,0 +1,54 @@
+// Test the self-assignemnt detection and warning.
+// { dg-do compile }
+// { dg-options "-Wself-assign" }
+
+class Foo {
+ private:
+ int a_;
+
+ public:
+ Foo() : a_(a_) {} // { dg-warning "assigned to itself" }
+
+ void setA(int a) {
+ a_ = a_; // { dg-warning "assigned to itself" }
+ }
+
+ void operator=(Foo& rhs) {
+ this->a_ = rhs.a_;
+ }
+};
+
+struct Bar {
+ int b_;
+ int c_;
+};
+
+int g = g; // { dg-warning "assigned to itself" }
+Foo foo = foo; // { dg-warning "assigned to itself" }
+
+int func()
+{
+ Bar *bar1, bar2;
+ Foo local_foo;
+ int x = x; // { dg-warning "assigned to itself" }
+ static int y = y; // { dg-warning "assigned to itself" }
+ float *f;
+ Bar bar_array[5];
+ char n;
+ int overflow;
+
+ *f = *f; // { dg-warning "assigned to itself" }
+ bar1->b_ = bar1->b_; // { dg-warning "assigned to itself" }
+ bar2.c_ = bar2.c_; // { dg-warning "assigned to itself" }
+ local_foo = local_foo; // { dg-warning "assigned to itself" }
+ foo = foo; // { dg-warning "assigned to itself" }
+ foo.setA(5);
+ bar_array[3].c_ = bar_array[3].c_; // { dg-warning "assigned to itself" }
+ bar_array[x+g].b_ = bar_array[x+g].b_; // { dg-warning "assigned to itself" }
+ y = x;
+ x = y;
+ x += 0; // should not warn
+ y -= 0; // should not warn
+ x /= x; // should not warn
+ y *= y; // should not warn
+}
===================================================================
@@ -0,0 +1,31 @@
+// Test the handling of expressions that depend on template parameters in
+// self-assignemnt detection.
+// { dg-do compile }
+// { dg-options "-Wself-assign" }
+
+template<typename T>
+struct Bar {
+ T x;
+ Bar operator++(int) {
+ Bar tmp = *this;
+ ++x;
+ tmp = tmp; // { dg-warning "assigned to itself" }
+ return tmp;
+ }
+};
+
+template<typename T>
+T DoSomething(T y) {
+ T a[5], *p;
+ Bar<T> b;
+ b.x = b.x; // { dg-warning "assigned to itself" }
+ *p = *p; // { dg-warning "assigned to itself" }
+ a[2] = a[2]; // { dg-warning "assigned to itself" }
+ return *p;
+}
+
+main() {
+ Bar<int> bar;
+ bar++;
+ DoSomething(5);
+}
===================================================================
@@ -0,0 +1,35 @@
+// Test how operands_equal_p handles a NULL operand.
+// { dg-do compile }
+// { dg-options "-Wself-assign" }
+
+#include <cstdio>
+
+namespace testing {
+
+class Foo {
+ int f;
+ public:
+ Foo() { printf("Construct Foo\n"); }
+};
+
+class Bar {
+ int b;
+ public:
+ Bar(int x) { printf("Construct Bar\n"); }
+
+ void operator=(const Foo& foo) {
+ printf("Assign Foo to Bar\n");
+ }
+};
+
+}
+
+template <class T>
+void func(T t) {
+ ::testing::Bar(1) = ::testing::Foo(); // used to trigger a segfault
+ ::testing::Foo() = ::testing::Foo(); // { dg-warning "assigned to itself" }
+}
+
+main() {
+ func(2);
+}
===================================================================
@@ -0,0 +1,48 @@
+// Test how self-assignment detection handles constant-folding happening
+// when parsing the RHS or the initializer.
+// { dg-do compile }
+// { dg-options "-Wself-assign" }
+
+class Foo {
+ private:
+ int a_;
+
+ public:
+ Foo() : a_(a_+0) {} // should not warn
+
+ void setA(int a) {
+ a_ = a_ + 0; // should not warn
+ }
+
+ void operator=(Foo& rhs) {
+ this->a_ = rhs.a_;
+ }
+};
+
+struct Bar {
+ int b_;
+ float c_;
+};
+
+int g = g * 1; // should not warn
+
+int func()
+{
+ Bar *bar1, bar2;
+ Foo foo;
+ int x = x - 0; // should not warn
+ static int y = y / 1; // should not warn
+ float *f;
+ Bar bar_array[5];
+
+ *f = *f / 1; // should not warn
+ bar1->b_ = bar1->b_ * 1; // should not warn
+ bar2.c_ = bar2.c_ - 0; // should not warn
+ foo.setA(5);
+ bar_array[3].c_ = bar_array[3].c_ * 1; // should not warn
+ bar_array[x+g].b_ = bar_array[x+g].b_ / 1; // should not warn
+ x += 0;
+ y -= 0;
+ foo = foo; // { dg-warning "assigned to itself" }
+ foo.operator=(foo); // should not warn
+}
===================================================================
@@ -0,0 +1,21 @@
+// Test whether -Wself-assign is enabled by -Wall.
+// { dg-do compile }
+// { dg-options "-Wall" }
+
+class Foo {
+ int a, b;
+ public:
+ Foo() : a(a) { } // { dg-warning "assigned to itself" }
+ int foo() { return b; }
+};
+
+int c = c; // { dg-warning "assigned to itself" }
+
+Foo foo;
+
+int bar() {
+ static int d = d; // { dg-warning "assigned to itself" }
+ int i = 0;
+ i = i; // { dg-warning "assigned to itself" }
+ return d;
+}
===================================================================
@@ -529,8 +529,14 @@ perform_member_init (tree member, tree i
init = build_x_compound_expr_from_list (init, ELK_MEM_INIT);
if (init)
- finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init,
- tf_warning_or_error));
+ {
+ finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init,
+ tf_warning_or_error));
+ /* Check for and warn about self-initialization if -Wself-assign is
+ enabled. */
+ if (warn_self_assign)
+ check_for_self_assign (input_location, decl, init);
+ }
}
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
===================================================================
@@ -6903,6 +6903,12 @@ cp_parser_assignment_expression (cp_pars
if (cp_parser_non_integral_constant_expression (parser,
NIC_ASSIGNMENT))
return error_mark_node;
+
+ /* Check for and warn about self-assignment if -Wself-assign is
+ enabled and the assignment operator is "=". */
+ if (warn_self_assign && assignment_operator == NOP_EXPR)
+ check_for_self_assign (input_location, expr, rhs);
+
/* Build the assignment expression. */
expr = build_x_modify_expr (expr,
assignment_operator,
@@ -14075,6 +14081,10 @@ cp_parser_init_declarator (cp_parser* pa
`explicit' constructor cannot be used. */
((is_direct_init || !is_initialized)
? 0 : LOOKUP_ONLYCONVERTING));
+ /* Check for and warn about self-initialization if -Wself-assign is
+ enabled. */
+ if (warn_self_assign && initializer)
+ check_for_self_assign (input_location, decl, initializer);
}
else if ((cxx_dialect != cxx98) && friend_p
&& decl && TREE_CODE (decl) == FUNCTION_DECL)
===================================================================
@@ -728,9 +728,8 @@ ccp_lattice_meet (prop_value_t *val1, pr
Ci M Cj = VARYING if (i != j)
If these two values come from memory stores, make sure that
- they come from the same memory reference. */
- val1->lattice_val = CONSTANT;
- val1->value = val1->value;
+ they come from the same memory reference.
+ Nothing to do. VAL1 already contains the value we want. */
}
else
{
===================================================================
@@ -288,9 +288,12 @@ static const char *base_input_file;
#endif
/* A C expression for the integer offset value of an argument (N_PSYM)
- having address X (an RTX). The nominal offset is OFFSET. */
+ having address X (an RTX). The nominal offset is OFFSET.
+ Note that we use OFFSET + 0 here to avoid the self-assign warning
+ when the macro is called in a context like
+ number = DEBUGGER_ARG_OFFSET(number, X) */
#ifndef DEBUGGER_ARG_OFFSET
-#define DEBUGGER_ARG_OFFSET(OFFSET, X) (OFFSET)
+#define DEBUGGER_ARG_OFFSET(OFFSET, X) (OFFSET + 0)
#endif
/* This obstack holds the stab string currently being constructed. We
===================================================================
@@ -1297,6 +1297,11 @@ c_parser_declaration_or_fndef (c_parser
maybe_warn_string_init (TREE_TYPE (d), init);
finish_decl (d, init_loc, init.value,
init.original_type, asm_name);
+ /* Check for and warn about self-initialization if
+ -Wself-assign is enabled. Don't warn if there is
+ already an error for the initializer. */
+ if (warn_self_assign && DECL_INITIAL (d) != error_mark_node)
+ check_for_self_assign (here, d, init.value);
}
}
else
@@ -4767,7 +4772,13 @@ c_parser_expr_no_commas (c_parser *parse
code, exp_location, rhs.value,
rhs.original_type);
if (code == NOP_EXPR)
- ret.original_code = MODIFY_EXPR;
+ {
+ ret.original_code = MODIFY_EXPR;
+ /* Check for and warn about self-assignment if -Wself-assign is
+ enabled. */
+ if (warn_self_assign)
+ check_for_self_assign (op_location, lhs.value, rhs.value);
+ }
else
{
TREE_NO_WARNING (ret.value) = 1;
===================================================================
@@ -29379,7 +29379,7 @@ ix86_vectorize_builtin_vec_perm (tree ve
tree itype = TREE_TYPE (vec_type);
bool u = TYPE_UNSIGNED (itype);
enum machine_mode vmode = TYPE_MODE (vec_type);
- enum ix86_builtins fcode = fcode; /* Silence bogus warning. */
+ enum ix86_builtins fcode;
bool ok = TARGET_SSE2;
switch (vmode)