Patchwork [C/C++] Add a new warning flag -Wself-assign

login
register
mail settings
Submitter Le-Chun Wu
Date June 24, 2010, 10:54 p.m.
Message ID <AANLkTikYA-W_iH9LnLrrYUsNbvLfecmSpMTiwq_9PO6t@mail.gmail.com>
Download mbox | patch
Permalink /patch/56868/
State New
Headers show

Comments

Le-Chun Wu - June 24, 2010, 10:54 p.m.
Attached please find the revised patch for the new flag -Wself-assign.
Comparing with the previous patch, this one puts -Winit-self back but
keeps it as a no-op, and resurrects the -Winit-self test cases to make
sure the flag is still accepted by GCC. It also fixes the following
self-assign/self-init warnings in GCC source code when bootstrapping.
(The flag actually identified a real bug/typo in cgraphunit.c. Yeah!
:-)) Relevant maintainers of these files are also cc'ed in this email.

        * dbxout.c (DEBUGGER_ARG_OFFSET):
        * omega.c (omega_eliminate_redundant)
        * tree-ssa-ccp.c (ccp_lattice_meet)
        * cgraphunit.c (cgraph_copy_node_for_versioning)
        * config/i386/i386.c (ix86_vectorize_builtin_vec_perm)

Again, bootstrapped and tested on x86_64-linux-gnu. OK for trunk?

Le-chun

gcc/ChangeLog

2010-06-24  Le-Chun Wu  <lcwu@google.com>

        * doc/invoke.texi (-Wall): Include -Wself-assign.
        (-Wself-assign): Documentation for the new flag.
        (-Winit-self): Remove.
        (-Wuninitialized): Remove mention of -Winit-self.
        (-Wunused-variable): Mention of new workaround.
        * tree.h (tree_base): Add a new tree_base flag indicating if an
        expression is the result of constant-folding.
        (operand_equal_flag): Add two new flags for operand_equal_p routine.
        * fold-const.c (operand_equal_p): Support comparison of NULL
        operands and operands without types.
        (set_expr_folded_flag): New helper function.
        (fold_unary_loc_1): Renamed from fold_unary_loc.
        (fold_unary_loc): A wrapper around fold_unary_loc_1 function that sets
        the EXPR_FOLDED flag of the folded expression if folding is
        successful.
        (fold_binary_loc_1): Renamed from fold_binary_loc.
        (fold_binary_loc): A wrapper around fold_binary_loc_1 function that
        sets the EXPR_FOLDED flag of the folded expression if folding is
        successful.
        (fold_ternary_loc_1): Renamed from fold_ternary_loc.
        (fold_ternary_loc): A wrapper around fold_ternary_loc_1 function that
        sets the EXPR_FOLDED flag of the folded expression if folding is
        successful.
        * c-parser.c (c_parser_declaration_or_fndef): Check for
        self-assign after parsing variable initialization.
        (c_parser_expr_no_commas): Check for self-assign after parsing an
        assignment.
        * dbxout.c (DEBUGGER_ARG_OFFSET): Change OFFSET to OFFSET+0 to avoid
        self-assign warning.
        * omega.c (omega_eliminate_redundant): Remove a self-assign statement.
        * tree-ssa-ccp.c (ccp_lattice_meet): Remove a self-assign statement
        and an unnecessary assignment.
        * cgraphunit.c (cgraph_copy_node_for_versioning): Fix a typo detected
        by -Wself-assign.
        * config/i386/i386.c (ix86_vectorize_builtin_vec_perm): Remove
        unnecessary self-init.

gcc/c-family/ChangeLog

2010-06-24  Le-Chun Wu  <lcwu@google.com>

        * gcc/c-family/c-gimplify.c (c_gimplify_expr): Remove support for
        -Winit-self.
        * gcc/c-family/c.opt: Make -Winit-self a no-op and add -Wself-assign.
        * gcc/c-family/c-opts.c : Enable -Wself-assign by -Wall.
        * gcc/c-family/c-common.c (check_for_self_assign): New function.
        * gcc/c-family/c-common.h: Add prototype for check_for_self_assign.

gcc/cp/ChangeLog

2010-06-24  Le-Chun Wu  <lcwu@google.com>

        * init.c (perform_member_init): Check for self-assign after parsing
        class member initialization.
        * parser.c (cp_parser_assignment_expression): Check for self-assign
        after parsing an assignment.
        (cp_parser_init_declarator): Check for self-assign after parsing
        variable initialization.

