Skip to content

Commit 9c4232c

Browse files
authored
Merge pull request #74722 from hyp/eng/destructor-cxx-interop-exc-cleanup
[cxx-interop] ensure destructors referenced only by the exception cle…
2 parents c5dff19 + 781a9fc commit 9c4232c

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

lib/IRGen/GenClangDecl.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,19 @@ class ClangDeclFinder
8585
bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *CXXCD) {
8686
callback(CXXCD);
8787
for (clang::CXXCtorInitializer *CXXCI : CXXCD->inits()) {
88-
if (clang::FieldDecl *FD = CXXCI->getMember())
88+
if (clang::FieldDecl *FD = CXXCI->getMember()) {
8989
callback(FD);
90+
// A throwing constructor might throw after the field is initialized,
91+
// emitting additional cleanup code that destroys the field. Make sure
92+
// we record the destructor of the field in that case as it might need
93+
// to be potentially emitted.
94+
if (auto *recordType = FD->getType()->getAsCXXRecordDecl()) {
95+
if (auto *destructor = recordType->getDestructor()) {
96+
if (!destructor->isDeleted())
97+
callback(destructor);
98+
}
99+
}
100+
}
90101
}
91102
return true;
92103
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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+
5+
//--- Inputs/module.modulemap
6+
module ThrowingConstructorDestructorCleanupRef {
7+
header "test.h"
8+
requires cplusplus
9+
}
10+
//--- Inputs/test.h
11+
12+
void testFunc(int x);
13+
14+
template<class T>
15+
class HasDestructor {
16+
T x = 0;
17+
public:
18+
19+
HasDestructor() { }
20+
HasDestructor(const HasDestructor &other) : x(other.x) {}
21+
inline ~HasDestructor() { testFunc(42); }
22+
};
23+
24+
template<class T>
25+
class HasThrowingConstructor {
26+
HasDestructor<T> m;
27+
public:
28+
HasThrowingConstructor();
29+
~HasThrowingConstructor();
30+
inline HasThrowingConstructor(const HasThrowingConstructor &f) : m(f.m) {
31+
doSomethingThatMightThrow();
32+
}
33+
34+
void doSomethingThatMightThrow();
35+
};
36+
37+
inline void test33(const HasThrowingConstructor<int> x) {
38+
39+
}
40+
41+
using HasThrowingConstructorInt = HasThrowingConstructor<int>;
42+
43+
//--- test.swift
44+
45+
import ThrowingConstructorDestructorCleanupRef
46+
47+
public func test() {
48+
let x = HasThrowingConstructorInt()
49+
test33(x)
50+
}
51+
52+
// Make sure we reach the destructor of 'HasDestructor'
53+
// CHECK: define linkonce_odr {{.*}} @{{_ZN13HasDestructorIiED2Ev|"\?\?1\?\$HasDestructor@H@@QEAA@XZ"}}

0 commit comments

Comments
 (0)