[cfe-dev] Clang and CUDA with C++11 features

Richard Smith richard at metafoo.co.uk
Mon Jun 18 16:44:05 PDT 2012


On Mon, Jun 18, 2012 at 3:46 PM, Peter Colberg <peter at colberg.org> wrote:
> On Sun, Jun 17, 2012 at 11:22:58PM -0700, Richard Smith wrote:
>> I've just improved the diagnostic for this in Clang ToT:
>>
>> test/Parser/cuda-kernel-call.cu:13:12: error: a space is required between
>>       consecutive right angle brackets (use '> >')
>>   S<S<S<int>>> s; // expected-error 2{{use '> >'}}
>>            ^~
>>            > >
>> test/Parser/cuda-kernel-call.cu:13:13: error: a space is required between
>>       consecutive right angle brackets (use '> >')
>>   S<S<S<int>>> s; // expected-error 2{{use '> >'}}
>>             ^~
>>             > >
>>
>> If we want to support CUDA + C++11, I think the right fix for this
>> issue is to extend C++11's rule for '>>'-fission to CUDA's '>>>'
>> token:
>>
>> Index: lib/Parse/ParseTemplate.cpp
>> ===================================================================
>> --- lib/Parse/ParseTemplate.cpp (revision 158652)
>> +++ lib/Parse/ParseTemplate.cpp (working copy)
>> @@ -785,7 +785,8 @@
>>      Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " ");
>>
>>    unsigned DiagId = diag::err_two_right_angle_brackets_need_space;
>> -  if (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater))
>> +  if (getLangOpts().CPlusPlus0x &&
>> +      (Tok.is(tok::greatergreater) || Tok.is(tok::greatergreatergreater)))
>>      DiagId = diag::warn_cxx98_compat_two_right_angle_brackets;
>>    else if (Tok.is(tok::greaterequal))
>>      DiagId = diag::err_right_angle_bracket_equal_needs_space;
>>
>> This will allow us to correctly deal with '>>' in almost all cases in
>> CUDA mode, and the exceptions are truly bizarre and implausible
>> constructs like "(SomeType)&FnTmpl<ClassTmpl<T>>>>3;" -- here the
>> '>>>>' splits into '> > >>' in C++11 and would split into '> > > >' in
>> CUDA/C++11 with the proposed rule.
>
> With the above patch, C++11 template parameters and CUDA syntax coexist nicely:
>
>    #include <cuda_runtime.h>
>
>    template <typename T>
>    struct S;
>
>    template <typename T>
>    __attribute__((global)) void f() {}
>
>    int main()
>    {
>        f<S<S<int>>><<<1, 1>>>();
>    }
>
> When including <iostream>, there is still a minor problem:
>
>    // template.cu
>
>    #include <cuda_runtime.h>
>    #include <iostream>
>
>    int main() {}
>
>
>    clang++ -Wall -I/usr/local/cuda-4.2/cuda/include -L/usr/local/cuda-4.2/cuda/lib64 -lcudart -o template template.cu
[...]
>    In file included from template.cu:2:
>    In file included from /home/peter/usr/rhel6-x86_64/gcc-4.7.1/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/iostream:39:
>    In file included from /home/peter/usr/rhel6-x86_64/gcc-4.7.1/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/ostream:39:
>    In file included from /home/peter/usr/rhel6-x86_64/gcc-4.7.1/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/ios:42:
>    In file included from /home/peter/usr/rhel6-x86_64/gcc-4.7.1/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/ios_base.h:42:
>    In file included from /home/peter/usr/rhel6-x86_64/gcc-4.7.1/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/locale_classes.h:41:
>    In file included from /home/peter/usr/rhel6-x86_64/gcc-4.7.1/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/string:53:
>    /home/peter/usr/rhel6-x86_64/gcc-4.7.1/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/basic_string.h:504:9: error: call to
>          implicitly-deleted copy constructor of 'std::basic_string<char, std::char_traits<char>, std::allocator<char>>::_Alloc_hider'
>          : _M_dataplus(__str._M_dataplus)
>            ^           ~~~~~~~~~~~~~~~~~
>    /home/peter/usr/rhel6-x86_64/gcc-4.7.1/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/basic_string.h:2863:12: note: in
>          instantiation of member function 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string' requested here
>      { return __gnu_cxx::__to_xstring<string>(&std::vsnprintf, 4 * sizeof(int),
>               ^
>    /home/peter/usr/rhel6-x86_64/gcc-4.7.1/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/basic_string.h:268:29: note: copy
>          constructor of '_Alloc_hider' is implicitly deleted because base class 'std::allocator<char>' has no copy constructor
>          struct _Alloc_hider : _Alloc
>                                ^

This "has no copy constructor" condition should not be possible. Looks
like the problem is here (end of Sema/SemaDeclCXX.cpp):

Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) {
  // Implicitly declared functions (e.g. copy constructors) are
  // __host__ __device__
  if (D->isImplicit())
    return CFT_HostDevice;

bool Sema::CheckCUDATarget(CUDAFunctionTarget CallerTarget,
                           CUDAFunctionTarget CalleeTarget) {
  if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice)
    return true;

So... an implicit copy constructor is __host__ __device__, and thus
can't call an explicitly-declared copy constructor (which is just
__host__). Oops. Is this a bug in the CUDA spec or in Clang?




More information about the cfe-dev mailing list