diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 3855c97b8ed65..7b1789373f418 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -28,6 +28,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CodeGenABITypes.h" #include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Sema/Sema.h" #include "llvm/IR/GlobalPtrAuthInfo.h" #include "llvm/IR/GlobalValue.h" #include "llvm/Support/Compiler.h" @@ -4555,6 +4556,23 @@ bool IRGenModule::isForeignExceptionHandlingEnabled() const { !clangLangOpts.IgnoreExceptions; } +bool IRGenModule::isCxxNoThrow(clang::FunctionDecl *fd, bool defaultNoThrow) { + auto *fpt = fd->getType()->getAs(); + if (!fpt) + return defaultNoThrow; + if (fpt->getExceptionSpecType() == + clang::ExceptionSpecificationType::EST_Unevaluated) { + // Clang might not have evaluated the exception spec for + // a constructor, so force the evaluation of it. + auto &clangSema = Context.getClangModuleLoader()->getClangSema(); + clangSema.EvaluateImplicitExceptionSpec(fd->getLocation(), fd); + fpt = fd->getType()->getAs(); + if (!fpt) + return defaultNoThrow; + } + return fpt->isNothrow(); +} + /// Emit the epilogue for the function. void IRGenFunction::emitEpilogue() { if (EarliestIP != AllocaIP) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index ad28d97682189..0ddae4b18d8e1 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -3282,11 +3282,9 @@ llvm::CallBase *swift::irgen::emitCXXConstructorCall( IRGenFunction &IGF, const clang::CXXConstructorDecl *ctor, llvm::FunctionType *ctorFnType, llvm::Constant *ctorAddress, llvm::ArrayRef args) { - bool canThrow = IGF.IGM.isForeignExceptionHandlingEnabled(); - if (auto *fpt = ctor->getType()->getAs()) { - if (fpt->isNothrow()) - canThrow = false; - } + bool canThrow = + IGF.IGM.isForeignExceptionHandlingEnabled() && + !IGF.IGM.isCxxNoThrow(const_cast(ctor)); if (!canThrow) return IGF.Builder.CreateCall(ctorFnType, ctorAddress, args); llvm::CallBase *result; diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp index acbd88bc12fe8..87136514e1000 100644 --- a/lib/IRGen/GenStruct.cpp +++ b/lib/IRGen/GenStruct.cpp @@ -720,11 +720,8 @@ namespace { } bool canThrow = false; if (IGF.IGM.isForeignExceptionHandlingEnabled()) { - if (auto *fpt = - destructor->getType()->getAs()) { - if (!fpt->isNothrow()) - canThrow = true; - } + if (!IGF.IGM.isCxxNoThrow(destructor, /*defaultNoThrow=*/true)) + canThrow = true; } if (canThrow) { IGF.createExceptionTrapScope([&](llvm::BasicBlock *invokeNormalDest, diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index a6b69151d6062..5dd87b09c2d11 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -1829,6 +1829,9 @@ private: \ bool isForeignExceptionHandlingEnabled() const; + /// Returns true if the given Clang function does not throw exceptions. + bool isCxxNoThrow(clang::FunctionDecl *fd, bool defaultNoThrow = false); + private: llvm::Constant * getAddrOfSharedContextDescriptor(LinkEntity entity, diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index cd9178473db8c..4922cc3ea289d 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -2887,12 +2887,10 @@ void IRGenSILFunction::visitFunctionRefBaseInst(FunctionRefBaseInst *i) { FunctionPointer fp = FunctionPointer::forDirect(fpKind, value, secondaryValue, sig); // Update the foreign no-throw information if needed. - if (const auto *cd = fn->getClangDecl()) { + if (auto *cd = fn->getClangDecl()) { if (auto *cfd = dyn_cast(cd)) { - if (auto *cft = cfd->getType()->getAs()) { - if (cft->isNothrow()) - fp.setForeignNoThrow(); - } + if (IGM.isCxxNoThrow(const_cast(cfd))) + fp.setForeignNoThrow(); } if (IGM.emittedForeignFunctionThunksWithExceptionTraps.count(fnPtr)) fp.setForeignCallCatchesExceptionInThunk(); diff --git a/test/Interop/Cxx/exceptions/trap-on-exception-irgen-itanium.swift b/test/Interop/Cxx/exceptions/trap-on-exception-irgen-itanium.swift index f7153f780ea34..19a2f24d8b26d 100644 --- a/test/Interop/Cxx/exceptions/trap-on-exception-irgen-itanium.swift +++ b/test/Interop/Cxx/exceptions/trap-on-exception-irgen-itanium.swift @@ -131,6 +131,33 @@ public: inline ClassWithNoThrowingConstructor() noexcept {} }; +struct StructWithDefaultConstructor { + StructWithDefaultConstructor() = default; + + int m = 0; +}; + + +struct NonTrivial { + ~NonTrivial() {} +}; + +struct StructWithDefaultCopyConstructor { + StructWithDefaultCopyConstructor() noexcept {} + StructWithDefaultCopyConstructor(const StructWithDefaultCopyConstructor &) = default; + + int m = 0; + NonTrivial _nonTrivialPoison; +}; + +struct StructWithDefaultDestructor { + StructWithDefaultDestructor() noexcept {} + ~StructWithDefaultDestructor() = default; + + int m = 0; + NonTrivial _nonTrivialPoison; +}; + //--- test.swift import CxxModule @@ -227,6 +254,22 @@ func testClassWithNoThrowingConstructor() -> CInt { return obj.m } +func testStructWithDefaultConstructor() -> StructWithDefaultConstructor { + return StructWithDefaultConstructor() +} + +func testStructWithDefaultCopyConstructor() -> CInt { + var s = StructWithDefaultCopyConstructor() + let copy = s + return s.m +} + +func testStructWithDefaultDestructor() -> CInt { + let s = StructWithDefaultDestructor() + let result = s.m + return result +} + let _ = testFreeFunctionNoThrowOnly() let _ = testFreeFunctionCalls() let _ = testMethodCalls() @@ -241,6 +284,9 @@ let _ = testClassWithCopyConstructor() let _ = testClassWithThrowingCopyConstructor() let _ = testClassWithThrowingConstructor() let _ = testClassWithNoThrowingConstructor() +let _ = testStructWithDefaultConstructor() +let _ = testStructWithDefaultCopyConstructor() +let _ = testStructWithDefaultDestructor() // CHECK: define {{.*}} @"$s4test0A23FreeFunctionNoThrowOnlys5Int32VyF"() #[[#SWIFTMETA:]] { // CHECK-NEXT: : @@ -393,6 +439,18 @@ let _ = testClassWithNoThrowingConstructor() // CHECK-NOT: invoke // CHECK: } +// CHECK: define {{.*}} @"$s4test0A28StructWithDefaultConstructorSo0bcdE0VyF"() #[[#SWIFTMETA]] { +// CHECK-NOT: invoke +// CHECK: } + +// CHECK: define {{.*}} @"$s4test0A32StructWithDefaultCopyConstructors5Int32VyF"() #[[#SWIFTMETA]] { +// CHECK-NOT: invoke +// CHECK: } + +// CHECK: define {{.*}} @"$s4test0A27StructWithDefaultDestructors5Int32VyF"() #[[#SWIFTMETA]] { +// CHECK-NOT: invoke +// CHECK: } + // CHECK: i32 @__gxx_personality_v0(...) // CHECK: attributes #[[#SWIFTMETA]] = {