Skip to content

Commit af36238

Browse files
authored
Merge pull request #74640 from hyp/eng/virtual-destructor-vtable-ref-irgen-linux-android
[cxx-interop] ensure that the body of implicit virtual destructor is …
2 parents 9c4232c + f4949bd commit af36238

File tree

4 files changed

+152
-8
lines changed

4 files changed

+152
-8
lines changed

lib/IRGen/GenClangDecl.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,12 @@ void IRGenModule::emitClangDecl(const clang::Decl *decl) {
299299
// class because they might be emitted in the vtable even if not used
300300
// directly from Swift.
301301
if (auto *record = dyn_cast<clang::CXXRecordDecl>(next->getDeclContext())) {
302+
if (auto *destructor = record->getDestructor()) {
303+
// Ensure virtual destructors have the body defined, even if they're
304+
// not used directly, as they might be referenced by the emitted vtable.
305+
if (destructor->isVirtual() && !destructor->isDeleted())
306+
ensureImplicitCXXDestructorBodyIsDefined(destructor);
307+
}
302308
for (auto *method : record->methods()) {
303309
if (method->isVirtual()) {
304310
callback(method);
@@ -348,3 +354,15 @@ void IRGenModule::finalizeClangCodeGen() {
348354
ClangCodeGen->HandleTranslationUnit(
349355
*const_cast<clang::ASTContext *>(ClangASTContext));
350356
}
357+
358+
void IRGenModule::ensureImplicitCXXDestructorBodyIsDefined(
359+
clang::CXXDestructorDecl *destructor) {
360+
if (destructor->isUserProvided() ||
361+
destructor->doesThisDeclarationHaveABody())
362+
return;
363+
assert(!destructor->isDeleted() &&
364+
"Swift cannot handle a type with no known destructor.");
365+
// Make sure we define the destructor so we have something to call.
366+
auto &sema = Context.getClangModuleLoader()->getClangSema();
367+
sema.DefineImplicitDestructor(clang::SourceLocation(), destructor);
368+
}

lib/IRGen/GenStruct.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -689,14 +689,7 @@ namespace {
689689
return;
690690
}
691691

692-
if (!destructor->isUserProvided() &&
693-
!destructor->doesThisDeclarationHaveABody()) {
694-
assert(!destructor->isDeleted() &&
695-
"Swift cannot handle a type with no known destructor.");
696-
// Make sure we define the destructor so we have something to call.
697-
auto &sema = IGF.IGM.Context.getClangModuleLoader()->getClangSema();
698-
sema.DefineImplicitDestructor(clang::SourceLocation(), destructor);
699-
}
692+
IGF.IGM.ensureImplicitCXXDestructorBodyIsDefined(destructor);
700693

701694
clang::GlobalDecl destructorGlobalDecl(destructor, clang::Dtor_Complete);
702695
auto *destructorFnAddr =

lib/IRGen/IRGenModule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ namespace clang {
7777
class ASTContext;
7878
template <class> class CanQual;
7979
class CodeGenerator;
80+
class CXXDestructorDecl;
8081
class Decl;
8182
class GlobalDecl;
8283
class Type;
@@ -1616,6 +1617,9 @@ private: \
16161617
ForeignFunctionInfo *foreignInfo=nullptr);
16171618
ForeignFunctionInfo getForeignFunctionInfo(CanSILFunctionType type);
16181619

1620+
void
1621+
ensureImplicitCXXDestructorBodyIsDefined(clang::CXXDestructorDecl *cxxDtor);
1622+
16191623
llvm::ConstantInt *getInt32(uint32_t value);
16201624
llvm::ConstantInt *getSize(Size size);
16211625
llvm::Constant *getAlignment(Alignment align);
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: %target-swiftxx-frontend -emit-ir -I %t/Inputs -validate-tbd-against-ir=none %t/test.swift | %FileCheck %s
4+
// RUN: %target-swiftxx-frontend -verify -emit-ir -I %t/Inputs -validate-tbd-against-ir=none %t/test.swift -Xcc -DDELETED -o /dev/null
5+
6+
//--- Inputs/module.modulemap
7+
module VtableDestructorRef {
8+
header "test.h"
9+
requires cplusplus
10+
}
11+
//--- Inputs/test.h
12+
13+
14+
namespace impl {
15+
16+
#ifdef DELETED
17+
18+
template<class T>
19+
class BaseClass
20+
{
21+
public:
22+
~BaseClass() = delete;
23+
};
24+
25+
template<class Fp, class T>
26+
class Func: public BaseClass<T>
27+
{
28+
Fp x;
29+
public:
30+
inline explicit Func(Fp x);
31+
Func(const Func &) = delete;
32+
~Func();
33+
};
34+
35+
#else
36+
37+
template<class T>
38+
class BaseClass
39+
{
40+
public:
41+
virtual ~BaseClass() {}
42+
};
43+
44+
template<class Fp, class T>
45+
class Func: public BaseClass<T>
46+
{
47+
Fp x;
48+
public:
49+
50+
inline explicit Func(Fp x) : x(x) {}
51+
};
52+
53+
#endif
54+
55+
template <class _Fp> class ValueFunc;
56+
57+
template <class _Rp, class... _ArgTypes> class ValueFunc<_Rp(_ArgTypes...)>
58+
{
59+
typedef impl::BaseClass<_Rp(_ArgTypes...)> FuncTy;
60+
FuncTy* _Nullable f;
61+
public:
62+
63+
template <class _Fp>
64+
ValueFunc(_Fp fp) {
65+
typedef impl::Func<_Fp, _Rp(_ArgTypes...)> _Fun;
66+
f = ::new _Fun(fp);
67+
}
68+
69+
ValueFunc(ValueFunc&& other) {
70+
if (other.f == nullptr)
71+
f = nullptr;
72+
else
73+
{
74+
f = other.f;
75+
other.f = nullptr;
76+
}
77+
}
78+
};
79+
80+
template<class _Rp>
81+
class Function;
82+
83+
template<class _Rp, class ..._ArgTypes>
84+
class Function<_Rp(_ArgTypes...)> {
85+
ValueFunc<_Rp(_ArgTypes...)> f;
86+
public:
87+
template<class _Fp>
88+
Function(_Fp);
89+
};
90+
91+
template <class _Rp, class... _ArgTypes>
92+
template <class _Fp>
93+
Function<_Rp(_ArgTypes...)>::Function(_Fp f) : f(f) {}
94+
95+
}
96+
97+
class MyFutureBase {
98+
public:
99+
void OnCompletion(impl::Function<void(const MyFutureBase&)> callback) const;
100+
};
101+
102+
template<class T>
103+
class MyFuture : public MyFutureBase {
104+
public:
105+
void OnCompletion(
106+
void (* _Nonnull completion)(void * _Nullable),
107+
void * _Nullable user_data) const {
108+
MyFutureBase::OnCompletion(
109+
[completion, user_data](const MyFutureBase&) {
110+
completion(user_data);
111+
});
112+
}
113+
};
114+
115+
using MyFutureInt = MyFuture<int>;
116+
117+
//--- test.swift
118+
119+
import VtableDestructorRef
120+
121+
public func test() {
122+
let f = MyFutureInt()
123+
f.OnCompletion({ _ in
124+
print("done")
125+
}, nil)
126+
}
127+
128+
// Make sure we reach the virtual destructor of 'Func'.
129+
// CHECK: define linkonce_odr {{.*}} @{{_ZN4impl4FuncIZNK8MyFutureIiE12OnCompletionEPFvPvES3_EUlRK12MyFutureBaseE_FvS8_EED2Ev|"\?\?1\?\$BaseClass@\$\$A6AXAEBVMyFutureBase@@@Z@impl@@UEAA@XZ"}}

0 commit comments

Comments
 (0)