Skip to content

Commit d37a392

Browse files
authored
[CUDA][HIP] fix virtual dtor host/device attr (llvm#128926)
Currently if CUDA/HIP users use template class with virtual dtor and std::string data member with C++20 and MSVC. When the template class is explicitly instantiated, there is error about host function called by host device function (used to be undefined symbols in linking stage before member destructors were checked by deferred diagnostics). It was caused by clang inferring host/device attributes for default dtors. Since all dtors of member and parent classes have implicit host device attrs, clang infers the virtual dtor have implicit host and device attrs. Since virtual dtor of explicitly instantiated template class must be emitted, this causes constexpr dtor of std::string emitted, which calls a host function which was not emitted on device side. This is a serious issue since it prevents users from using std::string with C++20 on Windows. When inferring host device attr of virtual dtor of explicit template class instantiation, clang should be conservative since it is sure to be emitted. Since an implicit host device function may call a host function, clang cannot assume it is always available on device. This guarantees dtors that may call host functions not to have implicit device attr, therefore will not be emitted on device side. Fixes: llvm#108548 Fixes: SWDEV-517435
1 parent cb94030 commit d37a392

File tree

3 files changed

+36
-10
lines changed

3 files changed

+36
-10
lines changed

clang/docs/HIPSupport.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,26 @@ Example Usage
286286
basePtr->virtualFunction(); // Allowed since obj is constructed in device code
287287
}
288288

289+
Host and Device Attributes of Default Destructors
290+
===================================================
291+
292+
If a default destructor does not have explicit host or device attributes,
293+
clang infers these attributes based on the destructors of its data members
294+
and base classes. If any conflicts are detected among these destructors,
295+
clang diagnoses the issue. Otherwise, clang adds an implicit host or device
296+
attribute according to whether the data members's and base classes's
297+
destructors can execute on the host or device side.
298+
299+
For explicit template classes with virtual destructors, which must be emitted,
300+
the inference adopts a conservative approach. In this case, implicit host or
301+
device attributes from member and base class destructors are ignored. This
302+
precaution is necessary because, although a constexpr destructor carries
303+
implicit host or device attributes, a constexpr function may call a
304+
non-constexpr function, which is by default a host function.
305+
306+
Users can override the inferred host and device attributes of default
307+
destructors by adding explicit host and device attributes to them.
308+
289309
C++ Standard Parallelism Offload Support: Compiler And Runtime
290310
==============================================================
291311

clang/lib/Sema/SemaCUDA.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,9 @@ bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
437437
if (!SMOR.getMethod())
438438
continue;
439439

440-
CUDAFunctionTarget BaseMethodTarget = IdentifyTarget(SMOR.getMethod());
440+
CUDAFunctionTarget BaseMethodTarget =
441+
IdentifyTarget(SMOR.getMethod(), IsExpVDtor);
442+
441443
if (!InferredTarget) {
442444
InferredTarget = BaseMethodTarget;
443445
} else {
@@ -481,7 +483,9 @@ bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
481483
if (!SMOR.getMethod())
482484
continue;
483485

484-
CUDAFunctionTarget FieldMethodTarget = IdentifyTarget(SMOR.getMethod());
486+
CUDAFunctionTarget FieldMethodTarget =
487+
IdentifyTarget(SMOR.getMethod(), IsExpVDtor);
488+
485489
if (!InferredTarget) {
486490
InferredTarget = FieldMethodTarget;
487491
} else {

clang/test/SemaCUDA/dtor.cu

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,24 @@ public:
3232
template class B<float>;
3333
}
3434

35-
// The implicit host/device attrs of virtual dtor B<float>::~B() is inferred to
36-
// have implicit device attr since dtors of its members and parent classes can
37-
// be executed on device. This causes a diagnostic since B<float>::~B() must
38-
// be emitted, and it eventually causes host_fun() called on device side.
35+
// The implicit host/device attrs of virtual dtor ~B() should be
36+
// conservatively inferred, where constexpr member dtor's should
37+
// not be considered device since they may call host functions.
38+
// Therefore B<float>::~B() should not have implicit device attr.
39+
// However C<float>::~C() should have implicit device attr since
40+
// it is trivial.
3941
namespace ExplicitInstantiationDtorNoAttr {
40-
void host_fun() // dev-note {{'host_fun' declared here}}
42+
void host_fun()
4143
{}
4244

4345
template <unsigned>
4446
constexpr void hd_fun() {
45-
host_fun(); // dev-error{{reference to __host__ function 'host_fun' in __host__ __device__ function}}
47+
host_fun();
4648
}
4749

4850
struct A {
49-
constexpr ~A() { // dev-note {{called by '~B'}}
50-
hd_fun<8>(); // dev-note {{called by '~A'}}
51+
constexpr ~A() {
52+
hd_fun<8>();
5153
}
5254
};
5355

0 commit comments

Comments
 (0)