Confusing clang error attempting to instantiate std::thread with a pointer - c++11

While looking at Thread and interfaces C++, I noticed something a little strange with my Clang.
I have c++ --version output of
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.3.0
Thread model: posix
Compiling the following
#include <thread>
class Foo {
public:
void operator()() { }
};
int main() {
Foo *foo = new Foo();
std::thread t(foo);
t.join();
delete foo;
}
with c++ thread.cpp yields the following sensible error:
In file included from thread.cpp:1:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:369:5: error: called object type 'Foo *' is not a function or
function pointer
(*__p)();
^~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:377:42: note: in instantiation of function template
specialization 'std::__1::__thread_proxy<Foo *>' requested here
int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Fp>, __p.get());
^
thread.cpp:10:17: note: in instantiation of function template specialization 'std::__1::thread::thread<Foo *>' requested here
std::thread t(foo);
^
1 error generated.
Total sense - Foo * isn't a function pointer.
But, compiling it with c++ -std=c++11 thread.cpp gives this cryptic error:
In file included from thread.cpp:1:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:332:5: error: attempt to use a deleted function
__invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:342:5: note: in instantiation of function template
specialization 'std::__1::__thread_execute<Foo *>' requested here
__thread_execute(*__p, _Index());
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:354:42: note: in instantiation of function template
specialization 'std::__1::__thread_proxy<std::__1::tuple<Foo *> >' requested here
int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Gp>, __p.get());
^
thread.cpp:10:17: note: in instantiation of function template specialization 'std::__1::thread::thread<Foo *&, void>' requested here
std::thread t(foo);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/type_traits:1027:5: note: '~__nat' has been explicitly marked
deleted here
~__nat() = delete;
^
1 error generated.
What's causing this weird error message about a deleted destructor? Should I consider it a bug in Clang to have such an odd message?

Your actual error message is the same in the two cases: whatever template is used to implement std::thread, it cannot be specialized for Foo*.
~__nat() = delete; is only a random difference between the old and new standard, one of the uninteresting things that fail because of the type error.

Related

No member named value in std::is_convertible when using clang

In a very simple situation with a constrained constructor, testing for convertibility of the argument, an error is produced in clang, but not in g++:
#include <type_traits>
template <class T, class U>
constexpr bool Convertible = std::is_convertible<T,U>::value && std::is_convertible<U,T>::value;
template <class T>
struct A
{
template <class S, class = std::enable_if_t<Convertible<S,T>> >
A(S const&) {}
};
int main()
{
A<double> s = 1.0;
}
Maybe this issue is related to Is clang's c++11 support reliable?
The error clang gives, reads:
error: no member named 'value' in 'std::is_convertible<double, A<double> >'
constexpr bool Convertible = std::is_convertible<T,U>::value && std::is_convertible<U,T>::value;
~~~~~~~~~~~~~~~~~~~~~~~~~~^
I've tried
g++-5.4, g++-6.2 (no error)
clang++-3.5, clang++-3.8, clang++-3.9 (error)
with argument -std=c++1y and for clang either with -stdlib=libstdc++ or -stdlib=libc++.
Which compiler is correct? Is it a bug in clang or gcc? Or is the behavior for some reasons undefined and thus both compilers correct?
First of all, note that it works fine if you use:
A<double> s{1.0};
Instead, the error comes from the fact that you are doing this:
A<double> s = 1.0;
Consider the line below (extracted from the definition of Convertible):
std::is_convertible<U,T>::value
In your case, this is seen as it follows (once substitution has been performed):
std::is_convertible<double, A<double>>::value
The compiler says this clearly in the error message.
This is because a temporary A<double> is constructed from 1.0, then it is assigned to s.
Note that in your class template you have defined a (more or less) catch-all constructor, so a const A<double> & is accepted as well.
Moreover, remember that a temporary binds to a const reference.
That said, the error happens because in the context of the std::enable_if_t we have that A<double> is an incomplete type and from the standard we have this for std::is_convertible:
From and To shall be complete types [...]
See here for the working draft.
Because of that, I would say that it's an undefined behavior.
As a suggestion, you don't need to use std::enable_if_t in this case.
You don't have a set of functions from which to pick the best one up in your example.
A static_assert is just fine and error messages are nicer:
template <class S>
A(S const&) { static_assert(Convertible<S,T>, "!"); }

GCC gives confusing warning message when using pointer to struct <typedef>

