diff mbox

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

Message ID AANLkTikS5OKUW9BGhwPCdG1wzF2Xh-C2RxMAfvxKeewL@mail.gmail.com
State New
Headers show

Commit Message

Le-Chun Wu July 22, 2010, 12:45 a.m. UTC
Sorry for my delay in responding. I finally got time to work on this
patch after coming back from holidays.

On Tue, Jun 29, 2010 at 12:51 PM, Manuel López-Ibáñez
<lopezibanez@gmail.com> wrote:
>
> --- 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 ())
>        {
>
> Please, use the new handle_option as it is done for Wimplicit just a
> few lines above. Otherwise, Werror= and pragma diagnostic won't work
> correctly. I know that the majority of options are not enabled this
> way. They should, but no one has bothered to finish this transition.

Done as suggested.

>
> >        * 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)
> >
>
> Please, sent these fixes separately. They are independent from your
> patch and make your patch more difficult to review. The smaller a
> patch the quickest to review. You may think that CCing more
> maintainers will get your patch reviewed quicker, but the opposite is
> often true.

Most certainly. I have removed them from this patch and will send out
separate patches for these changes.


On Tue, Jun 29, 2010 at 9:29 PM, Jason Merrill <jason@redhat.com> wrote:
>
> 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?

Yes, that's right.  This is a great catch. Wrapping uses of decls will
surely help in this case but, as you also said, it will require a
significant amount of work to make such a change to the IR. For now,
to fix this issue, I would clear the expr_folded flag after the
self-assign check (for each statement) is done. I also added comments
in tree.h to warn people not to use this flag in other places, and
added a new test for this case. What do you think?

Attached is the revised patch that incorporates Manuel's and Jason's
comments. Bootstrapped (with additional patches that address the
self-assign code in GCC source) and tested on x86_64-gnu-linux. OK for
trunk? (If it's OK, I will make sure the patches that fix the
self-assign warnings in GCC source get submitted before this one.)
Thanks.

Le-chun


gcc/ChangeLog:

2010-07-21  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.

gcc/c-family/ChangeLog

2010-07-21  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-07-21  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

2010-07-21  Le-Chun Wu  <lcwu@google.com>

        * 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.
        * g++.dg/warn/Wself-assign-6.C: New test.

Comments

Jack Howarth July 27, 2010, 2:01 p.m. UTC | #1
On Wed, Jul 21, 2010 at 05:45:16PM -0700, Le-Chun Wu wrote:
> 
> Attached is the revised patch that incorporates Manuel's and Jason's
> comments. Bootstrapped (with additional patches that address the
> self-assign code in GCC source) and tested on x86_64-gnu-linux. OK for
> trunk? (If it's OK, I will make sure the patches that fix the
> self-assign warnings in GCC source get submitted before this one.)
> Thanks.
> 

Le-chun,
    Would it make sense to extend the -Wself-assign flag to
other languages in gcc (like fortran for example)?
                    Jack

> Le-chun
> 
> 
> gcc/ChangeLog:
> 
> 2010-07-21  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.
> 
> gcc/c-family/ChangeLog
> 
> 2010-07-21  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-07-21  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
> 
> 2010-07-21  Le-Chun Wu  <lcwu@google.com>
> 
>         * 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.
>         * g++.dg/warn/Wself-assign-6.C: New test.
Jason Merrill July 27, 2010, 3 p.m. UTC | #2
On 07/21/2010 08:45 PM, Le-Chun Wu wrote:
> On Tue, Jun 29, 2010 at 9:29 PM, Jason Merrill<jason@redhat.com>  wrote:
>> 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?
>
> Yes, that's right.  This is a great catch. Wrapping uses of decls will
> surely help in this case but, as you also said, it will require a
> significant amount of work to make such a change to the IR. For now,
> to fix this issue, I would clear the expr_folded flag after the
> self-assign check (for each statement) is done. I also added comments
> in tree.h to warn people not to use this flag in other places, and
> added a new test for this case. What do you think?

That's certainly better, but it still makes me a bit uncomfortable to 
have a flag that's just used for transient marking.  Is it possible to 
avoid the need for this flag in the C front end, since it delays folding 
until c_fully_fold?

Jason
Richard Biener July 27, 2010, 3:31 p.m. UTC | #3
On Tue, 27 Jul 2010, Jason Merrill wrote:

> On 07/21/2010 08:45 PM, Le-Chun Wu wrote:
> > On Tue, Jun 29, 2010 at 9:29 PM, Jason Merrill<jason@redhat.com>  wrote:
> > > 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?
> > 
> > Yes, that's right.  This is a great catch. Wrapping uses of decls will
> > surely help in this case but, as you also said, it will require a
> > significant amount of work to make such a change to the IR. For now,
> > to fix this issue, I would clear the expr_folded flag after the
> > self-assign check (for each statement) is done. I also added comments
> > in tree.h to warn people not to use this flag in other places, and
> > added a new test for this case. What do you think?
> 
> That's certainly better, but it still makes me a bit uncomfortable to have a
> flag that's just used for transient marking.  Is it possible to avoid the need
> for this flag in the C front end, since it delays folding until c_fully_fold?

Btw, decls and constants are shared so it's certainly bogus to
set this flag there.  The proper thing to do is wrap the trees in
sth else (like NON_LVALUE_EXPR).

