12

Compiling the following code

template <typename X, typename F>
auto apply(X x, F f)
{
    return f(x);
}

template <typename Y>
auto add_value(Y y)
{
    return [y](auto x)
    {
        return x + y;
    };
}

int main()
{
    apply(1, add_value(2));
}

with g++ (e.g. v. 5.4) gives shadow warnings.

$ g++ -Wshadow -Werror -std=c++14 shadow_test.cpp 
shadow_test.cpp: In instantiation of ‘add_value(Y)::<lambda(auto:1)> [with auto:1 = int; Y = int]’:
shadow_test.cpp:4:13:   required from ‘auto apply(X, F) [with X = int; F = add_value(Y) [with Y = int]::<lambda(auto:1)>]’
shadow_test.cpp:18:26:   required from here
shadow_test.cpp:10:22: error: declaration of ‘int x’ shadows a parameter [-Werror=shadow]
     return [y](auto x)
                      ^
shadow_test.cpp:2:14: note: shadowed declaration is here
 auto apply(X x, F f)
              ^
cc1plus: all warnings being treated as errors

I do not understand why. Can anybody explain?

Tobias Hermann
  • 9,936
  • 6
  • 61
  • 134

1 Answers1

7

Must be a bug.

  • The variable is not being shadowed as it is not in the enclosing scope of the lambda, however it does produce the correct result.
  • VS2015 produces no warnings.
  • Clang produces no warnings.

This is speculative, but what is probably happening is the following substitution (or something like it):

#include <iostream>

template <typename X, typename Y>
auto add_value(X x, Y y)
{
    auto f = [y](auto x)
    {
        return x + y;
    };
    return f(x);
}

int main()
{
    std::cout << add_value(1, 2);
}

This program does produce a shadow warning on Clang, but even then it produces the correct result. VS2015 still does not consider this worthy of a warning, but it is probably wrong because names from the enclosing scope of the lambda are also in the scope of the lambda. If they are not captured they may be used, but may not be odr-used as explained here.

Community
  • 1
  • 1
wally
  • 10,717
  • 5
  • 39
  • 72
  • Thanks. I just [filed a bug](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78850). – Tobias Hermann Dec 18 '16 at 14:16
  • You misunderstand what shadowing is. [Here](http://coliru.stacked-crooked.com/a/04c9525c1ecae0f1) is an example of a correct shadow warning in clang. Note that the program still produces the correct result, because the program is correct. (Still a bug in gcc because Tobias' code has no shadowing.) – Oktalist Dec 18 '16 at 15:13
  • @Oktalist That is a good example of how the shadow warning would be valid. I'll update the answer accordingly. – wally Dec 18 '16 at 15:23
  • @Oktalist Actually, now I wonder if even the clang warning is valid. x is not being captured in the lambda and so there should be no expectation that it not be shadowed, right? – wally Dec 18 '16 at 15:35
  • 1
    @Muscampester: The shadowing can be in effect even without a capture, e.g. `decltype` and `sizeof` don't need you to capture the entity, since it's purely compile-time information. – Xeo Dec 18 '16 at 15:42
  • @Xeo I was very surprised to see [this](http://coliru.stacked-crooked.com/a/c7e22aae7b58d1ca). VS2015 produces an error stating that `z` is an undeclared identifier, yet gcc and clang are happy to work with it. Ok found [this answer](http://stackoverflow.com/a/37404301/1460794) to explain. – wally Dec 18 '16 at 16:03
  • 1
    Same error in VS2017RC. Bug report [here](https://connect.microsoft.com/VisualStudio/Feedback/Details/3116537). – Oktalist Dec 18 '16 at 21:41