Add -Wshadow=global -Wshadow=local and -Wshadow=compatible-local.

This patch from Le-Chun Wu adds two new shadow warning flags for
C and C++:

  -Wshadow=local which warns if a local variable shadows another local
  variable or parameter,

  -Wshadow=compatible-local which warns if a local variable shadows
  another local variable or parameter whose type is compatible with
  that of the shadowing variable.

It is already on the google/main branch (Google ref 39127) and was
previously submitted by Diego Novillo and reviewed on
http://codereview.appspot.com/4452058

I addressed the review comments and made the following changes:
- Add -Wshadow=global (the default alias for -Wshadow).
- Make the documented options -Wshadow=global, -Wshadow=local
  and -Wshadow=compatible-local (with hidden undocumented aliases
  -Wshadow-local and -Wshadow-compatible-local for compatibility).
- The -Wshadow=global, -Wshadow=local and -Wshadow=compatible-local
  relationships are expressed in common.opt instead of in opts.c
  and documented in invoke.texi.
- The "previous declaration" warnings were turned into notes and use
  the (now) existing infrastructure instead of duplicating the warnings.
  The testcases have been adjusted to expect the notes.
- The conditional change in name-lookup.c for non-locals (where we
  don't want to change the warnings, but just check the global ones)
  has been dropped.
- Use warning_at in c-decl.c (warn_if_shadowing).

gcc/ChangeLog:
2016-10-30  Le-Chun Wu  <lcwu@google.com>
            Mark Wielaard  <mjw@redhat.com>

       * doc/invoke.texi: Document Wshadow-local and Wshadow-compatible-local.
       * common.opt (Wshadow=global): New option. Default for -Wshadow.
       (Wshadow=local): New option.
       (Wshadow-local): Hidden alias for -Wshadow=local.
       (Wshadow=compatible-local): New option.
       (Wshadow-compatible-local): Hidden alias for
       -Wshadow=compatible-local.
       * doc/invoke.texi: Document Wshadow=global, Wshadow=local and
       Wshadow=compatible-local.

gcc/c/ChangeLog:
2016-10-30  Le-Chun Wu  <lcwu@google.com>
            Mark Wielaard  <mjw@redhat.com>

       * c-decl.c (warn_if_shadowing): Use the warning code corresponding
       to the given -Wshadow= variant. Use warning_at.

gcc/cp/ChangeLog:
2016-10-30  Le-Chun Wu  <lcwu@google.com>
            Mark Wielaard  <mjw@redhat.com>

       * name-lookup.c (pushdecl_maybe_friend): When emitting a
       shadowing warning, use the code corresponding to the
       given -Wshadow= variant.

gcc/testsuite/ChangeLog
2016-10-30  Le-Chun Wu  <lcwu@google.com>
            Mark Wielaard  <mjw@redhat.com>

       * gcc.dg/Wshadow-compatible-local-1.c: New test.
       * gcc.dg/Wshadow-local-1.c: Likewise.
       * gcc.dg/Wshadow-local-2.c: Likewise.
       * g++.dg/warn/Wshadow-compatible-local-1.C: Likewise.
       * g++.dg/warn/Wshadow-local-1.C: Likewise.
       * g++.dg/warn/Wshadow-local-2.C: Likewise.

Co-Authored-By: Mark Wielaard <mjw@redhat.com>

From-SVN: r241699
This commit is contained in:
Le-Chun Wu 2016-10-31 13:21:59 +00:00 committed by Mark Wielaard
parent 6517958578
commit 84ff4775d4
15 changed files with 439 additions and 11 deletions

View File

@ -1,3 +1,15 @@
2016-09-11 Le-Chun Wu <lcwu@google.com>
Mark Wielaard <mjw@redhat.com>
* common.opt (Wshadow=global): New option. Default for -Wshadow.
(Wshadow=local): New option.
(Wshadow-local): Hidden alias for -Wshadow=local.
(Wshadow=compatible-local): New option.
(Wshadow-compatible-local): Hidden alias for
-Wshadow=compatible-local.
* doc/invoke.texi: Document Wshadow=global, Wshadow=local and
Wshadow=compatible-local.
2016-10-31 Bin Cheng <bin.cheng@arm.com>
* tree-vect-slp.c (vect_get_and_check_slp_defs): New parameter SWAP.

View File

@ -1,3 +1,9 @@
2016-09-11 Le-Chun Wu <lcwu@google.com>
Mark Wielaard <mjw@redhat.com>
* c-decl.c (warn_if_shadowing): Use the warning code corresponding
to the given -Wshadow= variant.
2016-10-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
* c-typeck.c: Include memmodel.h.

View File

@ -2735,7 +2735,9 @@ warn_if_shadowing (tree new_decl)
struct c_binding *b;
/* Shadow warnings wanted? */
if (!warn_shadow
if (!(warn_shadow
|| warn_shadow_local
|| warn_shadow_compatible_local)
/* No shadow warnings for internally generated vars. */
|| DECL_IS_BUILTIN (new_decl)
/* No shadow warnings for vars made for inlining. */
@ -2759,9 +2761,23 @@ warn_if_shadowing (tree new_decl)
break;
}
else if (TREE_CODE (old_decl) == PARM_DECL)
warned = warning (OPT_Wshadow,
"declaration of %q+D shadows a parameter",
new_decl);
{
enum opt_code warning_code;
/* If '-Wshadow=compatible-local' is specified without other
-Wshadow= flags, we will warn only when the types of the
shadowing variable (i.e. new_decl) and the shadowed variable
(old_decl) are compatible. */
if (warn_shadow)
warning_code = OPT_Wshadow;
else if (comptypes (TREE_TYPE (old_decl), TREE_TYPE (new_decl)))
warning_code = OPT_Wshadow_compatible_local;
else
warning_code = OPT_Wshadow_local;
warned = warning_at (DECL_SOURCE_LOCATION (new_decl), warning_code,
"declaration of %qD shadows a parameter",
new_decl);
}
else if (DECL_FILE_SCOPE_P (old_decl))
{
/* Do not warn if a variable shadows a function, unless
@ -2784,8 +2800,23 @@ warn_if_shadowing (tree new_decl)
break;
}
else
warned = warning (OPT_Wshadow, "declaration of %q+D shadows a "
"previous local", new_decl);
{
enum opt_code warning_code;
/* If '-Wshadow=compatible-local' is specified without other
-Wshadow= flags, we will warn only when the types of the
shadowing variable (i.e. new_decl) and the shadowed variable
(old_decl) are compatible. */
if (warn_shadow)
warning_code = OPT_Wshadow;
else if (comptypes (TREE_TYPE (old_decl), TREE_TYPE (new_decl)))
warning_code = OPT_Wshadow_compatible_local;
else
warning_code = OPT_Wshadow_local;
warned = warning_at (DECL_SOURCE_LOCATION (new_decl), warning_code,
"declaration of %qD shadows a previous local",
new_decl);
}
if (warned)
inform (DECL_SOURCE_LOCATION (old_decl),

View File

@ -668,7 +668,25 @@ Warn about returning a pointer/reference to a local or temporary variable.
Wshadow
Common Var(warn_shadow) Warning
Warn when one local variable shadows another.
Warn when one variable shadows another. Same as -Wshadow=global.
Wshadow=global
Common Warning Alias(Wshadow)
Warn when one variable shadows another (globally).
Wshadow=local
Common Var(warn_shadow_local) Warning EnabledBy(Wshadow)
Warn when one local variable shadows another local variable or parameter.
Wshadow-local
Common Warning Undocumented Alias(Wshadow=local)
Wshadow=compatible-local
Common Var(warn_shadow_compatible_local) Warning EnabledBy(Wshadow=local)
Warn when one local variable shadows another local variable or parameter of compatible type.
Wshadow-compatible-local
Common Warning Undocumented Alias(Wshadow=compatible-local)
Wstack-protector
Common Var(warn_stack_protect) Warning

View File

@ -1,3 +1,10 @@
2016-09-11 Le-Chun Wu <lcwu@google.com>
Mark Wielaard <mjw@redhat.com>
* name-lookup.c (pushdecl_maybe_friend): When emitting a
shadowing warning, use the code corresponding to the
given -Wshadow= variant.
2016-10-26 Jason Merrill <jason@redhat.com>
* class.c (add_method): Allow using-declarations to coexist.

View File

@ -1195,19 +1195,41 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
nowarn = true;
}
if (warn_shadow && !nowarn)
if ((warn_shadow
|| warn_shadow_local
|| warn_shadow_compatible_local)
&& !nowarn)
{
bool warned;
enum opt_code warning_code;
/* If '-Wshadow=compatible-local' is specified without other
-Wshadow= flags, we will warn only when the type of the
shadowing variable (i.e. x) can be converted to that of
the shadowed parameter (oldlocal). The reason why we only
check if x's type can be converted to oldlocal's type
(but not the other way around) is because when users
accidentally shadow a parameter, more than often they
would use the variable thinking (mistakenly) it's still
the parameter. It would be rare that users would use the
variable in the place that expects the parameter but
thinking it's a new decl. */
if (warn_shadow)
warning_code = OPT_Wshadow;
else if (can_convert (TREE_TYPE (oldlocal), TREE_TYPE (x),
tf_none))
warning_code = OPT_Wshadow_compatible_local;
else
warning_code = OPT_Wshadow_local;
if (TREE_CODE (oldlocal) == PARM_DECL)
warned = warning_at (input_location, OPT_Wshadow,
warned = warning_at (input_location, warning_code,
"declaration of %q#D shadows a parameter", x);
else if (is_capture_proxy (oldlocal))
warned = warning_at (input_location, OPT_Wshadow,
warned = warning_at (input_location, warning_code,
"declaration of %qD shadows a lambda capture",
x);
else
warned = warning_at (input_location, OPT_Wshadow,
warned = warning_at (input_location, warning_code,
"declaration of %qD shadows a previous local",
x);

View File

@ -293,6 +293,7 @@ Objective-C and Objective-C++ Dialects}.
-Wpointer-arith -Wno-pointer-to-int-cast @gol
-Wno-pragmas -Wredundant-decls -Wno-return-local-addr @gol
-Wreturn-type -Wsequence-point -Wshadow -Wno-shadow-ivar @gol
-Wshadow=global, -Wshadow=local, -Wshadow=compatible-local @gol
-Wshift-overflow -Wshift-overflow=@var{n} @gol
-Wshift-count-negative -Wshift-count-overflow -Wshift-negative-value @gol
-Wsign-compare -Wsign-conversion -Wfloat-conversion @gol
@ -5321,6 +5322,7 @@ variable, parameter, type, class member (in C++), or instance variable
(in Objective-C) or whenever a built-in function is shadowed. Note
that in C++, the compiler warns if a local variable shadows an
explicit typedef, but not if it shadows a struct/class/enum.
Same as @option{-Wshadow=global}.
@item -Wno-shadow-ivar @r{(Objective-C only)}
@opindex Wno-shadow-ivar
@ -5328,6 +5330,48 @@ explicit typedef, but not if it shadows a struct/class/enum.
Do not warn whenever a local variable shadows an instance variable in an
Objective-C method.
@item -Wshadow=global
@opindex Wshadow=local
The default for @option{-Wshadow}. Warns for any (global) shadowing.
@item -Wshadow=local
@opindex Wshadow=local
Warn when a local variable shadows another local variable or parameter.
This warning is enabled by @option{-Wshadow=global}.
@item -Wshadow=compatible-local
@opindex Wshadow=compatible-local
Warn when a local variable shadows another local variable or parameter
whose type is compatible with that of the shadowing variable. In C++,
type compatibility here means the type of the shadowing variable can be
converted to that of the shadowed variable. The creation of this flag
(in addition to @option{-Wshadow=local}) is based on the idea that when
a local variable shadows another one of incompatible type, it is most
likely intentional, not a bug or typo, as shown in the following example:
@smallexample
@group
for (SomeIterator i = SomeObj.begin(); i != SomeObj.end(); ++i)
@{
for (int i = 0; i < N; ++i)
@{
...
@}
...
@}
@end group
@end smallexample
Since the two variable @code{i} in the example above have incompatible types,
enabling only @option{-Wshadow=compatible-local} will not emit a warning.
Because their types are incompatible, if a programmer accidentally uses one
in place of the other, type checking will catch that and emit an error or
warning. So not warning (about shadowing) in this case will not lead to
undetected bugs. Use of this flag instead of @option{-Wshadow=local} can
possibly reduce the number of warnings triggered by intentional shadowing.
This warning is enabled by @option{-Wshadow=local}.
@item -Wlarger-than=@var{len}
@opindex Wlarger-than=@var{len}
@opindex Wlarger-than-@var{len}

View File

@ -1,3 +1,14 @@
2016-10-30 Le-Chun Wu <lcwu@google.com>
Mark Wielaard <mjw@redhat.com>
* gcc.dg/Wshadow-compatible-local-1.c: New test.
* gcc.dg/Wshadow-local-1.c: Likewise.
* gcc.dg/Wshadow-local-2.c: Likewise.
* g++.dg/warn/Wshadow-compatible-local-1.C: Likewise.
* g++.dg/warn/Wshadow-local-1.C: Likewise.
* g++.dg/warn/Wshadow-local-2.C: Likewise.
2016-10-30 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
PR tree-optimization/71915

View File

@ -0,0 +1,63 @@
/* { dg-do compile } */
/* { dg-options -Wshadow=compatible-local } */
class Bar {
};
class ChildBar : public Bar {
};
Bar bar;
class Foo {
private:
int val;
public:
int func1(int x) {
int val;
val = x;
return val;
}
int func2(int i) { // { dg-message "note: shadowed declaration is here" }
int a = 3; // { dg-message "note: shadowed declaration is here" }
for (int i = 0; i < 5; ++i) { // { dg-warning "shadows a parameter" }
for (int i = 0; i < 3; ++i) { // { dg-warning "shadows a previous local" }
int a = i; // { dg-warning "shadows a previous local" }
func1(a);
}
}
return a;
}
int func3() {
int bar;
float func1 = 0.3;
int f = 5; // { dg-message "note: shadowed declaration is here" }
if (func1 > 1) {
float f = 2.0; // { dg-warning "shadows a previous local" }
bar = f;
}
else
bar = 1;
return bar;
}
void func4() {
Bar *bar; // { dg-bogus "shadowed declaration" }
ChildBar *cbp; // { dg-bogus "shadowed declaration" }
Bar *bp; // { dg-message "note: shadowed declaration is here" }
if (val) {
int bar; // { dg-bogus "shadows a previous local" }
Bar *cbp; // { dg-bogus "shadows a previous local" }
ChildBar *bp; // { dg-warning "shadows a previous local" }
func1(bar);
}
}
};
// { dg-message "note: shadowed declaration" "" { target *-*-* } 26 }

View File

@ -0,0 +1,35 @@
/* { dg-do compile } */
/* { dg-options -Wshadow=local } */
struct status
{
int member;
void foo2 ();
inline static int foo3 (int member)
{
return member;
}
};
int decl1; // { dg-bogus "shadowed declaration" }
int decl2; // { dg-bogus "shadowed declaration" }
void foo (struct status &status,
double decl1) // { dg-bogus "shadows a global" }
{
}
void foo1 (int d)
{
double d; // { dg-error "shadows a parameter" }
}
void status::foo2 ()
{
int member; // { dg-bogus "shadows a member" }
int decl2; // { dg-bogus "shadows a global" }
int local; // { dg-message "note: shadowed declaration is here" }
{
int local; // { dg-warning "shadows a previous local" }
}
}

View File

@ -0,0 +1,63 @@
/* { dg-do compile } */
/* { dg-options -Wshadow=local } */
class Bar {
};
class ChildBar : public Bar {
};
Bar bar; // { dg-bogus "shadowed declaration" }
class Foo {
private:
int val;
public:
int func1(int x) {
int val; // { dg-bogus "shadows a member" }
val = x;
return val;
}
int func2(int i) { // { dg-message "shadowed declaration is here" }
int a = 3; // { dg-message "shadowed declaration is here" }
for (int i = 0; i < 5; ++i) { // { dg-warning "shadows a parameter" }
for (int i = 0; i < 3; ++i) { // { dg-warning "shadows a previous local" }
int a = i; // { dg-warning "shadows a previous local" }
func1(a);
}
}
return a;
}
int func3() {
int bar; // { dg-bogus "shadows a global" }
float func1 = 0.3; // { dg-bogus "shadows a member" }
int f = 5; // { dg-message "shadowed declaration is here" }
if (func1 > 1) {
float f = 2.0; // { dg-warning "shadows a previous local" }
bar = f;
}
else
bar = 1;
return bar;
}
void func4() {
Bar *bar; // { dg-message "shadowed declaration is here" }
ChildBar *cbp; // { dg-message "shadowed declaration is here" }
Bar *bp; // { dg-message "shadowed declaration is here" }
if (val) {
int bar; // { dg-warning "shadows a previous local" }
Bar *cbp; // { dg-warning "shadows a previous local" }
ChildBar *bp; // { dg-warning "shadows a previous local" }
func1(bar);
}
}
};
// { dg-message "shadowed declaration is here" "" { target *-*-* } 26 }

View File

@ -0,0 +1,36 @@
/* { dg-do compile } */
/* { dg-options "-Wshadow=compatible-local" } */
struct Bar {
};
struct Bar bar; /* { dg-bogus "shadowed declaration" } */
int val; /* { dg-bogus "shadowed declaration" } */
int func1(int x) { /* { dg-bogus "shadowed declaration" } */
int val; /* { dg-bogus "shadows a global" } */
val = x;
return val;
}
int func2(int i) {
int a = 3; /* { dg-message "shadowed declaration" } */
int j; /* { dg-message "shadowed declaration" } */
for (j = 0; j < i; ++j) {
int a = j; /* { dg-warning "shadows a previous local" } */
int j = a + 1; /* { dg-warning "shadows a previous local" } */
func1(j);
}
return a;
}
void func4() {
struct Bar bar; /* { dg-bogus "shadowed declaration" } */
if (val) {
int bar; /* { dg-bogus "shadows a previous local" } */
func1(bar);
}
}

View File

@ -0,0 +1,22 @@
/* { dg-do compile } */
/* { dg-options "-Wshadow=local" } */
int decl1; /* should not warn */
void foo (double decl1) /* should not warn */
{
}
void foo2 (int d) /* { dg-message "shadowed declaration" } */
{
{
double d; /* { dg-warning "shadows a parameter" } */
}
}
void foo3 ()
{
int local; /* { dg-message "shadowed declaration" } */
{
int local; /* { dg-warning "shadows a previous local" } */
}
}

View File

@ -0,0 +1,49 @@
/* { dg-do compile } */
/* { dg-options "-Wshadow=local" } */
struct Bar {
};
struct Bar bar; /* { dg-bogus "shadowed declaration" } */
int val; /* { dg-bogus "shadowed declaration" } */
int func1(int x) { /* { dg-bogus "shadowed declaration" } */
int val; /* { dg-bogus "shadows a global" } */
val = x;
return val;
}
int func2(int i) {
int a = 3; /* { dg-message "shadowed declaration" } */
int j; /* { dg-message "shadowed declaration" } */
for (j = 0; j < i; ++j) {
int a = j; /* { dg-warning "shadows a previous local" } */
int j = a + 1; /* { dg-warning "shadows a previous local" } */
func1(j);
}
return a;
}
int func3() {
int bar; /* { dg-bogus "shadows a global" } */
float func1 = 0.3; /* { dg-bogus "shadows a global" } */
if (func1 > 1)
bar = 2;
else
bar = 1;
return bar;
}
void func4() {
struct Bar bar; /* { dg-message "shadowed declaration" } */
if (val) {
int bar; /* { dg-warning "shadows a previous local" } */
func1(bar);
}
}
/* { dg-bogus "shadows a global" "" { target *-*-* } 42 } */

View File

@ -0,0 +1,9 @@
/* { dg-do compile } */
/* { dg-options "-Wno-shadow" } */
void func() {
int i;
{
int i; /* should not warn */
}
}