Skip to content

Commit 2b76e20

Browse files
authored
[CUDA][HIP] allow trivial ctor/dtor in device var init (#73140)
Treat ctor/dtor in device var init as host device function so that they can be used to initialize file-scope device variables to match nvcc behavior. If they are non-trivial they will be diagnosed. We cannot add implicit host device attrs to non-trivial ctor/dtor since determining whether they are non-trivial needs to know whether they have a trivial body and all their member and base classes' ctor/dtor have trivial body, which is affected by where their bodies are defined or instantiated. Fixes: #72261 Fixes: SWDEV-432412
1 parent a4d8549 commit 2b76e20

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

clang/lib/Sema/SemaCUDA.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,15 @@ Sema::CUDAFunctionPreference
225225
Sema::IdentifyCUDAPreference(const FunctionDecl *Caller,
226226
const FunctionDecl *Callee) {
227227
assert(Callee && "Callee must be valid.");
228+
229+
// Treat ctor/dtor as host device function in device var initializer to allow
230+
// trivial ctor/dtor without device attr to be used. Non-trivial ctor/dtor
231+
// will be diagnosed by checkAllowedCUDAInitializer.
232+
if (Caller == nullptr && CurCUDATargetCtx.Kind == CTCK_InitGlobalVar &&
233+
CurCUDATargetCtx.Target == CFT_Device &&
234+
(isa<CXXConstructorDecl>(Callee) || isa<CXXDestructorDecl>(Callee)))
235+
return CFP_HostDevice;
236+
228237
CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller);
229238
CUDAFunctionTarget CalleeTarget = IdentifyCUDATarget(Callee);
230239

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -verify %s
2+
// RUN: %clang_cc1 -isystem %S/Inputs -fcuda-is-device -fsyntax-only -verify %s
3+
4+
#include <cuda.h>
5+
6+
// Check trivial ctor/dtor
7+
struct A {
8+
int x;
9+
A() {}
10+
~A() {}
11+
};
12+
13+
__device__ A a;
14+
15+
// Check trivial ctor/dtor of template class
16+
template<typename T>
17+
struct TA {
18+
T x;
19+
TA() {}
20+
~TA() {}
21+
};
22+
23+
__device__ TA<int> ta;
24+
25+
// Check non-trivial ctor/dtor in parent template class
26+
template<typename T>
27+
struct TB {
28+
T x;
29+
TB() { static int nontrivial_ctor = 1; }
30+
~TB() {}
31+
};
32+
33+
template<typename T>
34+
struct TC : TB<T> {
35+
T x;
36+
TC() {}
37+
~TC() {}
38+
};
39+
40+
template class TC<int>;
41+
42+
__device__ TC<int> tc; //expected-error {{dynamic initialization is not supported for __device__, __constant__, __shared__, and __managed__ variables}}
43+
44+
// Check trivial ctor specialization
45+
template <typename T>
46+
struct C {
47+
explicit C() {};
48+
};
49+
50+
template <> C<int>::C() {};
51+
__device__ C<int> ci_d;
52+
C<int> ci_h;
53+
54+
// Check non-trivial ctor specialization
55+
template <> C<float>::C() { static int nontrivial_ctor = 1; }
56+
__device__ C<float> cf_d; //expected-error {{dynamic initialization is not supported for __device__, __constant__, __shared__, and __managed__ variables}}
57+
C<float> cf_h;

0 commit comments

Comments
 (0)