implicit-member-target-inherited.cu 7.22 KB
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -Wno-defaulted-function-deleted

#include "Inputs/cuda.h"

//------------------------------------------------------------------------------
// Test 1: infer inherited default ctor to be host.

struct A1_with_host_ctor {
  A1_with_host_ctor() {}
};
// expected-note@-3 {{candidate constructor (the implicit copy constructor) not viable}}
// expected-note@-4 {{candidate constructor (the implicit move constructor) not viable}}

// The inherited default constructor is inferred to be host, so we'll encounter
// an error when calling it from a __device__ function, but not from a __host__
// function.
struct B1_with_implicit_default_ctor : A1_with_host_ctor {
  using A1_with_host_ctor::A1_with_host_ctor;
};

// expected-note@-4 {{call to __host__ function from __device__}}
// expected-note@-5 {{candidate constructor (the implicit copy constructor) not viable}}
// expected-note@-6 {{candidate constructor (the implicit move constructor) not viable}}
// expected-note@-6 2{{constructor from base class 'A1_with_host_ctor' inherited here}}

void hostfoo() {
  B1_with_implicit_default_ctor b;
}

__device__ void devicefoo() {
  B1_with_implicit_default_ctor b; // expected-error {{no matching constructor}}
}

//------------------------------------------------------------------------------
// Test 2: infer inherited default ctor to be device.

struct A2_with_device_ctor {
  __device__ A2_with_device_ctor() {}
};
// expected-note@-3 {{candidate constructor (the implicit copy constructor) not viable}}
// expected-note@-4 {{candidate constructor (the implicit move constructor) not viable}}

struct B2_with_implicit_default_ctor : A2_with_device_ctor {
  using A2_with_device_ctor::A2_with_device_ctor;
};

// expected-note@-4 {{call to __device__ function from __host__}}
// expected-note@-5 {{candidate constructor (the implicit copy constructor) not viable}}
// expected-note@-6 {{candidate constructor (the implicit move constructor) not viable}}
// expected-note@-6 2{{constructor from base class 'A2_with_device_ctor' inherited here}}

void hostfoo2() {
  B2_with_implicit_default_ctor b;  // expected-error {{no matching constructor}}
}

__device__ void devicefoo2() {
  B2_with_implicit_default_ctor b;
}

//------------------------------------------------------------------------------
// Test 3: infer inherited copy ctor

struct A3_with_device_ctors {
  __host__ A3_with_device_ctors() {}
  __device__ A3_with_device_ctors(const A3_with_device_ctors&) {}
};

struct B3_with_implicit_ctors : A3_with_device_ctors {
  using A3_with_device_ctors::A3_with_device_ctors;
};
// expected-note@-3 2{{call to __device__ function from __host__ function}}
// expected-note@-4 {{default constructor}}


void hostfoo3() {
  B3_with_implicit_ctors b;  // this is OK because the inferred inherited default ctor
                             // here is __host__
  B3_with_implicit_ctors b2 = b; // expected-error {{no matching constructor}}

}

//------------------------------------------------------------------------------
// Test 4: infer inherited default ctor from a field, not a base

struct A4_with_host_ctor {
  A4_with_host_ctor() {}
};

struct B4_with_inherited_host_ctor : A4_with_host_ctor{
  using A4_with_host_ctor::A4_with_host_ctor;
};

struct C4_with_implicit_default_ctor {
  B4_with_inherited_host_ctor field;
};

// expected-note@-4 {{call to __host__ function from __device__}}
// expected-note@-5 {{candidate constructor (the implicit copy constructor) not viable}}
// expected-note@-6 {{candidate constructor (the implicit move constructor) not viable}}

void hostfoo4() {
  C4_with_implicit_default_ctor b;
}

__device__ void devicefoo4() {
  C4_with_implicit_default_ctor b; // expected-error {{no matching constructor}}
}

//------------------------------------------------------------------------------
// Test 5: inherited copy ctor with non-const param

struct A5_copy_ctor_constness {
  __host__ A5_copy_ctor_constness() {}
  __host__ A5_copy_ctor_constness(A5_copy_ctor_constness&) {}
};

struct B5_copy_ctor_constness : A5_copy_ctor_constness {
  using A5_copy_ctor_constness::A5_copy_ctor_constness;
};

// expected-note@-4 {{candidate constructor (the implicit copy constructor) not viable: call to __host__ function from __device__ function}}
// expected-note@-5 {{candidate constructor (the implicit default constructor) not viable}}

void hostfoo5(B5_copy_ctor_constness& b_arg) {
  B5_copy_ctor_constness b = b_arg;
}

__device__ void devicefoo5(B5_copy_ctor_constness& b_arg) {
  B5_copy_ctor_constness b = b_arg; // expected-error {{no matching constructor}}
}

//------------------------------------------------------------------------------
// Test 6: explicitly defaulted ctor

struct A6_with_device_ctor {
  __device__ A6_with_device_ctor() {}
};

struct B6_with_defaulted_ctor : A6_with_device_ctor {
  using A6_with_device_ctor::A6_with_device_ctor;
  __host__ B6_with_defaulted_ctor() = default;
};

// expected-note@-3 {{explicitly defaulted function was implicitly deleted here}}
// expected-note@-6 {{default constructor of 'B6_with_defaulted_ctor' is implicitly deleted because base class 'A6_with_device_ctor' has no default constructor}}

void hostfoo6() {
  B6_with_defaulted_ctor b; // expected-error {{call to implicitly-deleted default constructor}}
}

__device__ void devicefoo6() {
  B6_with_defaulted_ctor b;
}

//------------------------------------------------------------------------------
// Test 7: inherited copy assignment operator

struct A7_with_copy_assign {
  A7_with_copy_assign() {}
  __device__ A7_with_copy_assign& operator=(const A7_with_copy_assign&) {}
};

struct B7_with_copy_assign : A7_with_copy_assign {
  using A7_with_copy_assign::A7_with_copy_assign;
};

// expected-note@-4 {{candidate function (the implicit copy assignment operator) not viable: call to __device__ function from __host__ function}}
// expected-note@-5 {{candidate function (the implicit move assignment operator) not viable: call to __device__ function from __host__ function}}

void hostfoo7() {
  B7_with_copy_assign b1, b2;
  b1 = b2; // expected-error {{no viable overloaded '='}}
}

//------------------------------------------------------------------------------
// Test 8: inherited move assignment operator

// definitions for std::move
namespace std {
inline namespace foo {
template <class T> struct remove_reference { typedef T type; };
template <class T> struct remove_reference<T&> { typedef T type; };
template <class T> struct remove_reference<T&&> { typedef T type; };

template <class T> typename remove_reference<T>::type&& move(T&& t);
}
}

struct A8_with_move_assign {
  A8_with_move_assign() {}
  __device__ A8_with_move_assign& operator=(A8_with_move_assign&&) {}
  __device__ A8_with_move_assign& operator=(const A8_with_move_assign&) {}
};

struct B8_with_move_assign : A8_with_move_assign {
  using A8_with_move_assign::A8_with_move_assign;
};

// expected-note@-4 {{candidate function (the implicit copy assignment operator) not viable: call to __device__ function from __host__ function}}
// expected-note@-5 {{candidate function (the implicit move assignment operator) not viable: call to __device__ function from __host__ function}}

void hostfoo8() {
  B8_with_move_assign b1, b2;
  b1 = std::move(b2); // expected-error {{no viable overloaded '='}}
}