Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 253
Ed Lambert Avatar asked Apr 13 '15 23:04

Ed Lambert


People also ask

What version of C does Clang use?

Clang 14, the latest major version of Clang as of March 2022, has full support for all published C++ standards up to C++17, implements most features of C++20, and has initial support for the upcoming C++23 standard.

Which is faster GCC or Clang?

GCC does not have this. GCC's PCH mechanism (which is just a dump of the compiler memory image) is related, but is architecturally only able to read the dump back into the exact same executable as the one that produced it (it is not a structured format). Clang is much faster and uses far less memory than GCC.

Should I use GCC or Clang?

GCC supports more traditional languages than Clang and LLVM, such as Ada, Fortran, and Go. GCC supports more less-popular architectures, and supported RISC-V earlier than Clang and LLVM. GCC supports more language extensions and more assembly language features than Clang and LLVM.

Does Clang optimize better than GCC?

GCC consistently outperformance Clang on all optimization levels. 32 Bit Performance is on a bit lower side with respect to corresponding 64-bit compilers & optimization levels. This can be attributed to being able to utilize the RAM properly. The contrast between O0 & Other optimization levels is very visible.


1 Answers

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.

like image 106
Chandler Carruth Avatar answered Oct 06 '22 06:10

Chandler Carruth