I've found a strange behavior using polymorphic C++14 lambdas (lambdas with auto in their parameters):
Snippet 0:
#include <iostream>
template<typename T> void doLambda(T&& mFn)
{
std::forward<T>(mFn)(int{0});
}
template<typename T> void test(T&& mV)
{
doLambda([&mV](auto mE)
{
std::forward<decltype(mV)>(mV);
});
}
int main() { test(int{0}); return 0; }
clang++ 3.5.1: the snippet compiles and runs successfully.
g++ 4.9.2: the snippet fails to compile:
example.cpp: In instantiation of 'test(T&&)::<lambda(auto:1)> [with auto:1 = int; T = int]':
5 : required from 'void doLambda(T&&) [with T = test(T&&) [with T = int]::]'
13 : required from 'void test(T&&) [with T = int]'
18 : required from here
12 : error: 'mV' was not declared in this scope
std::forward<decltype(mV)>(mV);
^
Compilation failed
Snippet 1:
The only difference from snippet 0 is that the auto inside the lambda was replaced to int.
#include <iostream>
template<typename T> void doLambda(T&& mFn)
{
std::forward<T>(mFn)(int{0});
}
template<typename T> void test(T&& mV)
{
doLambda([&mV](int mE)
{
std::forward<decltype(mV)>(mV);
});
}
int main() { test(int{0}); return 0; }
clang++ 3.5.1: the snippet compiles and runs successfully.
g++ 4.9.2: the snippet compiles and runs successfully.
Snippet 3:
The lambda is now called in-place. auto is still used.
#include <iostream>
template<typename T> void test(T&& mV)
{
[&mV](auto mE)
{
std::forward<decltype(mV)>(mV);
}(int{0});
}
int main() { test(int{0}); return 0; }
clang++ 3.5.1: the snippet compiles and runs successfully.
g++ 4.9.2: the snippet compiles and runs successfully.
Why is g++ complaining about snippet 0? Is there anything wrong in my code? Is this a known bug or should I submit this?
As stated in the comments, this behavior is indeed a gcc bug.
Related
I had written some c++ code in Visual Studio and was trying to run it on my c++ code on a linux server. When I tried to compile it with G++ however, it failed to compile with tons of errors. I looked through the error and was able to simplify the problem to this:
template<int x>
struct Struct
{
template<int y>
static void F()
{
//Struct<x>::F<0>(); // compiles
//Struct<y>::G(); // compiles
Struct<y>::F<0>(); // does not compile?
}
static void G()
{
}
};
int main ()
{
Struct<0>::F<0>();
}
On Visual Studio this code compiles just fine but on G++ or Clang++, it fails to compile. Errors on G++ 8.3.0:
test.cpp: In static member function ‘static void Struct<x>::F()’:
test.cpp:9:19: error: expected primary-expression before ‘)’ token
Struct<y>::F<0>(); // does not compile?
^
test.cpp: In instantiation of ‘static void Struct<x>::F() [with int y = 0; int x = 0]’:
test.cpp:19:18: required from here
test.cpp:9:15: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
Struct<y>::F<0>(); // does not compile?
Errors on Clang++:
5691311/source.cpp:9:19: error: expected expression
Struct<y>::F<0>(); // does not compile?
^
See it live: https://rextester.com/AAL19278
You can change the compiler and copy the code to see the different errors.
Is there anyway I could get around this problem so that my code will compile on G++ or Clang++?
Original Code:
template<int x, int y>
ThisType add()
{
return ThisType::Create(this->x() + x, this->y() + y);
}
ResultPos to = p.add<0, 1>();
template<int x>
struct Struct
{
template<int y>
static void F()
{
Struct<y>::F<0>(); // does not compile?
}
};
should not compile. You need to specify for the compiler that F in fact requires a template list, since F is a dependent template type. Otherwise the compiler will assume that the next < is a smaller than.
template<int x>
struct Struct
{
template<int y>
static void F()
{
Struct<y>::template F<0>();
}
};
I assume Struct<x>::F<0> works, since the compiler already knows that the current type is Struct<x>, but it cannot know that y is the same as xin this case.
I've spent quite a few hours today trying to understand why this code segfaults on g++6.2 and g++7.0, while happily working as intended on clang++3.9 (and 4.0).
I reduced the issue to a 85 lines self-contained code snippet, which does not segfault upon normal execution, but always reports an error under UBSAN.
The issue is reproducible on wandbox, by compiling with g++7, enabling optimizations and passing -fsanitize=undefined as an extra flag.
This is what UBSAN reports:
prog.cc: In function 'int main()':
prog.cc:61:49: warning: 'ns#0' is used uninitialized in this function [-Wuninitialized]
([&] { ([&] { n.execute(ns...); })(); })();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
prog.cc:28:10: note: 'ns#0' was declared here
auto execute(TNode& n, TNodes&... ns)
^~~~~~~
prog.cc:30:9: runtime error: member call on null pointer of type 'struct node_then'
g++ claims that ns#0 is uninitialized inside the "lambda gibberish" (which simulates the for_tuple from the original snippet). Now, some very interesting things occur:
If I remove the "lambda gibberish", transforming line 61 into
n.execute(ns...);
then UBSAN stops complaining.
If I change the capture list from [&] to [&n, &ns...], UBSAN stops complaining as well:
([&](auto) { ([&n, &ns...] { n.execute(ns...); })(); })(0);
...wait what? How is that different from [&]?
Applying the above discoveries to the original code snippet fixes the segfaults.
Is this a g++ bug? Or is there any undefined behavior in my code?
This has nothing to do with temporaries: it's a gcc7.0 optimizer bug. This is a simpler reproducer:
#include <utility>
struct root
{
template <typename TNode, typename... TNodes>
void start(TNode n, TNodes... ns)
{
n->execute(ns...);
}
};
template <typename TParent>
struct node_then
{
TParent *_p;
node_then(TParent *p) : _p{ p }
{
}
auto execute()
{
}
template <typename TNode, typename... TNodes>
auto execute(TNode n, TNodes... ns)
{
n->execute(ns...);
}
template <typename... TNodes>
auto start(TNodes... ns)
{
_p->start(this, ns...);
}
};
template <typename TParent>
struct node_wait_all
{
TParent *_p;
node_wait_all(TParent *p) : _p{ p }
{
}
template <typename TNode, typename... TNodes>
auto execute(TNode n, TNodes... ns)
{
([&] { ([&] { n->execute(ns...); })(); })();
}
template <typename... TNodes>
auto start(TNodes... ns)
{
_p->start(this, ns...);
}
};
int main()
{
//node_wait_all<root> obj(new root());
//node_then<node_wait_all<root>> obj2(new node_wait_all<root>(new root()));
node_then<node_then<node_wait_all<root>>> obj3(new node_then<node_wait_all<root>>(new node_wait_all<root>(new root())));
obj3.start();
}
Output:
prog.cc: In function 'int main()':
prog.cc:67:1: internal compiler error: in visit_ref_for_mod_analysis, at ipa-prop.c:2308
}
^
0x96c4d6 visit_ref_for_mod_analysis
/home/heads/gcc/gcc-source/gcc/ipa-prop.c:2308
0x8f615d walk_stmt_load_store_addr_ops(gimple*, void*, bool (*)(gimple*, tree_node*, tree_node*, void*), bool (*)(gimple*, tree_node*, tree_node*, void*), bool (*)(gimple*, tree_node*, tree_node*, void*))
/home/heads/gcc/gcc-source/gcc/gimple-walk.c:817
0x9761a2 ipa_analyze_params_uses_in_bb
/home/heads/gcc/gcc-source/gcc/ipa-prop.c:2335
0x9761a2 analysis_dom_walker::before_dom_children(basic_block_def*)
/home/heads/gcc/gcc-source/gcc/ipa-prop.c:2415
0x10c8472 dom_walker::walk(basic_block_def*)
/home/heads/gcc/gcc-source/gcc/domwalk.c:265
0x977ceb ipa_analyze_node(cgraph_node*)
/home/heads/gcc/gcc-source/gcc/ipa-prop.c:2486
0x1108f0a ipcp_generate_summary
/home/heads/gcc/gcc-source/gcc/ipa-cp.c:5036
0xa4759c execute_ipa_summary_passes(ipa_opt_pass_d*)
/home/heads/gcc/gcc-source/gcc/passes.c:2167
0x7d6b45 ipa_passes
/home/heads/gcc/gcc-source/gcc/cgraphunit.c:2311
0x7d6b45 symbol_table::compile()
/home/heads/gcc/gcc-source/gcc/cgraphunit.c:2425
0x7d8616 symbol_table::compile()
/home/heads/gcc/gcc-source/gcc/cgraphunit.c:2587
0x7d8616 symbol_table::finalize_compilation_unit()
/home/heads/gcc/gcc-source/gcc/cgraphunit.c:2584
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.
Link: http://melpon.org/wandbox/permlink/E11fOumFJda6OW6m
To aid in this code's comprehension I'm using a powerful debugging tool: paint.exe
Here's a sample program:
#include <type_traits>
#include <stdio.h>
template <typename X>
struct test
{
operator int() const { puts("?"); return 0; }
template <typename T, typename = typename std::enable_if<std::is_same<X, void*>::value, T>::type>
operator T() const { puts("T"); return 0; }
};
int main()
{
test<void*> t;
char* c = (char*)t;
switch (t)
{
case 0: break;
}
return 0;
}
And this is the error that g++-4.7 gives
user#user:~$ g++-4.7 -std=c++0x test.cpp
test.cpp: In function ‘int main()’:
test.cpp:13:14: error: ambiguous default typeconversion from ‘test<void*>’
test.cpp:13:14: error: candidate conversions include ‘template<class T, class> test::operator void*() const [with T = T; <template-parameter-2-2> = <template-parameter-1-2>; X = void*]’
g++ 4.6 compiles it without errors and different operators are actually called.
Is there a way to make this work under g++ 4.7?
UPDATE: actually it works in 4.6 without any enable_if at all... so the question still applies but I'm now not sure if enable_if will help.
If you add an explicit cast to int here:
switch ((int)t)
Then it should compile.
I think it's complaining about the conversion being ambiguous since there exists more than one type that can hold a 0 value.
I'm using g++ 4.8 though.
I found at least one "acceptable" solution:
#define switch(x) \
switch( (typename switch_type<__typeof(x)>::type)(x) )
which switch_type trait can be extended to resolve ambiguity for specific app-related types (property types).
I encountered a problem when using constexpr functions together with lambdas.
The following code is a minimal version which reproduces the error:
#include <iostream>
constexpr unsigned bar(unsigned q) {
return q;
}
template<unsigned N>
unsigned foo() {
return N;
}
template<typename F>
void print(F f) {
std::cout << f() << std::endl;
}
template<unsigned Q>
int stuff() {
constexpr unsigned n = bar(Q);
print([]() { return foo<n>(); });
}
int main() {
stuff<13>();
}
When compiling with gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) there are the following compiler errors:
constexpr_template.cpp: In lambda function:
constexpr_template.cpp:24:9: instantiated from ‘stuff() [with unsigned int Q = 13u]::<lambda()>’
constexpr_template.cpp:24:2: instantiated from ‘int stuff() [with unsigned int Q = 13u]’
constexpr_template.cpp:29:12: instantiated from here
constexpr_template.cpp:24:32: error: no matching function for call to ‘foo()’
constexpr_template.cpp:24:32: note: candidate is:
constexpr_template.cpp:9:10: note: template<unsigned int N> unsigned int foo()
Now the strange part is, if constexpr unsigned n = bar(Q); is changed into constexpr unsigned n = Q; it works.
What is also working is print([]() { return foo<bar(Q)>(); });...
Is this a bug in GCC or what am I doing wrong?
Gcc 4.6 was the first version to support constexpr, and it is not unusual for minor bugs to be present upon release of such features. You can verify from this Live Example on Coliru that gcc 4.8.1 and Clang 3.4 SVN correctly parse your code. You probably should upgrade your compiler accordingly.
I like to use local classes in template classes to perform constructions like "static if". But I've faced with the problem that gcc 4.8 does not want to compile my code. However 4.7 does.
This sample:
#include <type_traits>
#include <iostream>
#include <string>
using namespace std;
struct A {
void printA() {
cout << "I am A" << endl;
}
};
struct B {
void printB() {
cout << "I am B" << endl;
}
};
template <typename T>
struct Test {
void print() {
struct IfA {
constexpr IfA(T &value) : value(value) {
}
T &value;
void print() {
value.printA();
}
};
struct IfB {
constexpr IfB(T &value) : value(value) {
}
T &value;
void print() {
value.printB();
}
};
struct Else {
constexpr Else(...) {}
void print() {
}
};
typename conditional<is_same<T, A>::value, IfA, Else>::type(value).print();
typename conditional<is_same<T, B>::value, IfB, Else>::type(value).print();
}
T value;
};
int main() {
Test<A>().print();
Test<B>().print();
}
Options:
g++ --std=c++11 main.cc -o local-sfinae
Task:
Given classes A and B with different interfaces for printing.
Write a generic class Test that can print both A and B.
Do not pollute either any namespace or class scope.
Description of the code:
This is only a clean example.
I use an approach like this, because I want to generalize the construction "static if". See, that I pass the arguments to IfA and IfB classes via their fields, not directly to the print() function.
I use such constructions a lot.
I've found that these constructions should not be in (pollute) class scope. I mean they should be placed in a method scope.
So the question.
This code can not be compiled with GCC 4.8. Because it checks ALL classes, even if they are never used. But it has not instantiate them in binary (I've commented the lines that cause errors and compiled it with gcc 4.8). Proof:
$ nm local-sfinae |c++filt |grep "::If.*print"
0000000000400724 W Test<A>::print()::IfA::print()
00000000004007fe W Test<B>::print()::IfB::print()
See, there is no Test::print()::IfB::print(). (See later: 'void Test::print()::IfB::print() [with T = A]')
The errors if I compile aforementioned code with gcc 4.8:
g++ --std=c++11 main.cc -o local-sfinae
main.cc: In instantiation of 'void Test<T>::print()::IfB::print() [with T = A]':
main.cc:36:9: required from 'void Test<T>::print() [with T = A]'
main.cc:49:21: required from here
main.cc:34:17: error: 'struct A' has no member named 'printB'
value.printB();
^
main.cc: In instantiation of 'void Test<T>::print()::IfA::print() [with T = B]':
main.cc:28:9: required from 'void Test<T>::print() [with T = B]'
main.cc:50:21: required from here
main.cc:26:17: error: 'struct B' has no member named 'printA'
value.printA();
^
Is it a GCC 4.8 bug?
Or is it GCC 4.7 bug? Maybe the code should not be compiled.
Or it is a my bug, and I should not rely on the compiler behavior/should not use such approach to implement "static if".
Additional info:
This simple code compiles on 4.7, but not on 4.8. I shortened it.
struct A {
void exist() {
}
};
template <typename T>
struct Test {
void print() {
struct LocalClass {
constexpr LocalClass(T &value) : value(value) {
}
T &value;
void print() {
value.notExist();
}
};
}
T value;
};
int main() {
Test<A>().print();
}
Errors:
main.cc: In instantiation of 'void Test<T>::print()::LocalClass::print() [with T = A]':
main.cc:16:9: required from 'void Test<T>::print() [with T = A]'
main.cc:22:21: required from here
main.cc:14:17: error: 'struct A' has no member named 'notExist'
value.notExist();
^
Have tested two GCC 4.8 versions: 2012.10 and 2013.02. Hope it is GCC 4.8 bug and it can be fixed.
LocalClass is not a template. The "not instantiated if not used" rule is only applicable to member functions of class templates.
That is, when Test::print() is instantiated, everything that is inside is brought to life, including the unused member of its local class.
There is no SFINAE in your code.
SFINAE applies during template argument deduction and argument substitution (the 'S' in SFINAE stands for substitution) but the only substitution in your program happens when substituting A for T in the template parameter list of Test, which doesn't fail.
You then call print() which instantiates Test<A>::print(), which doesn't involve any substitution, and you get an error because value.notExist(); is not valid.
SFINAE has to be used in substitution contexts, such as template argument deduction caused by a function call or when deducing template parameters with default arguments.