gcc/testsuite/ChangeLog

        * gcc.dg/plugin/selfassign.c (check_self_assign): Renamed from
        warn_self_assign.
        * gcc.dg/wself-assign-1.c: New test.
        * gcc.dg/wself-assign-2.c: New test.
        * gcc.dg/wself-assign-3.c: New test.
        * gcc.dg/uninit-D-O0.c: Add new warning.
        * gcc.dg/uninit-D.c: Add new warning.
        * gcc.dg/uninit-E-O0.c: Modify comment.
        * gcc.dg/uninit-E.c: Modify comment.
        * g++.dg/plugin/selfassign.c (check_self_assign): Renamed from
        warn_self_assign.
        * g++.dg/warn/Wself-assign-1.C: New test.
        * g++.dg/warn/Wself-assign-2.C: New test.
        * g++.dg/warn/Wself-assign-3.C: New test.
        * g++.dg/warn/Wself-assign-4.C: New test.
        * g++.dg/warn/Wself-assign-5.C: New test.
Le-Chun Wu - June 29, 2010, 5:26 p.m.
Ping?

On Thu, Jun 24, 2010 at 3:54 PM, Le-Chun Wu <lcwu@google.com> wrote:
> Attached please find the revised patch for the new flag -Wself-assign.
> Comparing with the previous patch, this one puts -Winit-self back but
> keeps it as a no-op, and resurrects the -Winit-self test cases to make
> sure the flag is still accepted by GCC. It also fixes the following
> self-assign/self-init warnings in GCC source code when bootstrapping.
> (The flag actually identified a real bug/typo in cgraphunit.c. Yeah!
> :-)) Relevant maintainers of these files are also cc'ed in this email.
>
>        * dbxout.c (DEBUGGER_ARG_OFFSET):
>        * omega.c (omega_eliminate_redundant)
>        * tree-ssa-ccp.c (ccp_lattice_meet)
>        * cgraphunit.c (cgraph_copy_node_for_versioning)
>        * config/i386/i386.c (ix86_vectorize_builtin_vec_perm)
>
> Again, bootstrapped and tested on x86_64-linux-gnu. OK for trunk?
>
> Le-chun
>
> gcc/ChangeLog
>
> 2010-06-24  Le-Chun Wu  <lcwu@google.com>
>
>        * doc/invoke.texi (-Wall): Include -Wself-assign.
>        (-Wself-assign): Documentation for the new flag.
>        (-Winit-self): Remove.
>        (-Wuninitialized): Remove mention of -Winit-self.
>        (-Wunused-variable): Mention of new workaround.
>        * tree.h (tree_base): Add a new tree_base flag indicating if an
>        expression is the result of constant-folding.
>        (operand_equal_flag): Add two new flags for operand_equal_p routine.
>        * fold-const.c (operand_equal_p): Support comparison of NULL
>        operands and operands without types.
>        (set_expr_folded_flag): New helper function.
>        (fold_unary_loc_1): Renamed from fold_unary_loc.
>        (fold_unary_loc): A wrapper around fold_unary_loc_1 function that sets
>        the EXPR_FOLDED flag of the folded expression if folding is
>        successful.
>        (fold_binary_loc_1): Renamed from fold_binary_loc.
>        (fold_binary_loc): A wrapper around fold_binary_loc_1 function that
>        sets the EXPR_FOLDED flag of the folded expression if folding is
>        successful.
>        (fold_ternary_loc_1): Renamed from fold_ternary_loc.
>        (fold_ternary_loc): A wrapper around fold_ternary_loc_1 function that
>        sets the EXPR_FOLDED flag of the folded expression if folding is
>        successful.
>        * c-parser.c (c_parser_declaration_or_fndef): Check for
>        self-assign after parsing variable initialization.
>        (c_parser_expr_no_commas): Check for self-assign after parsing an
>        assignment.
>        * dbxout.c (DEBUGGER_ARG_OFFSET): Change OFFSET to OFFSET+0 to avoid
>        self-assign warning.
>        * omega.c (omega_eliminate_redundant): Remove a self-assign statement.
>        * tree-ssa-ccp.c (ccp_lattice_meet): Remove a self-assign statement
>        and an unnecessary assignment.
>        * cgraphunit.c (cgraph_copy_node_for_versioning): Fix a typo detected
>        by -Wself-assign.
>        * config/i386/i386.c (ix86_vectorize_builtin_vec_perm): Remove
>        unnecessary self-init.
>
> gcc/c-family/ChangeLog
>
> 2010-06-24  Le-Chun Wu  <lcwu@google.com>
>
>        * gcc/c-family/c-gimplify.c (c_gimplify_expr): Remove support for
>        -Winit-self.
>        * gcc/c-family/c.opt: Make -Winit-self a no-op and add -Wself-assign.
>        * gcc/c-family/c-opts.c : Enable -Wself-assign by -Wall.
>        * gcc/c-family/c-common.c (check_for_self_assign): New function.
>        * gcc/c-family/c-common.h: Add prototype for check_for_self_assign.
>
> gcc/cp/ChangeLog
>
> 2010-06-24  Le-Chun Wu  <lcwu@google.com>
>
>        * init.c (perform_member_init): Check for self-assign after parsing
>        class member initialization.
>        * parser.c (cp_parser_assignment_expression): Check for self-assign
>        after parsing an assignment.
>        (cp_parser_init_declarator): Check for self-assign after parsing
>        variable initialization.
>
> gcc/testsuite/ChangeLog
>
>        * gcc.dg/plugin/selfassign.c (check_self_assign): Renamed from
>        warn_self_assign.
>        * gcc.dg/wself-assign-1.c: New test.
>        * gcc.dg/wself-assign-2.c: New test.
>        * gcc.dg/wself-assign-3.c: New test.
>        * gcc.dg/uninit-D-O0.c: Add new warning.
>        * gcc.dg/uninit-D.c: Add new warning.
>        * gcc.dg/uninit-E-O0.c: Modify comment.
>        * gcc.dg/uninit-E.c: Modify comment.
>        * g++.dg/plugin/selfassign.c (check_self_assign): Renamed from
>        warn_self_assign.
>        * g++.dg/warn/Wself-assign-1.C: New test.
>        * g++.dg/warn/Wself-assign-2.C: New test.
>        * g++.dg/warn/Wself-assign-3.C: New test.
>        * g++.dg/warn/Wself-assign-4.C: New test.
>        * g++.dg/warn/Wself-assign-5.C: New test.
>
Jason Merrill - June 30, 2010, 4:29 a.m.
On 06/24/2010 06:54 PM, Le-Chun Wu wrote:
> +   expr_folded_flag:
> +
> +       EXPR_FOLDED in
> +           all expressions
> +           all decls
> +           all constants

