From 6e4ce4680a852e6e23cace6829e1130c5805165c Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Tue, 25 Nov 2014 07:20:20 +0000 Subject: [PATCH] MS ABI: Add CodeGen support for rethrowing MS C++ exceptions Rethrowing exceptions in the MS model is very simple: just call _CxxThrowException with nullptr for both arguments. N.B. They chose stdcall as the calling convention for x86 but cdecl for all other platforms. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@222733 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/MSVCCompatibility.rst | 5 +++-- lib/CodeGen/CGCXXABI.h | 1 + lib/CodeGen/CGException.cpp | 24 ++++++++---------------- lib/CodeGen/ItaniumCXXABI.cpp | 16 ++++++++++++++++ lib/CodeGen/MicrosoftCXXABI.cpp | 26 ++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 18 deletions(-) diff --git a/docs/MSVCCompatibility.rst b/docs/MSVCCompatibility.rst index 4dfaab8846..73f01fc2b0 100644 --- a/docs/MSVCCompatibility.rst +++ b/docs/MSVCCompatibility.rst @@ -84,8 +84,9 @@ The status of major ABI-impacting C++ features: * RTTI: :good:`Complete`. Generation of RTTI data structures has been finished, along with support for the ``/GR`` flag. -* Exceptions and SEH: :none:`Unstarted`. Clang can parse both constructs, but - does not know how to emit compatible handlers. +* Exceptions and SEH: :partial:`Minimal`. Clang can parse both constructs, but + does not know how to emit compatible handlers. Clang cannot throw exceptions + but it can rethrow them. * Thread-safe initialization of local statics: :none:`Unstarted`. We are ABI compatible with MSVC 2013, which does not support thread-safe local statics. diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index c52b8e29d1..cc5c1b2e0a 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -213,6 +213,7 @@ public: const CXXDeleteExpr *DE, llvm::Value *Ptr, QualType ElementType, const CXXDestructorDecl *Dtor) = 0; + virtual void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) = 0; virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) = 0; diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 8cd49d1703..05fc863176 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -13,6 +13,7 @@ #include "CodeGenFunction.h" #include "CGCleanup.h" +#include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "TargetInfo.h" #include "clang/AST/StmtCXX.h" @@ -52,15 +53,6 @@ static llvm::Constant *getThrowFn(CodeGenModule &CGM) { return CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); } -static llvm::Constant *getReThrowFn(CodeGenModule &CGM) { - // void __cxa_rethrow(); - - llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false); - - return CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); -} - static llvm::Constant *getGetExceptionPtrFn(CodeGenModule &CGM) { // void *__cxa_get_exception_ptr(void*); @@ -425,13 +417,8 @@ llvm::Value *CodeGenFunction::getSelectorFromSlot() { void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E, bool KeepInsertionPoint) { - if (CGM.getTarget().getTriple().isKnownWindowsMSVCEnvironment()) { - ErrorUnsupported(E, "throw expression"); - return; - } - if (!E->getSubExpr()) { - EmitNoreturnRuntimeCallOrInvoke(getReThrowFn(CGM), None); + CGM.getCXXABI().emitRethrow(*this, /*isNoReturn*/true); // throw is an expression, and the expression emitters expect us // to leave ourselves at a valid insertion point. @@ -441,6 +428,11 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E, return; } + if (CGM.getTarget().getTriple().isKnownWindowsMSVCEnvironment()) { + ErrorUnsupported(E, "throw expression"); + return; + } + QualType ThrowType = E->getSubExpr()->getType(); if (ThrowType->isObjCObjectPointerType()) { @@ -1281,7 +1273,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { // constructor function-try-block's catch handler (p14), so this // really only applies to destructors. if (doImplicitRethrow && HaveInsertPoint()) { - EmitRuntimeCallOrInvoke(getReThrowFn(CGM)); + CGM.getCXXABI().emitRethrow(*this, /*isNoReturn*/false); Builder.CreateUnreachable(); Builder.ClearInsertionPoint(); } diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index a65c5ef8fc..c272091b79 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -110,6 +110,8 @@ public: llvm::Value *Ptr, QualType ElementType, const CXXDestructorDecl *Dtor) override; + void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override; + void EmitFundamentalRTTIDescriptor(QualType Type); void EmitFundamentalRTTIDescriptors(); llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override; @@ -887,6 +889,20 @@ void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF, CGF.PopCleanupBlock(); } +void ItaniumCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) { + // void __cxa_rethrow(); + + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false); + + llvm::Constant *Fn = CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); + + if (isNoReturn) + CGF.EmitNoreturnRuntimeCallOrInvoke(Fn, None); + else + CGF.EmitRuntimeCallOrInvoke(Fn); +} + static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) { // void *__dynamic_cast(const void *sub, // const abi::__class_type_info *src, diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 659ed0a305..6e7d4385d0 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -70,6 +70,8 @@ public: llvm::Value *Ptr, QualType ElementType, const CXXDestructorDecl *Dtor) override; + void emitRethrow(CodeGenFunction &CGF, bool isNoReturn); + llvm::GlobalVariable *getMSCompleteObjectLocator(const CXXRecordDecl *RD, const VPtrInfo *Info); @@ -665,6 +667,30 @@ void MicrosoftCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF, CGF.EmitDeleteCall(DE->getOperatorDelete(), MDThis, ElementType); } +static llvm::Function *getRethrowFn(CodeGenModule &CGM) { + // _CxxThrowException takes two pointer width arguments: a value and a context + // object which points to a TypeInfo object. + llvm::Type *ArgTypes[] = {CGM.Int8PtrTy, CGM.Int8PtrTy}; + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGM.VoidTy, ArgTypes, false); + auto *Fn = cast( + CGM.CreateRuntimeFunction(FTy, "_CxxThrowException")); + // _CxxThrowException is stdcall on 32-bit x86 platforms. + if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86) + Fn->setCallingConv(llvm::CallingConv::X86_StdCall); + return Fn; +} + +void MicrosoftCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) { + llvm::Value *Args[] = {llvm::ConstantPointerNull::get(CGM.Int8PtrTy), + llvm::ConstantPointerNull::get(CGM.Int8PtrTy)}; + auto *Fn = getRethrowFn(CGM); + if (isNoReturn) + CGF.EmitNoreturnRuntimeCallOrInvoke(Fn, Args); + else + CGF.EmitRuntimeCallOrInvoke(Fn, Args); +} + /// \brief Gets the offset to the virtual base that contains the vfptr for /// MS-ABI polymorphic types. static llvm::Value *getPolymorphicOffset(CodeGenFunction &CGF, -- 2.40.0