On compiling the following C program, GCC emits a warning message which is somewhat confusing.
Program Source
#include <stdio.h>
typedef struct {
int x;
} dummy_t;
void myfunc (dummy_t *pointer)
{
printf("x = %d\n", pointer->x);
}
int main ()
{
dummy_t d = { 10 };
/* INCORRECT. */
myfunc((struct dummy_t *)&d);
/* Correct. */
// myfunc((dummy_t *)&d);
return 0;
}
Compilation
bash$ gcc c.c
c.c: In function ‘main’:
c.c:17:20: warning: passing argument 1 of ‘myfunc’ from incompatible pointer type
myfunc((struct dummy_t *)&d);
^
c.c:7:6: note: expected ‘struct dummy_t *’ but argument is of type ‘struct dummy_t *’
void myfunc (dummy_t *pointer)
Notice how both the expected type and the argument type are reported to have the same value struct dummy_t *. This is confusing.
Shouldn't the expected type be dummy_t *?
The above program is a simplified version of the actual code where I faced this problem.
GCC Version
bash$ gcc --version
gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
You're right that the error message is confusing. A newer version gives a much better error message:
note: expected 'dummy_t * {aka struct <anonymous> *}' but argument is
of type 'struct dummy_t *'
As you can see, dummy_t and struct dummy_t are different types. With this declaration:
typedef struct {
int x;
} dummy_t;
You are typedef'ing an anonymous struct. However, later when you do struct dummy_t, you are forward declaring a new struct named dummy_t. Clearly, these are two different types, hence the error.

Is this change in overload resolution between Clang 3.5 and 3.6 correct or a bug?

The code below compiles in Visual Studio 2013, gcc 4.8, clang 3.4 and clang 3.5 (Apple LLVM 6.0) but does not compile in clang 3.6 (via Apple LLVM 6.1)
The code is a simplified version of a complicated class in our codebase which is the minimum required to exhibit the issue.
The crux of the problem is that the copy construction of TYPED_VALUE is, in 3.6, evaluating the templated conversion operator for type STRING because of the presence of a constructor that accepts a STRING; this causes std::is_constructible to be evaluated which leads to it needing the definition of STRING (which we cannot provide here - would lead to a circular dependency in the full code).
class STRING;
class TYPED_VALUE
{
public:
TYPED_VALUE( const TYPED_VALUE& ) = default; // explicit or implicit doesn't make a difference
TYPED_VALUE( const STRING & ) {}
template< typename TYPE, typename std::enable_if<!std::is_pointer< TYPE >::value && !std::is_constructible< TYPE, const STRING& >::value && !std::is_constructible< TYPE, bool >::value, int >::type = 0 >
operator TYPE( void ) const = delete;
};
class TYPED_STORAGE
{
public:
TYPED_STORAGE( const TYPED_VALUE &v ) : value( v ) {}
TYPED_VALUE value;
};
The error message is
/type_traits:2329:38: error: incomplete type 'SICORE::STRING' used in type trait expression
: public integral_constant<bool, __is_constructible(_Tp, _Args...)>
^
/main.cpp:348:99: note: in instantiation of template class 'std::__1::is_constructible<SICORE::STRING, const SICORE::STRING &>' requested here
template< typename TYPE, typename std::enable_if<!std::is_pointer< TYPE >::value && !std::is_constructible< TYPE, const STRING& >::value && !std::is_constructible< TYPE, bool >::value, int >::type = 0 >
^
/main.cpp:349:9: note: while substituting prior template arguments into non-type template parameter [with TYPE = SICORE::STRING]
operator TYPE( void ) const = delete;
^~~~~~~~~~~~~~~~~~~~~~~~~~~
/main.cpp:355:56: note: while substituting deduced template arguments into function template 'operator type-parameter-0-0' [with TYPE = SICORE::STRING, $1 = (no value)]
TYPED_STORAGE( const TYPED_VALUE &v ) : value( v ) {}
^
/main.cpp:340:11: note: forward declaration of 'SICORE::STRING'
class STRING;
^
To me this seems like a bug in 3.6, in previous versions the overload resolution determines that the copy constructor is the best fit without having to evaluate the template arguments - I tried to understand the overload resolution notes in the standard but I think that just confused me more ;)
(This can be fixed by making either the constructor or the conversion operator explicit I realise, but that is not the behaviour we want)
Any standard experts out there know the answer?
I believe Clang is correct to produce this error:
The [temp.inst] section of the C++ standard in paragraph 10 says:
If a function template or a member function template specialization is
used in a way that involves overload resolution, a declaration of the
specialization is implicitly instantiated (14.8.3).
Forming the implicit conversion sequence necessary to rank the overload candidates for the call to TYPE_VALUE's constructor requires the instantiation of the conversion operator. And the use of an incomplete type parameter to the trait doesn't form an invalid type, so this isn't a substitution failure, it is a hard error.
The copy constructor of TYPED_VALUE uses a reference to STRING, it should not be evaluated.
I think this is a clang error.
I haven't read the new c++ standard for a long time, however, I couldn't make sure it hadn't changed.
templates are instantiated as-needed, and I think Clang 3.6 implemented a DR where it needed to instantiate a template earlier than 3.5 did.

