Skip to content

Commit 3dcd992

Browse files
committed
[cxx-interop] evaluate default constructor's unevaluated exception spec if needed when emitting C++ constructor call
Fixes #65891 (cherry picked from commit b0dab0b)
1 parent 67cf190 commit 3dcd992

File tree

6 files changed

+87
-15
lines changed

6 files changed

+87
-15
lines changed

lib/IRGen/GenCall.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "clang/Basic/TargetInfo.h"
2929
#include "clang/CodeGen/CodeGenABITypes.h"
3030
#include "clang/CodeGen/ModuleBuilder.h"
31+
#include "clang/Sema/Sema.h"
3132
#include "llvm/IR/GlobalPtrAuthInfo.h"
3233
#include "llvm/IR/GlobalValue.h"
3334
#include "llvm/Support/Compiler.h"
@@ -4555,6 +4556,23 @@ bool IRGenModule::isForeignExceptionHandlingEnabled() const {
45554556
!clangLangOpts.IgnoreExceptions;
45564557
}
45574558

4559+
bool IRGenModule::isCxxNoThrow(clang::FunctionDecl *fd, bool defaultNoThrow) {
4560+
auto *fpt = fd->getType()->getAs<clang::FunctionProtoType>();
4561+
if (!fpt)
4562+
return defaultNoThrow;
4563+
if (fpt->getExceptionSpecType() ==
4564+
clang::ExceptionSpecificationType::EST_Unevaluated) {
4565+
// Clang might not have evaluated the exception spec for
4566+
// a constructor, so force the evaluation of it.
4567+
auto &clangSema = Context.getClangModuleLoader()->getClangSema();
4568+
clangSema.EvaluateImplicitExceptionSpec(fd->getLocation(), fd);
4569+
fpt = fd->getType()->getAs<clang::FunctionProtoType>();
4570+
if (!fpt)
4571+
return defaultNoThrow;
4572+
}
4573+
return fpt->isNothrow();
4574+
}
4575+
45584576
/// Emit the epilogue for the function.
45594577
void IRGenFunction::emitEpilogue() {
45604578
if (EarliestIP != AllocaIP)

lib/IRGen/GenDecl.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3282,11 +3282,9 @@ llvm::CallBase *swift::irgen::emitCXXConstructorCall(
32823282
IRGenFunction &IGF, const clang::CXXConstructorDecl *ctor,
32833283
llvm::FunctionType *ctorFnType, llvm::Constant *ctorAddress,
32843284
llvm::ArrayRef<llvm::Value *> args) {
3285-
bool canThrow = IGF.IGM.isForeignExceptionHandlingEnabled();
3286-
if (auto *fpt = ctor->getType()->getAs<clang::FunctionProtoType>()) {
3287-
if (fpt->isNothrow())
3288-
canThrow = false;
3289-
}
3285+
bool canThrow =
3286+
IGF.IGM.isForeignExceptionHandlingEnabled() &&
3287+
!IGF.IGM.isCxxNoThrow(const_cast<clang::CXXConstructorDecl *>(ctor));
32903288
if (!canThrow)
32913289
return IGF.Builder.CreateCall(ctorFnType, ctorAddress, args);
32923290
llvm::CallBase *result;

lib/IRGen/GenStruct.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -720,11 +720,8 @@ namespace {
720720
}
721721
bool canThrow = false;
722722
if (IGF.IGM.isForeignExceptionHandlingEnabled()) {
723-
if (auto *fpt =
724-
destructor->getType()->getAs<clang::FunctionProtoType>()) {
725-
if (!fpt->isNothrow())
726-
canThrow = true;
727-
}
723+
if (!IGF.IGM.isCxxNoThrow(destructor, /*defaultNoThrow=*/true))
724+
canThrow = true;
728725
}
729726
if (canThrow) {
730727
IGF.createExceptionTrapScope([&](llvm::BasicBlock *invokeNormalDest,

lib/IRGen/IRGenModule.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1829,6 +1829,9 @@ private: \
18291829

18301830
bool isForeignExceptionHandlingEnabled() const;
18311831

1832+
/// Returns true if the given Clang function does not throw exceptions.
1833+
bool isCxxNoThrow(clang::FunctionDecl *fd, bool defaultNoThrow = false);
1834+
18321835
private:
18331836
llvm::Constant *
18341837
getAddrOfSharedContextDescriptor(LinkEntity entity,

lib/IRGen/IRGenSIL.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2887,12 +2887,10 @@ void IRGenSILFunction::visitFunctionRefBaseInst(FunctionRefBaseInst *i) {
28872887
FunctionPointer fp =
28882888
FunctionPointer::forDirect(fpKind, value, secondaryValue, sig);
28892889
// Update the foreign no-throw information if needed.
2890-
if (const auto *cd = fn->getClangDecl()) {
2890+
if (auto *cd = fn->getClangDecl()) {
28912891
if (auto *cfd = dyn_cast<clang::FunctionDecl>(cd)) {
2892-
if (auto *cft = cfd->getType()->getAs<clang::FunctionProtoType>()) {
2893-
if (cft->isNothrow())
2894-
fp.setForeignNoThrow();
2895-
}
2892+
if (IGM.isCxxNoThrow(const_cast<clang::FunctionDecl *>(cfd)))
2893+
fp.setForeignNoThrow();
28962894
}
28972895
if (IGM.emittedForeignFunctionThunksWithExceptionTraps.count(fnPtr))
28982896
fp.setForeignCallCatchesExceptionInThunk();

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,33 @@ public:
131131
inline ClassWithNoThrowingConstructor() noexcept {}
132132
};
133133

134+
struct StructWithDefaultConstructor {
135+
StructWithDefaultConstructor() = default;
136+
137+
int m = 0;
138+
};
139+
140+
141+
struct NonTrivial {
142+
~NonTrivial() {}
143+
};
144+
145+
struct StructWithDefaultCopyConstructor {
146+
StructWithDefaultCopyConstructor() noexcept {}
147+
StructWithDefaultCopyConstructor(const StructWithDefaultCopyConstructor &) = default;
148+
149+
int m = 0;
150+
NonTrivial _nonTrivialPoison;
151+
};
152+
153+
struct StructWithDefaultDestructor {
154+
StructWithDefaultDestructor() noexcept {}
155+
~StructWithDefaultDestructor() = default;
156+
157+
int m = 0;
158+
NonTrivial _nonTrivialPoison;
159+
};
160+
134161
//--- test.swift
135162

136163
import CxxModule
@@ -227,6 +254,22 @@ func testClassWithNoThrowingConstructor() -> CInt {
227254
return obj.m
228255
}
229256

257+
func testStructWithDefaultConstructor() -> StructWithDefaultConstructor {
258+
return StructWithDefaultConstructor()
259+
}
260+
261+
func testStructWithDefaultCopyConstructor() -> CInt {
262+
var s = StructWithDefaultCopyConstructor()
263+
let copy = s
264+
return s.m
265+
}
266+
267+
func testStructWithDefaultDestructor() -> CInt {
268+
let s = StructWithDefaultDestructor()
269+
let result = s.m
270+
return result
271+
}
272+
230273
let _ = testFreeFunctionNoThrowOnly()
231274
let _ = testFreeFunctionCalls()
232275
let _ = testMethodCalls()
@@ -241,6 +284,9 @@ let _ = testClassWithCopyConstructor()
241284
let _ = testClassWithThrowingCopyConstructor()
242285
let _ = testClassWithThrowingConstructor()
243286
let _ = testClassWithNoThrowingConstructor()
287+
let _ = testStructWithDefaultConstructor()
288+
let _ = testStructWithDefaultCopyConstructor()
289+
let _ = testStructWithDefaultDestructor()
244290

245291
// CHECK: define {{.*}} @"$s4test0A23FreeFunctionNoThrowOnlys5Int32VyF"() #[[#SWIFTMETA:]] {
246292
// CHECK-NEXT: :
@@ -393,6 +439,18 @@ let _ = testClassWithNoThrowingConstructor()
393439
// CHECK-NOT: invoke
394440
// CHECK: }
395441

442+
// CHECK: define {{.*}} @"$s4test0A28StructWithDefaultConstructorSo0bcdE0VyF"() #[[#SWIFTMETA]] {
443+
// CHECK-NOT: invoke
444+
// CHECK: }
445+
446+
// CHECK: define {{.*}} @"$s4test0A32StructWithDefaultCopyConstructors5Int32VyF"() #[[#SWIFTMETA]] {
447+
// CHECK-NOT: invoke
448+
// CHECK: }
449+
450+
// CHECK: define {{.*}} @"$s4test0A27StructWithDefaultDestructors5Int32VyF"() #[[#SWIFTMETA]] {
451+
// CHECK-NOT: invoke
452+
// CHECK: }
453+
396454
// CHECK: i32 @__gxx_personality_v0(...)
397455

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

0 commit comments

Comments
 (0)