Skip to content

Commit 8998f97

Browse files
committed
[interop] trap on uncaught C++ copy constructor exceptions
1 parent 7d8ecfc commit 8998f97

File tree

8 files changed

+121
-17
lines changed

8 files changed

+121
-17
lines changed

lib/IRGen/GenCall.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1982,17 +1982,9 @@ Signature SignatureExpansion::getSignature() {
19821982
result.Attributes = Attrs;
19831983
using ExtraData = Signature::ExtraData;
19841984
if (FnType->getLanguage() == SILFunctionLanguage::C) {
1985-
const auto &clangLangOpts =
1986-
IGM.Context.getClangModuleLoader()->getClangASTContext().getLangOpts();
1987-
bool exceptionHandlingEnabled = IGM.Context.LangOpts.EnableCXXInterop &&
1988-
clangLangOpts.Exceptions &&
1989-
!clangLangOpts.IgnoreExceptions;
1990-
// FIXME: Support exceptions on windows MSVC.
1991-
if (IGM.Triple.isWindowsMSVCEnvironment())
1992-
exceptionHandlingEnabled = false;
19931985
// This is a potentially throwing function. The use of 'noexcept' /
19941986
// 'nothrow' is applied at the call site in the \c FunctionPointer class.
1995-
ForeignInfo.canThrow = exceptionHandlingEnabled;
1987+
ForeignInfo.canThrow = IGM.isForeignExceptionHandlingEnabled();
19961988
result.ExtraDataKind = ExtraData::kindForMember<ForeignFunctionInfo>();
19971989
result.ExtraDataStorage.emplace<ForeignFunctionInfo>(result.ExtraDataKind,
19981990
ForeignInfo);
@@ -4473,6 +4465,15 @@ llvm::BasicBlock *IRGenFunction::createExceptionUnwindBlock() {
44734465
return result;
44744466
}
44754467

4468+
void IRGenFunction::createExceptionTrapScope(
4469+
llvm::function_ref<void(llvm::BasicBlock *, llvm::BasicBlock *)>
4470+
invokeEmitter) {
4471+
auto *invokeNormalDest = createBasicBlock("invoke.cont");
4472+
auto *invokeUnwindDest = createExceptionUnwindBlock();
4473+
invokeEmitter(invokeNormalDest, invokeUnwindDest);
4474+
Builder.emitBlock(invokeNormalDest);
4475+
}
4476+
44764477
/// Emit the prologue for the function.
44774478
void IRGenFunction::emitPrologue() {
44784479
// Set up the IRBuilder.
@@ -4532,6 +4533,16 @@ llvm::Function *IRGenModule::getForeignExceptionHandlingPersonalityFunc() {
45324533
return foreignExceptionHandlingPersonalityFunc;
45334534
}
45344535

4536+
bool IRGenModule::isForeignExceptionHandlingEnabled() const {
4537+
// FIXME: Support exceptions on windows MSVC.
4538+
if (Triple.isWindowsMSVCEnvironment())
4539+
return false;
4540+
const auto &clangLangOpts =
4541+
Context.getClangModuleLoader()->getClangASTContext().getLangOpts();
4542+
return Context.LangOpts.EnableCXXInterop && clangLangOpts.Exceptions &&
4543+
!clangLangOpts.IgnoreExceptions;
4544+
}
4545+
45354546
/// Emit the epilogue for the function.
45364547
void IRGenFunction::emitEpilogue() {
45374548
if (EarliestIP != AllocaIP)

lib/IRGen/GenDecl.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3252,7 +3252,20 @@ llvm::Constant *swift::irgen::emitCXXConstructorThunkIfNeeded(
32523252
Args.push_back(arg);
32533253
}
32543254

3255-
subIGF.Builder.CreateCall(ctorFnType, ctorAddress, Args);
3255+
bool canThrow = IGM.isForeignExceptionHandlingEnabled();
3256+
if (auto *fpt = ctor->getType()->getAs<clang::FunctionProtoType>()) {
3257+
if (fpt->isNothrow())
3258+
canThrow = false;
3259+
}
3260+
if (canThrow)
3261+
subIGF.createExceptionTrapScope([&](llvm::BasicBlock *invokeNormalDest,
3262+
llvm::BasicBlock *invokeUnwindDest) {
3263+
subIGF.Builder.createInvoke(ctorFnType, ctorAddress, Args,
3264+
invokeNormalDest, invokeUnwindDest);
3265+
});
3266+
else
3267+
subIGF.Builder.CreateCall(ctorFnType, ctorAddress, Args);
3268+
32563269
subIGF.Builder.CreateRetVoid();
32573270

32583271
return thunk;

lib/IRGen/GenStruct.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -648,12 +648,12 @@ namespace {
648648
canThrow = true;
649649
}
650650
if (canThrow) {
651-
auto *invokeNormalDest = IGF.createBasicBlock("invoke.cont");
652-
auto *invokeUnwindDest = IGF.createExceptionUnwindBlock();
653-
IGF.Builder.createInvoke(destructorFnAddr->getFunctionType(),
654-
destructorFnAddr, args, invokeNormalDest,
655-
invokeUnwindDest);
656-
IGF.Builder.emitBlock(invokeNormalDest);
651+
IGF.createExceptionTrapScope([&](llvm::BasicBlock *invokeNormalDest,
652+
llvm::BasicBlock *invokeUnwindDest) {
653+
IGF.Builder.createInvoke(destructorFnAddr->getFunctionType(),
654+
destructorFnAddr, args, invokeNormalDest,
655+
invokeUnwindDest);
656+
});
657657
return;
658658
}
659659

lib/IRGen/IRGenFunction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ class IRGenFunction {
105105

106106
llvm::BasicBlock *createExceptionUnwindBlock();
107107

108+
void createExceptionTrapScope(
109+
llvm::function_ref<void(llvm::BasicBlock *, llvm::BasicBlock *)>
110+
invokeEmitter);
111+
108112
void emitAllExtractValues(llvm::Value *aggValue, llvm::StructType *type,
109113
Explosion &out);
110114

lib/IRGen/IRGenModule.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,6 +1807,8 @@ private: \
18071807

18081808
llvm::Function *getForeignExceptionHandlingPersonalityFunc();
18091809

1810+
bool isForeignExceptionHandlingEnabled() const;
1811+
18101812
private:
18111813
llvm::Constant *
18121814
getAddrOfSharedContextDescriptor(LinkEntity entity,

test/Interop/Cxx/exceptions/exceptions-disabled-exception-irgen.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ inline int freeFunctionNoThrow(int x) noexcept {
2424
return -x;
2525
}
2626

27+
class ClassWithThrowingCopyConstructor {
28+
public:
29+
int m = 0;
30+
inline ClassWithThrowingCopyConstructor() noexcept {}
31+
inline ClassWithThrowingCopyConstructor(const ClassWithThrowingCopyConstructor &) { (void)freeFunctionThrows(0); }
32+
};
33+
2734
//--- test.swift
2835

2936
import CxxModule
@@ -43,8 +50,15 @@ func testFreeFunctionCalls() -> CInt {
4350
return p
4451
}
4552

53+
func testClassWithThrowingCopyConstructor() -> CInt {
54+
let p1 = ClassWithThrowingCopyConstructor()
55+
let p2 = p1
56+
return p2.m
57+
}
58+
4659
let _ = testFreeFunctionNoThrowOnly()
4760
let _ = testFreeFunctionCalls()
61+
let _ = testClassWithThrowingCopyConstructor()
4862

4963
// CHECK: define {{.*}} @"$s4test0A23FreeFunctionNoThrowOnlys5Int32VyF"() #[[#SWIFTMETA:]] {
5064
// CHECK-NEXT: :
@@ -60,3 +74,7 @@ let _ = testFreeFunctionCalls()
6074
// CHECK: call i32 @{{_Z18freeFunctionThrowsi|"\?freeFunctionThrows@@YAHH@Z"}}(i32
6175
// CHECK: ret i32
6276
// CHECK-NEXT: }
77+
78+
// CHECK: define {{.*}} @"$s4test0A32ClassWithThrowingCopyConstructors5Int32VyF"() #[[#SWIFTMETA]] {
79+
// CHECK-NOT: invoke
80+
// CHECK: }

test/Interop/Cxx/exceptions/trap-on-exception-execution.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// RUN: %target-codesign %t/trap-exceptions-no-debug
1010
// RUN: %target-run %t/trap-exceptions-no-debug
1111

12-
// RUN: %target-build-swift %s -I %t/Inputs -o %t/trap-exceptions-opt -Xfrontend -enable-experimental-cxx-interop -Xfrontend -validate-tbd-against-ir=none -O
12+
// RUN: %target-build-swift %s -I %t/Inputs -o %t/trap-exceptions-opt -Xfrontend -enable-experimental-cxx-interop -Xfrontend -validate-tbd-against-ir=none -O -DOPTIMIZE
1313
// RUN: %target-codesign %t/trap-exceptions-opt
1414
// RUN: %target-run %t/trap-exceptions-opt
1515

@@ -93,4 +93,14 @@ TrapOnExecutionTestSuite.test("TestClassWithThrowingDestructor") {
9393
let _ = ClassWithThrowingDestructor()
9494
}
9595

96+
#if OPTIMIZE
97+
#else
98+
TrapOnExecutionTestSuite.test("TestClassWithThrowingCopyConstructor") {
99+
expectCrashLater()
100+
let p1 = ClassWithThrowingCopyConstructor()
101+
let p2 = p1
102+
expectEqual(p2.m, 0)
103+
}
104+
#endif
105+
96106
runAllTests()

test/Interop/Cxx/exceptions/trap-on-exception-irgen-itanium.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,20 @@ public:
105105
}
106106
};
107107

108+
class ClassWithCopyConstructor {
109+
public:
110+
int m = 0;
111+
inline ClassWithCopyConstructor() noexcept {}
112+
inline ClassWithCopyConstructor(const ClassWithCopyConstructor &) noexcept { (void)freeFunctionNoThrow(0); }
113+
};
114+
115+
class ClassWithThrowingCopyConstructor {
116+
public:
117+
int m = 0;
118+
inline ClassWithThrowingCopyConstructor() noexcept {}
119+
inline ClassWithThrowingCopyConstructor(const ClassWithThrowingCopyConstructor &) { throw 2; }
120+
};
121+
108122
//--- test.swift
109123

110124
import CxxModule
@@ -179,6 +193,18 @@ func testClassWithThrowingDestructor() {
179193
let _ = ClassWithThrowingDestructor()
180194
}
181195

196+
func testClassWithCopyConstructor() -> CInt {
197+
let p1 = ClassWithCopyConstructor()
198+
let p2 = p1
199+
return p2.m
200+
}
201+
202+
func testClassWithThrowingCopyConstructor() -> CInt {
203+
let p1 = ClassWithThrowingCopyConstructor()
204+
let p2 = p1
205+
return p2.m
206+
}
207+
182208
let _ = testFreeFunctionNoThrowOnly()
183209
let _ = testFreeFunctionCalls()
184210
let _ = testMethodCalls()
@@ -189,6 +215,8 @@ testProtocolConformanceThunkInvoke()
189215
let _ = testSubscriptThunkInvoke()
190216
testClassWithDestructor()
191217
testClassWithThrowingDestructor()
218+
let _ = testClassWithCopyConstructor()
219+
let _ = testClassWithThrowingCopyConstructor()
192220

193221
// CHECK: define {{.*}} @"$s4test0A23FreeFunctionNoThrowOnlys5Int32VyF"() #[[#SWIFTMETA:]] {
194222
// CHECK-NEXT: :
@@ -313,6 +341,24 @@ testClassWithThrowingDestructor()
313341
// CHECK-NEXT: unreachable
314342
// CHECK-NEXT: }
315343

344+
// CHECK: define {{.*}} @"$s4test0A24ClassWithCopyConstructors5Int32VyF"() #[[#SWIFTMETA]]
345+
// CHECK-NOT: invoke
346+
// CHECK: }
347+
348+
// CHECK: define {{.*}} @"$s4test0A32ClassWithThrowingCopyConstructors5Int32VyF"() #[[#SWIFTMETA]] personality
349+
// CHECK: invoke {{.*}} @_ZN32ClassWithThrowingCopyConstructorC1ERKS_(
350+
// CHECK-NEXT: to label %[[CONT41:.*]] unwind label %[[UNWIND41:.*]]
351+
// CHECK-EMPTY:
352+
// CHECK-NEXT: [[UNWIND41]]:
353+
// CHECK-NEXT: landingpad { i8*, i32 }
354+
// CHECK-NEXT: catch i8* null
355+
// CHECK-NEXT: call void @llvm.trap()
356+
// CHECK-NEXT: unreachable
357+
// CHECK-EMPTY:
358+
// CHECK: [[CONT41]]:
359+
// CHECK: ret i32
360+
// CHECK-NEXT: }
361+
316362
// CHECK: i32 @__gxx_personality_v0(...)
317363

318364
// CHECK: attributes #[[#SWIFTMETA]] = {

0 commit comments

Comments
 (0)