20

In the following example:

class A
{
  public:
    int len();
    void setLen(int len) { len_ = len; } // warning at this line
  private:
    int len_;
};

gcc with -Wshadow issue a warning:

main.cpp:4: warning: declaration of `len' shadows a member of `this'

function len and integer len are of different type. Why the warning?

Update

I see there's a wide consensus of what "shadow" means. And from a formal point of view, the compiler does exactly what it's meant to do.

However IMHO, the flag is not practical. For example commonly used setter/getter idiom :

class A {
   void prop(int prop);  // setter
   int prop() const;     // getter

   int prop;
};

It would be nice if there was a warning flag that won't issue warning in the case, but will warn in case "int a" hides "int a".

Adding -Wshadow on my legacy code issues tons of warnings, while from time to time I discover bugs caused by "shadowing" problem.

I don't mind how it will be called "-Wmuch_more_practical_and_interesting_shadow" or "-Wfoooooo".

So, are there other gcc warning flags that do what I described?

Update 2

I'm not the only one who thinks -Wshadow is somehow not useful link text. I'm not alone :) Less strict checking could be much more useful.

benathon
  • 7,455
  • 2
  • 41
  • 70
dimba
  • 26,717
  • 34
  • 141
  • 196

7 Answers7

28

This seems to be solved on newer versions of GCC.

From version 4.8 changelog:

The option -Wshadow no longer warns if a declaration shadows a function declaration,
unless the former declares a function or pointer to function, because this is a common
and valid case in real-world code.

And it references Linus Torvalds's thoughts on the subject: https://lkml.org/lkml/2006/11/28/253

Unfortunately the newest compiler of the embedded system where I'm currently working is still based on gcc 4.6.

Joseph Quinsey
  • 9,553
  • 10
  • 54
  • 77
mMontu
  • 8,983
  • 4
  • 38
  • 53
  • +1 for this answer. -1 to GCC for this decision, though! – Lightness Races in Orbit May 15 '14 at 16:40
  • 7
    Actually as of GCC 4.8.2 this issue with -Wshadow is still there. If you read through this bugzilla issue: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57709 it's confirmed that _member_ functions that are named the same as a function parameter, as in your example, still generate the shadow warning. As of GCC 4.8, only free functions have this error suppressed. Looks like we have to wait until GCC 5.0 to have this work the way you'd expect. – ScottG Sep 25 '14 at 12:56
16

The fact that the parameter has a different type from the member function doesn't affect the fact that the parameter shadows the member function.

Why would you expect there not to be a warning about this?

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • I'm interesting in cases when variable hides variable. This potentially a bug. But case when variable "hides" a function is just not interesting. – dimba Jun 02 '10 at 14:11
  • 5
    @idimba: I disagree. A function pointer may be stored in a variable. Also a variable may have an `operator()` defined for it so it can be invoked like a function. – Troubadour Jun 02 '10 at 14:14
  • 7
    It may not be interesting, but it *is* shadowing. And the warning is called -Wshadow, not -Winteresting. So I'd expect it to warn when one name hides another, not when @idimba thinks the code is "interesting". – jalf Jun 02 '10 at 14:14
  • 32
    @jalf: I'd pay good money for a compiler that had a -Winteresting flag that only showed me warnings about which I was interested. – James McNellis Jun 02 '10 at 14:15
10

I don't understand why you insist only on some specific types of shadowing. Shadowing is shadowing, and the dangers of it are the same even if the types are different and even if a variable shadows a function, as in your case. The danger of shadowing is that the code might do something different from what its author wanted it to do.

This, BTW, can easily happen when a variable is shadowing a function, since in C++ the distinction between the two is much thinner than it might seem at the first sight.

For example, here a variable shadows a function

struct L { 
  void operator ()(); 
};

struct A {
  void len();

  A(L len) {
    len();
    // Intended to call the member function. Instead got a call to the functor
  }
};

and I think it is pretty obvious that because of the shadowing the code might do something the author did not intend it to do.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
8

It does exactly what it says on the box. It warns you of shadowing.

Inside the setLen function, two symbols are in scope which share the same name. len is the name of a function parameter, and also the name of a function.

One shadows the name of the other, so when you write code that refers to len, you may not get the result you wanted. Since you asked the compiler to warn you about symbols shadowing for each others, this is what it warns you about.

jalf
  • 243,077
  • 51
  • 345
  • 550
6

Even though this is a fairly old question, in GCC >= 7 there now exist three variants of -Wshadow with varying impact on the programmers sanity. From the man-page of GCC 9.1.0:

  • -Wshadow=global

The default for -Wshadow. Warns for any (global) shadowing.

  • -Wshadow=local

Warn when a local variable shadows another local variable or parameter. This warning is enabled by -Wshadow=global.

  • -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 -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:

               for (SomeIterator i = SomeObj.begin(); i != SomeObj.end(); ++i)
               {
                 for (int i = 0; i < N; ++i)
                 {
                   ...
                 }
                 ...
               }

Since the two variable "i" in the example above have incompatible types, enabling only -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 -Wshadow=local can possibly reduce the number of warnings triggered by intentional shadowing.

This warning is enabled by -Wshadow=local.

Daniel E.
  • 91
  • 1
  • 3
2

Yea, we can tune this warning to warn only when the shadowing might be dangerous. For example do not shadow for

void set(int what).. int what() const ..

but warn for local variable shadowning and for the functor example above.

To be more exact, warn when the shadowing might be dangerous, when the intent of the code writer might not be clear. In the case of an int parameter and a member function having the same name, it is clear that the author does not want the member to be called when he/she references the parameter.

I find this shadow warning to be a good idea, very helpful, it just needs a bit more thought to not warn about perfectly safe and clear cases. I for example can live with arguments needed to have a prefix or something, but I prefer clean and simple names.

Mehul Mistri
  • 15,037
  • 14
  • 70
  • 94
0

From the Update section of the question:

class A {
   void prop(int prop);  // setter
   int prop() const;     // getter

   int prop;
};

This is simply an error; you cannot have both a member variable and a method with the same name.

The minimal changes with respect to your example that give a working interface are:

class A {
public:
  void prop(int prop);  // setter
  int prop() const;     // getter

private:
   int prop_;
};
fwyzard
  • 2,364
  • 1
  • 21
  • 19