Queue not working for structs defined inside functions

I'm using gcc.
I want to create a queue of my own datatype.
In the following code, when I declare struct outside main(), it works fine but it gives compile-time errors when that struct is defined inside.
#include <queue>
using namespace std;
int main()
{
struct tempPos {int a; int b;}; //....(1)
queue<tempPos> b; //works only if tempPos is defined outside main
queue<int> x; //works fine anyways
return 0;
}
Following are the errors.
test.cpp: In function ‘int main()’:
test.cpp:10:15: error: template argument for ‘template<class _Tp> class std::allocator’ uses local type ‘main()::tempPos’
test.cpp:10:15: error: trying to instantiate ‘template<class _Tp> class std::allocator’
test.cpp:10:15: error: template argument 2 is invalid
test.cpp:10:18: error: invalid type in declaration before ‘;’ token
Compilation failed.
C++ forbids using locally-defined classes with templates because they have no linkage. The standard says:
14.3.1/2: .A local type, a type with no linkage, an unnamed type or a type compounded from any of these types shall not be used as a template-argument for a template type-parameter.

What are "lowered vtable references"?

Clang's own diagnostics propaganda contains this exerpt:
Since Clang has range highlighting, it never needs to pretty print your code back out to you. This is particularly bad in G++ (which often emits errors containing lowered vtable references), but even GCC can produce inscrutible error messages in some cases when it tries to do this.
Googling this phrase doesn't give anything very helpful, and the subsequent example is completely unrelated.
Can someone please post an example of what it's talking about?
Thanks.
Here is an example:
struct a {
virtual int bar();
};
struct foo : public virtual a {
};
void test(foo *P) {
return P->bar()+*P;
}
Clang produces:
t.cc:9:18: error: invalid operands to binary expression ('int' and 'foo')
return P->bar()+*P;
~~~~~~~~^~~
GCC 4.2 produces:
t.cc: In function ‘void test(foo*)’:
t.cc:9: error: no match for ‘operator+’ in ‘(((a*)P) + (*(long int*)(P->foo::<anonymous>.a::_vptr$a + -0x00000000000000020)))->a::bar() + * P’
t.cc:9: error: return-statement with a value, in function returning 'void'
GCC does this because its C++ frontend is bolted on top of the C frontend in many cases. Instead of building C++-specific Abstract Syntax Trees (ASTs) for various C++ operations, the parser just lowers them immediately to their C equivalent. In this case, GCC synthesizes an struct to contain the vtable, and the pointer dereference to bar is then lowered into a series of C pointer dereferences, casts, pointer arithmetic etc.
Clang does not have this problem, because it has a very clean AST that directly represents the source code. If you change the example to:
struct a {
virtual int bar();
};
struct foo : public virtual a {
};
void test(foo *P) {
P->bar();
}
.. so that the code is valid, then ask clang to dump its ast with "clang -cc1 -ast-dump t.cc", you get:
...
void test(foo *P)
(CompoundStmt 0x10683cae8 <t.cc:8:19, line:10:1>
(CXXMemberCallExpr 0x10683ca78 <line:9:3, col:10> 'int'
(MemberExpr 0x10683ca40 <col:3, col:6> '<bound member function type>' ->bar 0x10683bef0
(ImplicitCastExpr 0x10683cac8 <col:3> 'struct a *' <UncheckedDerivedToBase (virtual a)>
(ImplicitCastExpr 0x10683ca28 <col:3> 'struct foo *' <LValueToRValue>
(DeclRefExpr 0x10683ca00 <col:3> 'struct foo *' lvalue ParmVar 0x10683c8a0 'P' 'struct foo *'))))))
-Chris

Resources