This seems problematic given that DECLs and some constants are shared. 
If at some point some expression is folded into a DECL, any subsequent 
appearance of that DECL will be marked EXPR_FOLDED; so if we have

x = x+0;
x = x;

the second assignment won't warn.  Right?

Incidentally, I've been thinking lately that we really ought to wrap 
uses of decls in another tree so that we have location information for 
the use, not just the decl itself; thus the introduction of 
mark_lvalue_use and mark_rvalue_use in the C++ front end (which are 
currently just placeholders).  That might help with this issue as well, 
but of course would be a significant chunk of work.

Jason

Patch

Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 161236)
+++ gcc/doc/invoke.texi	(working copy)
@@ -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
Index: gcc/c-family/c-gimplify.c
===================================================================
--- gcc/c-family/c-gimplify.c	(revision 161236)
+++ gcc/c-family/c-gimplify.c	(working copy)
@@ -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;
 }
Index: gcc/c-family/c.opt
===================================================================
--- gcc/c-family/c.opt	(revision 161236)
+++ gcc/c-family/c.opt	(working copy)
@@ -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
Index: gcc/c-family/c-opts.c
===================================================================
--- gcc/c-family/c-opts.c	(revision 161236)
+++ gcc/c-family/c-opts.c	(working copy)
@@ -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 ())
 	{
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 161236)
+++ gcc/c-family/c-common.c	(working copy)
@@ -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"
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 161236)
+++ gcc/c-family/c-common.h	(working copy)
@@ -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);
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 161236)
+++ gcc/tree.h	(working copy)
@@ -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);
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(revision 161236)
+++ gcc/fold-const.c	(working copy)
@@ -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.
Index: gcc/omega.c
===================================================================
--- gcc/omega.c	(revision 161236)
+++ gcc/omega.c	(working copy)
@@ -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]
Index: gcc/cgraphunit.c
===================================================================
--- gcc/cgraphunit.c	(revision 161236)
+++ gcc/cgraphunit.c	(working copy)
@@ -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;
 
