Why does the following code generate a warning when it is compiled with g++ -Wshadow -std=c++14?
template<typename Function>
void f(Function g) {
int x;
g(0);
}
int main() {
auto g = [](auto x) {};
f(g);
return 0;
}
Compilation (assume this code is saved as lambda_shadow.cc):
$ g++ -std=c++14 -Wshadow lambda_shadow.cc
lambda_shadow.cc: In instantiation of ‘main()::<lambda(auto:1)> [with auto:1 = int]’:
lambda_shadow.cc:4:6: required from ‘void f(Function) [with Function = main()::<lambda(auto:1)>]’
lambda_shadow.cc:9:6: required from here
lambda_shadow.cc:8:21: warning: declaration of ‘x’ shadows a previous local [-Wshadow]
auto g = [](auto x) {};
^
lambda_shadow.cc:3:7: note: shadowed declaration is here
int x;
^
This warning is strange because g++ seems to follow the dynamic scoping rules.
I used g++ version 4.9.2 and 5.2.0, and clang++ 4.6 does not generate any warning.
In addition, I noticed that g++ compiles this code without warnings if a type of the lambda argument is specified (i.e., auto g = [](int x) {};).
Does anyone know the reason for this behavior? A bug of g++?
Related
Clang accepts the following code, but gcc rejects it.
void h() { }
constexpr int f() {
return 1;
h();
}
int main() {
constexpr int i = f();
}
Here is the error message:
g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'constexpr int f()':
main.cpp:5:6: error: call to non-'constexpr' function 'void h()'
h();
~^~
main.cpp: In function 'int main()':
main.cpp:9:24: error: 'constexpr int f()' called in a constant expression
constexpr int i = f();
~^~
main.cpp:9:19: warning: unused variable 'i' [-Wunused-variable]
constexpr int i = f();
This could well be the case where both compilers are correct, once we consider [dcl.constexpr]/5, given that f() is not a constant expression, as it doesn't satisfy [expr.const]/(4.2), as it calls a non-constexpr function h. That is, the code is ill-formed, but no diagnostic is required.
One other possibility is that the code is well formed, as [expr.const]/(4.2) doesn't apply in this case because the call to h in f is not evaluated. If this is the case, gcc is wrong and clang is correct.
Clang is correct. A call to f() is a constant expression since the call to h() is never evaluated, so [dcl.constexpr]/5 doesn't apply. The call to h() in the body of f() is not ill-formed because the constraints on constexpr functions don't say anything about not being allowed to call non-constexpr functions. Indeed, a function like the following is well-formed because a call to it can be a constant expression when x is odd:
constexpr int g(int x) {
if (x%2 == 0) h();
return 0;
}
Consider the following program:
struct S {
enum E {
e
};
template<E> void f() = delete;
};
template<> void S::f<S::E::e>() {}
int main() {
S s;
s.f<S::E::e>();
}
GCC 5.4.0 compiles the code, while clang 3.8.0 fails:
$ clang++ -std=c++14 main.cpp
main.cpp:10:20: error: redefinition of 'f'
template<> void S::f<S::E::e>() {
^
main.cpp:8:20: note: previous definition is here
template<> void S::f<S::E::e>();
^
main.cpp:14:11: error: no matching member function for call to 'f'
s.f<S::E::e>();
~~^~~~~~~~~~
main.cpp:5:22: note: candidate template ignored: substitution failure [with $0 = S::E::e]
template<E> void f() = delete;
^
2 errors generated.
Is clang correct and GCC wrong or is it the opposite? Note that if the delete specifier is removed, then clang compiles the code.
this seems defect report Explicit specialization of deleted function template , as you can see from here the issue seems fixed in clang since 3.9.0.
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?
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.
The code below compiles correctly on clang 3.8.1-1 on ArchLinux.
Is this clang bug?
gcc issue correct warning/error on this.
template <class T>
struct BugReproducer{
using size_type = typename T::size_type;
int bug1(size_type count);
int bug2(size_type count) const;
static int bug3(size_type count);
};
template <class T>
int BugReproducer<T>::bug1(size_type const count){
// this is a bug. must be not allowed
count = 5;
// return is to use the result...
return count;
}
template <class T>
int BugReproducer<T>::bug2(size_type const count) const{
// same for const method
count = 5;
return count;
}
template <class T>
int BugReproducer<T>::bug3(size_type const count){
// same for static method
count = 5;
return count;
}
struct DummyVector{
using size_type = int;
};
int main(){
using BugRepr = BugReproducer<DummyVector>;
BugRepr reproducer;
auto a = reproducer.bug1(1);
auto b = reproducer.bug2(1);
auto c = BugRepr::bug3(1);
// return is to use the result...
return a + b + c;
}
Here how I compile:
[nmmm#zenbook HM3]$ clang x.cc -std=c++11 -lstdc++ -Wall -Wpedantic -Wconversion
clang and c++14 - same result.
[nmmm#zenbook HM3]$ clang x.cc -std=c++14 -lstdc++ -Wall -Wpedantic -Wconversion
Here is gcc output:
[nmmm#zenbook HM3]$ gcc x.cc -std=c++11 -lstdc++ -Wall -Wpedantic -Wconversion
x.cc: In instantiation of ‘int BugReproducer<T>::bug1(BugReproducer<T>::size_type) [with T = DummyVector; BugReproducer<T>::size_type = int]’:
x.cc:46:28: required from here
x.cc:13:8: error: assignment of read-only parameter ‘count’
count = 5;
~~~~~~^~~
x.cc: In instantiation of ‘int BugReproducer<T>::bug2(BugReproducer<T>::size_type) const [with T = DummyVector; BugReproducer<T>::size_type = int]’:
x.cc:47:28: required from here
x.cc:22:8: error: assignment of read-only parameter ‘count’
count = 5;
~~~~~~^~~
x.cc: In instantiation of ‘static int BugReproducer<T>::bug3(BugReproducer<T>::size_type) [with T = DummyVector; BugReproducer<T>::size_type = int]’:
x.cc:48:20: required from here
x.cc:29:8: error: assignment of read-only parameter ‘count’
count = 5;
~~~~~~^~~
Yes, this is a bug in clang; filed at https://llvm.org/bugs/show_bug.cgi?id=30365.
The nature of the bug is that in a class template member function definition appearing outside ([class.mfct]/1) the class template, with the type of a parameter dependent on the class template parameters, clang uses the parameter type of the declaration rather than the parameter type of the definition where they differ in topmost cv-qualification. Simplified example:
template<class T> struct A { void f(typename T::U); };
template<class T> void A<T>::f(typename T::U const i) { i = 1; }
struct X { using U = int; };
int main() { A<X>{}.f(0); }
Per [dcl.fct]/5 the type of i within the definition of A<X>::f is int const (Use of 'const' for function parameters):
5 - [...] After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter
type are deleted when forming the function type. [...]
[ Note: This transformation does not affect the types of the parameters. [...] — end note ]
Why can I not get the template function to accept the lambda expression?
After searching high and low -- I seriously though that this would work, but this C++ code;
template <typename F> int proc(const F& lam)
{
return lam();
}
void caller()
{
int i = 42;
int j = proc( [&i]()->int{ return i/7; } );
}
An I get the following errors;
$ g++ x.cc
x.cc: In function ‘void caller()’:
x.cc:11:44: warning: lambda expressions only available with -std=c++0x or -std=gnu++0x [enabled by default]
x.cc:11:46: error: no matching function for call to ‘proc(caller()::<lambda()>)’
x.cc:11:46: note: candidate is:
x.cc:3:27: note: template<class F> int proc(const F&)
I'm on linux using g++ 4.6.3 and 4.7.2
Does anybody know what I have to do to pass on a lambda expression as a parameter to a receiving template function? -- I don't want to use the std::function -- so my only alternative is to create an ugly functor pattern.
Update: Tried to declare the argument const F& lam, but without success.
Update2: added call to compiler...
Since the lambda isn't an lvalue, you need to pass it by const reference:
template <typename F> int proc(const F& lam)
Make sure to use -std=c++11 with g++ 4.7.2 or -std=c++0x with g++ 4.6.3.