Author: Joseph Huber
Date: 2026-03-06T09:49:15-06:00
New Revision: 9e15c6cc3358287e93a25d869a31ab14c1791dcb

URL: 
https://github.com/llvm/llvm-project/commit/9e15c6cc3358287e93a25d869a31ab14c1791dcb
DIFF: 
https://github.com/llvm/llvm-project/commit/9e15c6cc3358287e93a25d869a31ab14c1791dcb.diff

LOG: [CUDA/HIP] Do not ignore complete destructors in abstract classes (#184894)

Summary:
The complete destructor destroys virtual base subobjects even for
abstract classes, so target inference must consider vbases when
analyzing destructors.

This was motivated by behavior observed from a bug where a constexpr
function that calls a non-constexpr function. I believe this error is
secondary, but can be fixed by this observation. The issue was the
switch to C++20 allowing allocator destructors to be constexpr began
opting the function into `__host__ __device__` contexts. This function
then called a non-constexpr function through a type-trait interface
which lead to that only having `__host__` which is illegal.

The fix offered here is to check the bases of this function and
correctly derive that it is `__host__` and not `__host__ __device__` as
was previously inferred. This should only affect cases where the *only*
member is an inherited virtual destructor. Previously we found no bases
and thus made no judgement.

Fixes: https://github.com/llvm/llvm-project/issues/184856

Added: 
    clang/test/SemaCUDA/dtor-constexpr-virtual-base.cu

Modified: 
    clang/lib/Sema/SemaCUDA.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index 6c40b92ddfa12..c086f9a32ce4e 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -496,7 +496,9 @@ bool 
SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
 
   // Look for special members in base classes that should be invoked from here.
   // Infer the target of this member base on the ones it should call.
-  // Skip direct and indirect virtual bases for abstract classes.
+  // Skip direct and indirect virtual bases for abstract classes, except for
+  // destructors — the complete destructor variant destroys virtual bases
+  // regardless of whether the class is abstract.
   llvm::SmallVector<const CXXBaseSpecifier *, 16> Bases;
   for (const auto &B : ClassDecl->bases()) {
     if (!B.isVirtual()) {
@@ -504,9 +506,8 @@ bool 
SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
     }
   }
 
-  if (!ClassDecl->isAbstract()) {
+  if (!ClassDecl->isAbstract() || CSM == CXXSpecialMemberKind::Destructor)
     llvm::append_range(Bases, llvm::make_pointer_range(ClassDecl->vbases()));
-  }
 
   for (const auto *B : Bases) {
     auto *BaseClassDecl = B->getType()->getAsCXXRecordDecl();

diff  --git a/clang/test/SemaCUDA/dtor-constexpr-virtual-base.cu 
b/clang/test/SemaCUDA/dtor-constexpr-virtual-base.cu
new file mode 100644
index 0000000000000..1c4d88a62f21a
--- /dev/null
+++ b/clang/test/SemaCUDA/dtor-constexpr-virtual-base.cu
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 %s -std=c++20 -fsyntax-only -verify=host
+// RUN: %clang_cc1 %s -std=c++20 -fcuda-is-device -fsyntax-only -verify=dev
+
+// host-no-diagnostics
+// dev-no-diagnostics
+
+#include "Inputs/cuda.h"
+
+// The implicit destructor of an abstract class with virtual bases should
+// consider those virtual bases during CUDA target inference, since the
+// complete destructor variant destroys them.
+void host_only();
+
+constexpr void wraps_host() {
+  if (!__builtin_is_constant_evaluated())
+    host_only();
+}
+
+struct HasDtor {
+  ~HasDtor() { wraps_host(); }
+};
+
+struct Base {
+  HasDtor m;
+  virtual ~Base();
+};
+
+template <class T>
+struct Derived : virtual public Base {
+  virtual void foo() = 0;
+};
+
+template class Derived<int>;


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to