Index: gcc/testsuite/gcc.dg/wself-assign-3.c
===================================================================
--- gcc/testsuite/gcc.dg/wself-assign-3.c	(revision 0)
+++ gcc/testsuite/gcc.dg/wself-assign-3.c	(revision 0)
@@ -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;
+}
Index: gcc/testsuite/gcc.dg/uninit-D-O0.c
===================================================================
--- gcc/testsuite/gcc.dg/uninit-D-O0.c	(revision 161236)
+++ gcc/testsuite/gcc.dg/uninit-D-O0.c	(working copy)
@@ -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;
 }
Index: gcc/testsuite/gcc.dg/uninit-D.c
===================================================================
--- gcc/testsuite/gcc.dg/uninit-D.c	(revision 161236)
+++ gcc/testsuite/gcc.dg/uninit-D.c	(working copy)
@@ -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;
 }
Index: gcc/testsuite/gcc.dg/plugin/selfassign.c
===================================================================
--- gcc/testsuite/gcc.dg/plugin/selfassign.c	(revision 161236)
+++ gcc/testsuite/gcc.dg/plugin/selfassign.c	(working copy)
@@ -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;
Index: gcc/testsuite/gcc.dg/wself-assign-1.c
===================================================================
--- gcc/testsuite/gcc.dg/wself-assign-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/wself-assign-1.c	(revision 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 */
+}
Index: gcc/testsuite/gcc.dg/uninit-E.c
===================================================================
--- gcc/testsuite/gcc.dg/uninit-E.c	(revision 161236)
+++ gcc/testsuite/gcc.dg/uninit-E.c	(working copy)
@@ -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" } */
 
Index: gcc/testsuite/gcc.dg/wself-assign-2.c
===================================================================
--- gcc/testsuite/gcc.dg/wself-assign-2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/wself-assign-2.c	(revision 0)
@@ -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  */
+}
Index: gcc/testsuite/gcc.dg/uninit-E-O0.c
===================================================================
--- gcc/testsuite/gcc.dg/uninit-E-O0.c	(revision 161236)
+++ gcc/testsuite/gcc.dg/uninit-E-O0.c	(working copy)
@@ -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" } */
 
Index: gcc/testsuite/g++.dg/plugin/selfassign.c
===================================================================
--- gcc/testsuite/g++.dg/plugin/selfassign.c	(revision 161236)
+++ gcc/testsuite/g++.dg/plugin/selfassign.c	(working copy)
@@ -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;
Index: gcc/testsuite/g++.dg/warn/Wself-assign-1.C
===================================================================
--- gcc/testsuite/g++.dg/warn/Wself-assign-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/warn/Wself-assign-1.C	(revision 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
+}
Index: gcc/testsuite/g++.dg/warn/Wself-assign-2.C
===================================================================
--- gcc/testsuite/g++.dg/warn/Wself-assign-2.C	(revision 0)
+++ gcc/testsuite/g++.dg/warn/Wself-assign-2.C	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/g++.dg/warn/Wself-assign-3.C
===================================================================
--- gcc/testsuite/g++.dg/warn/Wself-assign-3.C	(revision 0)
+++ gcc/testsuite/g++.dg/warn/Wself-assign-3.C	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/g++.dg/warn/Wself-assign-4.C
===================================================================
--- gcc/testsuite/g++.dg/warn/Wself-assign-4.C	(revision 0)
+++ gcc/testsuite/g++.dg/warn/Wself-assign-4.C	(revision 0)
@@ -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
+}
Index: gcc/testsuite/g++.dg/warn/Wself-assign-5.C
===================================================================
--- gcc/testsuite/g++.dg/warn/Wself-assign-5.C	(revision 0)
+++ gcc/testsuite/g++.dg/warn/Wself-assign-5.C	(revision 0)
@@ -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;
+}
Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c	(revision 161236)
+++ gcc/cp/init.c	(working copy)
@@ -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))
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 161236)
+++ gcc/cp/parser.c	(working copy)
@@ -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)
Index: gcc/tree-ssa-ccp.c
===================================================================
--- gcc/tree-ssa-ccp.c	(revision 161236)
+++ gcc/tree-ssa-ccp.c	(working copy)
@@ -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
     {
Index: gcc/dbxout.c
===================================================================
--- gcc/dbxout.c	(revision 161236)
+++ gcc/dbxout.c	(working copy)
@@ -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
Index: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c	(revision 161236)
+++ gcc/c-parser.c	(working copy)
@@ -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;
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 161236)
+++ gcc/config/i386/i386.c	(working copy)
@@ -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)