mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 07:06:05 +00:00

render the function deleted instead of rendering the program ill-formed. This change also adds an enabled-by-default warning for the case where an explicitly-defaulted special member function of a non-template class is implicitly deleted by the type checking rules. (This fires either due to this language change or due to pre-C++20 reasons for the member being implicitly deleted). I've tested this on a large codebase and found only bugs (where the program means something that's clearly different from what the programmer intended), so this is enabled by default, but we should revisit this if there are problems with this being enabled by default. llvm-svn: 343285
188 lines
6.3 KiB
Plaintext
188 lines
6.3 KiB
Plaintext
// RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -verify %s -Wno-defaulted-function-deleted
|
|
|
|
#include "Inputs/cuda.h"
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Test 1: infer default ctor to be host.
|
|
|
|
struct A1_with_host_ctor {
|
|
A1_with_host_ctor() {}
|
|
};
|
|
|
|
// The implicit default constructor is inferred to be host because it only needs
|
|
// to invoke a single host constructor (A1_with_host_ctor's). 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 {
|
|
};
|
|
|
|
// expected-note@-3 {{call to __host__ function from __device__}}
|
|
// expected-note@-4 {{candidate constructor (the implicit copy constructor) not viable}}
|
|
// expected-note@-5 {{candidate constructor (the implicit move constructor) not viable}}
|
|
|
|
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 default ctor to be device.
|
|
|
|
struct A2_with_device_ctor {
|
|
__device__ A2_with_device_ctor() {}
|
|
};
|
|
|
|
struct B2_with_implicit_default_ctor : A2_with_device_ctor {
|
|
};
|
|
|
|
// expected-note@-3 {{call to __device__ function from __host__}}
|
|
// expected-note@-4 {{candidate constructor (the implicit copy constructor) not viable}}
|
|
// expected-note@-5 {{candidate constructor (the implicit move constructor) not viable}}
|
|
|
|
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 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 {
|
|
};
|
|
// expected-note@-2 2{{call to __device__ function from __host__ function}}
|
|
// expected-note@-3 {{default constructor}}
|
|
|
|
|
|
void hostfoo3() {
|
|
B3_with_implicit_ctors b; // this is OK because the inferred default ctor
|
|
// here is __host__
|
|
B3_with_implicit_ctors b2 = b; // expected-error {{no matching constructor}}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Test 4: infer default ctor from a field, not a base
|
|
|
|
struct A4_with_host_ctor {
|
|
A4_with_host_ctor() {}
|
|
};
|
|
|
|
struct B4_with_implicit_default_ctor {
|
|
A4_with_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() {
|
|
B4_with_implicit_default_ctor b;
|
|
}
|
|
|
|
__device__ void devicefoo4() {
|
|
B4_with_implicit_default_ctor b; // expected-error {{no matching constructor}}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Test 5: 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 {
|
|
};
|
|
|
|
// expected-note@-3 {{candidate constructor (the implicit copy constructor) not viable: call to __host__ function from __device__ function}}
|
|
// expected-note@-4 {{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: since they are spelled out, they have
|
|
// a host/device designation explicitly so no inference needs to be done.
|
|
|
|
struct A6_with_device_ctor {
|
|
__device__ A6_with_device_ctor() {}
|
|
};
|
|
|
|
struct B6_with_defaulted_ctor : A6_with_device_ctor {
|
|
__host__ B6_with_defaulted_ctor() = default;
|
|
};
|
|
|
|
// expected-note@-3 {{candidate constructor not viable: call to __host__ function from __device__ function}}
|
|
// expected-note@-5 {{candidate constructor (the implicit copy constructor) not viable}}
|
|
// expected-note@-6 {{candidate constructor (the implicit move constructor) not viable}}
|
|
|
|
__device__ void devicefoo6() {
|
|
B6_with_defaulted_ctor b; // expected-error {{no matching constructor}}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Test 7: 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 {
|
|
};
|
|
|
|
// expected-note@-3 {{candidate function (the implicit copy assignment operator) not viable: call to __device__ function from __host__ function}}
|
|
// expected-note@-4 {{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: 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 {
|
|
};
|
|
|
|
// expected-note@-3 {{candidate function (the implicit copy assignment operator) not viable: call to __device__ function from __host__ function}}
|
|
// expected-note@-4 {{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 '='}}
|
|
}
|