diff mbox

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

Message ID AANLkTik8O-6lEaPf9ZbKXrhR78XIc5OUfAgXfeOvdkhI@mail.gmail.com
State New
Headers show

Commit Message

Le-Chun Wu June 23, 2010, 9:21 p.m. UTC
Hi,

Here is the revised patch for the implementation of -Wself-assign
warning. Besides minor changes that address the review comments, the
major differences of this revised patch from the original one are (1)
-Wself-assign is enabled by -Wall, and (2) -Winit-self flag is
removed.

(For the discussion thread of the original patch, please see
http://gcc.gnu.org/ml/gcc-patches/2010-06/msg00974.html)

Bootstrapped and tested on x86_64-linux-gnu. OK for trunk?

Thanks,

Le-chun

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

	* gcc/doc/invoke.texi (-Wall): Include -Wself-assign.
	(-Wself-assign): New documentation for the flag.
	(-Winit-self): Removed.
	(-Wuninitialized): Remove mention of -Winit-self.
	(-Wunused-variable): Mention of new workaround.
	* gcc/c-family/c-gimplify.c (c_gimplify_expr): Remove support for
	-Winit-self.
	* gcc/c-family/c.opt: Remove -Winit-self 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/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.
	* gcc/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.
	* gcc/testsuite/gcc.dg/plugin/selfassign.c (check_self_assign):
	Renamed from warn_self_assign.
	* gcc/testsuite/gcc.dg/wself-assign-1.c: New test.
	* gcc/testsuite/gcc.dg/wself-assign-2.c: New test.
	* gcc/testsuite/gcc.dg/wself-assign-3.c: New test.
	* gcc/testsuite/gcc.dg/uninit-D-O0.c: Removed.
	* gcc/testsuite/gcc.dg/uninit-D.c: Removed.
	* gcc/testsuite/gcc.dg/uninit-E-O0.c: Removed.
	* gcc/testsuite/gcc.dg/uninit-E.c: Removed.
	* gcc/testsuite/g++.dg/plugin/selfassign.c (check_self_assign):
	Renamed from warn_self_assign.
	* gcc/testsuite/g++.dg/warn/Wself-assign-1.C: New test.
	* gcc/testsuite/g++.dg/warn/Wself-assign-2.C: New test.
	* gcc/testsuite/g++.dg/warn/Wself-assign-3.C: New test.
	* gcc/testsuite/g++.dg/warn/Wself-assign-4.C: New test.
	* gcc/testsuite/g++.dg/warn/Wself-assign-5.C: New test.
	* gcc/cp/init.c (perform_member_init): Check for self-assign after
	parsing class member initialization.
	* gcc/cp/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/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.

Comments

Paul Koning June 23, 2010, 9:30 p.m. UTC | #1
> ...
> Besides minor changes that address the review comments, the
> major differences of this revised patch from the original one are (1)
> -Wself-assign is enabled by -Wall, and (2) -Winit-self flag is
> removed.

Given that self-assign is the documented way to suppress a warning (for
uninitialized variable) is it appropriate for -Wall to turn this on?  It
would mean that code that was specifically fixed to avoid warnings under
-Wall will now get warnings again on that exact same line.  I don't
object to the feature itself, but I do object to that aspect.

	paul
Le-Chun Wu June 23, 2010, 9:56 p.m. UTC | #2
Paul,

On Wed, Jun 23, 2010 at 2:30 PM, Paul Koning <Paul_Koning@dell.com> wrote:
>> ...
>> Besides minor changes that address the review comments, the
>> major differences of this revised patch from the original one are (1)
>> -Wself-assign is enabled by -Wall, and (2) -Winit-self flag is
>> removed.
>
> Given that self-assign is the documented way to suppress a warning (for
> uninitialized variable) is it appropriate for -Wall to turn this on?  It
> would mean that code that was specifically fixed to avoid warnings under
> -Wall will now get warnings again on that exact same line.  I don't
> object to the feature itself, but I do object to that aspect.
>

This patch actually removes the paragraph in invoke.texi that
recommends using self-initialization to suppress uninitialized
variable warnings. Yes, this would be a disruptive change to people
who use self-initialization, but in my opinion, self-initialization
doesn't really make sense and is not a good way to fix or work around
uninitialized variable warnings. (One can initialize a variable with
other more meaningful value as easily.)

Le-chun
Le-Chun Wu June 23, 2010, 10:15 p.m. UTC | #3
On Wed, Jun 23, 2010 at 2:56 PM, Le-Chun Wu <lcwu@google.com> wrote:
> Paul,
>
> On Wed, Jun 23, 2010 at 2:30 PM, Paul Koning <Paul_Koning@dell.com> wrote:
>>> ...
>>> Besides minor changes that address the review comments, the
>>> major differences of this revised patch from the original one are (1)
>>> -Wself-assign is enabled by -Wall, and (2) -Winit-self flag is
>>> removed.
>>
>> Given that self-assign is the documented way to suppress a warning (for
>> uninitialized variable) is it appropriate for -Wall to turn this on?  It
>> would mean that code that was specifically fixed to avoid warnings under
>> -Wall will now get warnings again on that exact same line.  I don't
>> object to the feature itself, but I do object to that aspect.
>>
>
> This patch actually removes the paragraph in invoke.texi that
> recommends using self-initialization to suppress uninitialized
> variable warnings. Yes, this would be a disruptive change to people
> who use self-initialization, but in my opinion, self-initialization
> doesn't really make sense and is not a good way to fix or work around
> uninitialized variable warnings. (One can initialize a variable with
> other more meaningful value as easily.)
>

I forgot to mention that when this patch is approved and checked in, I
will also update gcc-4.6/changes.html to mention that
self-initialization is not longer a recommended way to suppress the
uninitialized variable warnings.

Le-chun
Joseph Myers June 23, 2010, 10:37 p.m. UTC | #4
On Wed, 23 Jun 2010, Le-Chun Wu wrote:

> Hi,
> 
> Here is the revised patch for the implementation of -Wself-assign
> warning. Besides minor changes that address the review comments, the
> major differences of this revised patch from the original one are (1)
> -Wself-assign is enabled by -Wall, and (2) -Winit-self flag is
> removed.
> 
> (For the discussion thread of the original patch, please see
> http://gcc.gnu.org/ml/gcc-patches/2010-06/msg00974.html)

I see nothing in that thread that justifies breaking backwards 
compatibility by removing an option.  The usual practice for non-semantic 
options (those not affecting how source code is interpreted or placing 
specific requirements on generated code) would be to keep as a no-op; this 
was done for -Wunreachable-code, for example.  It might perhaps be better 
to make -Winit-self an alias for the new option, as the nearest current 
equivalent.

> 	* gcc/doc/invoke.texi (-Wall): Include -Wself-assign.

Please give the ChangeLog entries separately for each affected ChangeLog 
file.  This one for example would go in gcc/ChangeLog and the entry would 
start "* doc/invoke.texi".  The logs in gcc/c-family and gcc/testsuite and 
gcc/cp would also have entries, with the paths being relative to the 
relevant ChangeLog directories.

> +@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 */

Note that an *initialization*, as opposed to an *assignment*, using i + 0 
as the initializer for i (or i + 1, for that matter), is an example of 
erroneous code (using an uninitialized value) people may well want a 
warning for and can get one for right now with -Winit-self.  Can they 
still get such a warning with the new option?

(The logic above seems fine for which *assignments* get warnings for being 
self-assignments.  Though if i is uninitialized, an assignment i = i + 0 
should still get a warning for the uninitialized use of i, and I hope it 
does; that warning doesn't depend on -Winit-self at present.)
Le-Chun Wu June 23, 2010, 11:59 p.m. UTC | #5
On Wed, Jun 23, 2010 at 3:37 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> On Wed, 23 Jun 2010, Le-Chun Wu wrote:
>
>> Hi,
>>
>> Here is the revised patch for the implementation of -Wself-assign
>> warning. Besides minor changes that address the review comments, the
>> major differences of this revised patch from the original one are (1)
>> -Wself-assign is enabled by -Wall, and (2) -Winit-self flag is
>> removed.
>>
>> (For the discussion thread of the original patch, please see
>> http://gcc.gnu.org/ml/gcc-patches/2010-06/msg00974.html)
>
> I see nothing in that thread that justifies breaking backwards
> compatibility by removing an option.  The usual practice for non-semantic
> options (those not affecting how source code is interpreted or placing
> specific requirements on generated code) would be to keep as a no-op; this
> was done for -Wunreachable-code, for example.  It might perhaps be better
> to make -Winit-self an alias for the new option, as the nearest current
> equivalent.

Yes, I agree we should not remove -Winit-self and break backwards
compatibility. I will put the option back. However, in this case I
think it's probably better to make it a no-op because -Winit-self used
to only work with -Wuninitialized. (i.e. Without using
-Wuninitialized, -Winit-self is a no-op.) Now that we remove the
functionality of -Winit-self, people who use -Wuninitialized will
always get a warning on the following code with or without
-Winit-self:

void func() {
  int i = i;
}

And also by not making it an alias of -Wself-assign, people who use
-Winit-self won't be surprised by the new warning on self-assignment
statements.

I will send out a revised patch later.

>
>>       * gcc/doc/invoke.texi (-Wall): Include -Wself-assign.
>
> Please give the ChangeLog entries separately for each affected ChangeLog
> file.  This one for example would go in gcc/ChangeLog and the entry would
> start "* doc/invoke.texi".  The logs in gcc/c-family and gcc/testsuite and
> gcc/cp would also have entries, with the paths being relative to the
> relevant ChangeLog directories.

Yes. I actually have separate ChangeLog files in my svn tree (and Eric
mention that to me as well). I was simply lazy and reused the
ChangeLog entry I sent out in my original patch. :-) I will send out
separate ChangeLog entries in my revised patch.

>
>> +@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 */
>
> Note that an *initialization*, as opposed to an *assignment*, using i + 0
> as the initializer for i (or i + 1, for that matter), is an example of
> erroneous code (using an uninitialized value) people may well want a
> warning for and can get one for right now with -Winit-self.  Can they
> still get such a warning with the new option?

The new flag doesn't warn on "int i = i + 0", but -Wuninitialized does
(which is a more appropriate option to control the warning on this
case, I think).

$ cat self-init.c
void func()
{
  int a = a + 0;
  int b = b + 1;
  int c;
  c = c + 0;
}

$ gcc -c self-init.c -Wuninitialized
self-init.c: In function ‘func’:
self-init.c:3:7: warning: ‘a’ is used uninitialized in this function
[-Wuninitialized]
self-init.c:4:7: warning: ‘b’ is used uninitialized in this function
[-Wuninitialized]
self-init.c:6:5: warning: ‘c’ is used uninitialized in this function
[-Wuninitialized]

So I think we are covered here.

>
> (The logic above seems fine for which *assignments* get warnings for being
> self-assignments.  Though if i is uninitialized, an assignment i = i + 0
> should still get a warning for the uninitialized use of i, and I hope it
> does; that warning doesn't depend on -Winit-self at present.)

Yes, it does. See the example above.

Thanks,

Le-chun
Joseph Myers June 24, 2010, 12:51 a.m. UTC | #6
On Wed, 23 Jun 2010, Le-Chun Wu wrote:

> The new flag doesn't warn on "int i = i + 0", but -Wuninitialized does
> (which is a more appropriate option to control the warning on this
> case, I think).

Agreed.  Perhaps instead of removing the -Winit-self testcases you should 
change them to verify that -Wuninitialized alone is now enough to enable 
those warnings.
Le-Chun Wu June 24, 2010, 12:52 a.m. UTC | #7
On Wed, Jun 23, 2010 at 5:51 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> On Wed, 23 Jun 2010, Le-Chun Wu wrote:
>
>> The new flag doesn't warn on "int i = i + 0", but -Wuninitialized does
>> (which is a more appropriate option to control the warning on this
>> case, I think).
>
> Agreed.  Perhaps instead of removing the -Winit-self testcases you should
> change them to verify that -Wuninitialized alone is now enough to enable
> those warnings.

That's exactly what I am doing now. :-)

Thanks,

Le-chun
Paul Koning June 24, 2010, 12:54 a.m. UTC | #8
> > Given that self-assign is the documented way to suppress a warning
> (for
> > uninitialized variable) is it appropriate for -Wall to turn this on?
>  It
> > would mean that code that was specifically fixed to avoid warnings
> under
> > -Wall will now get warnings again on that exact same line.  I don't
> > object to the feature itself, but I do object to that aspect.
> >
> 
> This patch actually removes the paragraph in invoke.texi that
> recommends using self-initialization to suppress uninitialized
> variable warnings. Yes, this would be a disruptive change to people
> who use self-initialization, but in my opinion, self-initialization
> doesn't really make sense and is not a good way to fix or work around
> uninitialized variable warnings. (One can initialize a variable with
> other more meaningful value as easily.)

Yes, and that's usually fine.  But there is a performance difference -- a small one admittedly.  If the initialization is in fact not necessary, then the existing coding convention suppresses the warning with no run-time overhead, while the proposed workaround you describe does have a run-time cost.

	paul
Le-Chun Wu June 24, 2010, 7:33 p.m. UTC | #9
On Wed, Jun 23, 2010 at 5:54 PM, Paul Koning <Paul_Koning@dell.com> wrote:
>> > Given that self-assign is the documented way to suppress a warning
>> (for
>> > uninitialized variable) is it appropriate for -Wall to turn this on?
>>  It
>> > would mean that code that was specifically fixed to avoid warnings
>> under
>> > -Wall will now get warnings again on that exact same line.  I don't
>> > object to the feature itself, but I do object to that aspect.
>> >
>>
>> This patch actually removes the paragraph in invoke.texi that
>> recommends using self-initialization to suppress uninitialized
>> variable warnings. Yes, this would be a disruptive change to people
>> who use self-initialization, but in my opinion, self-initialization
>> doesn't really make sense and is not a good way to fix or work around
>> uninitialized variable warnings. (One can initialize a variable with
>> other more meaningful value as easily.)
>
> Yes, and that's usually fine.  But there is a performance difference -- a small one admittedly.  If the initialization is in fact not necessary, then the existing coding convention suppresses the warning with no run-time overhead, while the proposed workaround you describe does have a run-time cost.
>

I would think most of the uninitialized warnings triggered are genuine
bugs and the programmers should just fix them. The self-init
workaround was probably used primarily to suppress the false positives
that were often caused by the analysis not understanding the
predicates that guard the definitions and uses of variables. Now that
David Li has checked in the patch that makes the uninitialized
variable analysis predicate-aware (r158835), the false positive rate
should go down quite a lot. And even for the rare cases where people
still have to suppress the warnings, as you said, the performance
difference of initializing a variable to a real value should be pretty
small (but the code would make more sense). So I still think that we
should include -Wself-assign in -Wall, and that people who use
self-initialization (with -Wall) should evaluate whether the false
positives still exist, and either remove the self-initialization or
change the initialization to a more meaningful value.

Thanks,

Le-chun
diff mbox

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)
@@ -258,10 +258,6 @@  Wignored-qualifiers
 C C++ Var(warn_ignored_qualifiers) Init(-1) Warning
 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
-
 Wimplicit
 C ObjC Var(warn_implicit) Init(-1) Warning
 Warn about implicit declarations
@@ -425,6 +421,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/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/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/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 +0,0 @@ 
-/* Test we do not warn about initializing variable with self. */
-/* { dg-do compile } */
-/* { dg-options "-Wuninitialized" } */
-
-int f()
-{
-  int i = i;
-  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 +0,0 @@ 
-/* Test we do not warn about initializing variable with self. */
-/* { dg-do compile } */
-/* { dg-options "-O -Wuninitialized" } */
-
-int f()
-{
-  int i = i;
-  return i;
-}
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,9 +0,0 @@ 
-/* Test we do warn about initializing variable with self when
-Winit-self is supplied. */
-/* { dg-do compile } */
-/* { dg-options "-Wuninitialized -Winit-self" } */
-
-int f()
-{
-  int i = i; /* { dg-warning "i" "uninitialized variable warning" }  */
-  return i;
-}
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,9 +0,0 @@ 
-/* Test we do warn about initializing variable with self when
-Winit-self is supplied. */
-/* { dg-do compile } */
-/* { dg-options "-O -Wuninitialized -Winit-self" } */
-
-int f()
-{
-  int i = i; /* { dg-warning "i" "uninitialized variable warning" }  */
-  return i;
-}
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/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;