Richard.
diff mbox

Patch

Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 162385)
+++ 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
@@ -2944,6 +2943,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
@@ -3144,24 +3144,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
@@ -3330,6 +3312,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
@@ -3453,6 +3482,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
@@ -3482,9 +3515,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 162385)
+++ gcc/c-family/c-gimplify.c	(working copy)
@@ -172,18 +172,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 162385)
+++ 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 162385)
+++ 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;
+      handle_option (OPT_Wself_assign, value, NULL, c_family_lang_mask, kind);
 
       if (!c_dialect_cxx ())
 	{
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 162385)
+++ gcc/c-family/c-common.c	(working copy)
@@ -9305,4 +9305,30 @@  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)) {
+    if (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);
+  }
+  else
+    /* Clear the expr_folded flag as DECLS and CONSTANTS are shared by
+       expressions/statements. Without doing this, the compiler will not
+       warn on the second statement in the following example:
+
+         x = x + 0;
+         x = x;
+    */
+    set_expr_folded_flag (rhs, 0);
+}
+
 #include "gt-c-family-c-common.h"
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 162385)
+++ gcc/c-family/c-common.h	(working copy)
@@ -900,6 +900,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 162385)
+++ gcc/tree.h	(working copy)
@@ -387,8 +387,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
@@ -626,6 +627,16 @@  struct GTY(()) tree_common {
 
        SSA_NAME_IS_DEFAULT_DEF in
            SSA_NAME
+
+   expr_folded_flag:
+
+       EXPR_FOLDED in
+           all expressions
+           all decls
+           all constants
+       (This flag is used only for -Wself-assign warning and cleared after
+       the check (see check_for_self_assign in c-common.c). Don't use it in
+       other places/passes.)
 */
 
 #undef DEFTREESTRUCT
@@ -1350,6 +1361,12 @@  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. This flag is used only
+   for -Wself-assign warning and cleared after the check (see
+   check_for_self_assign in c-common.c). Don't use it in other places.  */
+#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)
@@ -4862,6 +4879,9 @@  extern int folding_initializer;
 extern int native_encode_expr (const_tree, unsigned char *, int);
 extern tree native_interpret_expr (tree, const unsigned char *, int);
 
+/* Set/reset the expr_folded flag.  */
+extern void set_expr_folded_flag (tree, int);
+
 /* Fold constants as much as possible in an expression.
    Returns the simplified expression.
    Acts only on the top level of the expression;
@@ -4924,7 +4944,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 162385)
+++ gcc/fold-const.c	(working copy)
@@ -2388,22 +2388,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)
@@ -2414,19 +2437,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);
@@ -2451,9 +2480,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.
@@ -2486,7 +2516,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.  */
@@ -2554,8 +2585,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:
@@ -7640,8 +7672,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;
@@ -8291,6 +8323,41 @@  fold_unary_loc (location_t loc, enum tre
     } /* switch (code) */
 }
 
+/* Given an expression tree EXP, set the EXPR_FOLDED flag with VALUE,
+   and if it is a nop, recursively set the EXPR_FOLDED flag of its operand.  */
+
+void
+set_expr_folded_flag (tree exp, int value)
+{
+  EXPR_FOLDED (exp) = value;
+
+  /* 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) = value;
+    }
+}
+
+/* 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, 1);
+  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
@@ -9393,8 +9460,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);
@@ -13095,6 +13162,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, 1);
+  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.  */
@@ -13131,8 +13216,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;
@@ -13467,6 +13552,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, 1);
+  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/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 162385)
+++ 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 162385)
+++ 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 162385)
+++ gcc/testsuite/gcc.dg/plugin/selfassign.c	(working copy)
@@ -194,7 +194,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;
 
@@ -247,7 +247,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 162385)
+++ 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 162385)
+++ 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 162385)
+++ gcc/testsuite/g++.dg/plugin/selfassign.c	(working copy)
@@ -194,7 +194,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;
 
@@ -247,7 +247,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/testsuite/g++.dg/warn/Wself-assign-6.C
===================================================================
--- gcc/testsuite/g++.dg/warn/Wself-assign-6.C	(revision 0)
+++ gcc/testsuite/g++.dg/warn/Wself-assign-6.C	(revision 0)
@@ -0,0 +1,10 @@ 
+// Test whether the expr_folded flag used by -Wself-assign is properly reset
+// after each check.
+// { dg-do compile }
+// { dg-options "-Wself-assign" }
+
+void bar() {
+  int x = 0;
+  x = x + 0;
+  x = x;             // { dg-warning "assigned to itself" }
+}
Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c	(revision 162385)
+++ gcc/cp/init.c	(working copy)
@@ -529,8 +529,14 @@  perform_member_init (tree member, tree i
 						tf_warning_or_error);
 
       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 162385)
+++ gcc/cp/parser.c	(working copy)
@@ -6918,6 +6918,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,
@@ -14090,6 +14096,10 @@  cp_parser_init_declarator (cp_parser* pa
 			 `explicit' constructor cannot be used.  */
 		      ((is_direct_init || !is_initialized)
 		       ? LOOKUP_NORMAL : LOOKUP_IMPLICIT));
+      /* 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/c-parser.c
===================================================================
--- gcc/c-parser.c	(revision 162385)
+++ 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
@@ -4764,7 +4769,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;