3

My question is similar to this answered question, but with one big difference.

If I try to compile the following,

void test(string x){
  int x = 5;
  cout << x << endl;
}

I get the expected warning:

In function ‘void test(std::__cxx11::string)’:
error: declaration of ‘int x’ shadows a parameter
    int x = 5;
        ^

Now to get to the meat of my question; if I have a type with a function call operator like the following:

struct foo{
  string bar;
  foo(const string& bar) : bar(bar) { }
  void operator()(){
    cout << "my bar is \"" << bar << '"' << endl;
  }
};

I can create a temporary object and call its () operator with foo("this will print")(); or with foo{"this will also print"}();

If I try to do the following, I will get a compiler error which is expected and can be explained with the post I linked above.

void redeclaration_error(){
  string x("lol");
  foo(x)();
}

However, things get weird here:

void hmm1(string str){
  foo(str)();
}
void hmm2(string str){
  foo{str}();
}

While hmm2 will print out its argument when called, hmm1 will do absolutely nothing. This is expected, as hmm1's body does nothing more than declare str to be of type foo. However, in the scope of hmm1, str is already declared as type string from the function's parameter, so why does this not result in a compiler error like error: declaration of ‘foo str‘ shadows a parameter?

I understand that the compiler is interpreting foo(str)(); as a declaration, and that lines like foo(str).operator()(); and (foo(str))(); will be interpreted as creating a temporary foo object and calling their function call operator, but why it it okay to declare a variable with the same name as a parameter in this circumstance?


Here's and Ideone link where I was playing around with this.

M.M
  • 138,810
  • 21
  • 208
  • 365
Jeffrey Cash
  • 1,023
  • 6
  • 12
  • 1
    Looks like gcc's bug, clang issues an error: https://godbolt.org/z/ECiUdI – R2RT Mar 06 '19 at 22:57
  • 1
    MSVC also rejects it. – aschepler Mar 06 '19 at 22:58
  • Interesting! Thanks for testing it out on other compilers for me, I should have tried that too. I guess I trust gcc more than I should – Jeffrey Cash Mar 06 '19 at 23:02
  • 1
    You should report this, looks definitely like a bug – XapaJIaMnu Mar 06 '19 at 23:15
  • @XapaJIaMnu I'll do that as soon as soon as GCC Bugzilla gets back to me about creating an account. Also, can I mark a post as solved without having received an answer? – Jeffrey Cash Mar 06 '19 at 23:19
  • Please don't edit answers into the question, if you've concluded it's a bug and nobody wrote an answer yet then you can post that in the answer box – M.M Mar 07 '19 at 00:19
  • @M.M gotcha. So should I just answer my own question and mark it as solved? That just seems like an odd thing to do – Jeffrey Cash Mar 07 '19 at 00:35
  • That's a fairly normal thing to do if the people who answered answered in comments instead of posting an answer :) – M.M Mar 07 '19 at 00:39
  • Although I am not convinced about the supposed rule that a variable declared in the function body cannot have the same name as a function parameter , the standard does not seem to say that (perhaps a separate question would be in order there) – M.M Mar 07 '19 at 00:43
  • @M.M I'll look into it more, but I checked an old working draft of the C++ standard, and found the following: ["A parameter name shall not be redeclared in the outermost block of the function definition nor in the outermost block of any handler associated with a function-try-block" (3.3.2)](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2691.pdf). This makes me pretty certain it is a GCC bug, unless there have been changes to the standard in this area since this draft – Jeffrey Cash Mar 07 '19 at 01:08
  • 1
    @JeffreyCash Ah that looks correct – M.M Mar 07 '19 at 01:14
  • 1
    OK, I posted an answer based on the comments and marked it as 'community' accordingly – M.M Mar 07 '19 at 01:16

1 Answers1

1

A simpler program to produce the same issue (the extra parentheses are a red herring):

void f(int x)
{
    void x();
}

This is incorrect because of C++17 [basic.scope.block]/2:

[...] A parameter name shall not be redeclared in the outermost block of the function definition nor in the outermost block of any handler associated with a function-try-block.

If a compiler accepts this code then it is a compiler bug.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • Awesome job distilling it down to its simplest form! I'll file a bug report as soon as I can. I'm amazed this has been in GCC for so long, it's been in every version I've checked between 4.4.7 and 8.3 – Jeffrey Cash Mar 07 '19 at 01:25