Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -701,6 +701,7 @@ LANGBUILTIN(_exception_info, "v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__abnormal_termination, "i", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_abnormal_termination, "i", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__GetExceptionInfo, "v*.", "ntu", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchange, "LiLiD*LiLi", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedDecrement, "LiLiD*", "n", ALL_MS_LANGUAGES) Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -4442,8 +4442,7 @@ ExprResult ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *expr); ExprResult BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, bool IsThrownVarInScope); - ExprResult CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, - bool IsThrownVarInScope); + bool CheckCXXThrowOperand(SourceLocation ThrowLoc, QualType ThrowTy, Expr *E); /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. /// Can be interpreted either as function-style casting ("int(x)") Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -7840,6 +7840,9 @@ ArgTypes.push_back(Ty); } + if (Id == Builtin::BI__GetExceptionInfo) + return QualType(); + assert((TypeStr[0] != '.' || TypeStr[1] == 0) && "'.' should only occur at end of builtin type list!"); Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -2634,7 +2634,14 @@ // extern "C". // FIXME: A recognised library function may not be directly in an extern "C" // declaration, for instance "extern "C" { namespace std { decl } }". - if (!LinkageDecl || LinkageDecl->getLanguage() != LinkageSpecDecl::lang_c) + if (!LinkageDecl) { + if (BuiltinID == Builtin::BI__GetExceptionInfo && + Context.getTargetInfo().getCXXABI().isMicrosoft() && + isInStdNamespace()) + return Builtin::BI__GetExceptionInfo; + return 0; + } + if (LinkageDecl->getLanguage() != LinkageSpecDecl::lang_c) return 0; } Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" +#include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CodeGenModule.h" #include "TargetInfo.h" @@ -1729,6 +1730,13 @@ return RValue::get(CS.getInstruction()); } } + + case Builtin::BI__GetExceptionInfo: { + if (llvm::GlobalVariable *GV = + CGM.getCXXABI().getThrowInfo(FD->getParamDecl(0)->getType())) + return RValue::get(llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy)); + break; + } } // If this is an alias for a lib function (e.g. __builtin_sin), emit Index: lib/CodeGen/CGCXXABI.h =================================================================== --- lib/CodeGen/CGCXXABI.h +++ lib/CodeGen/CGCXXABI.h @@ -216,6 +216,7 @@ const CXXDestructorDecl *Dtor) = 0; virtual void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) = 0; virtual void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) = 0; + virtual llvm::GlobalVariable *getThrowInfo(QualType T) { return nullptr; } virtual void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) = 0; Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -644,7 +644,7 @@ llvm::GlobalVariable *getCatchableTypeArray(QualType T); - llvm::GlobalVariable *getThrowInfo(QualType T); + llvm::GlobalVariable *getThrowInfo(QualType T) override; private: typedef std::pair VFTableIdTy; Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -499,6 +499,19 @@ break; } + case Builtin::BI__GetExceptionInfo: + if (checkArgCount(*this, TheCall, 1)) + return ExprError(); + + if (CheckCXXThrowOperand( + TheCall->getLocStart(), + Context.getExceptionObjectType(FDecl->getParamDecl(0)->getType()), + TheCall)) + return ExprError(); + + TheCall->setType(Context.VoidPtrTy); + break; + } // Since the target specific builtins for each arch overlap, only check those Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -647,12 +647,39 @@ Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw"; if (Ex && !Ex->isTypeDependent()) { - ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex, IsThrownVarInScope); - if (ExRes.isInvalid()) + QualType ExceptionObjectTy = Context.getExceptionObjectType(Ex->getType()); + if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex)) return ExprError(); - Ex = ExRes.get(); + + // Initialize the exception result. This implicitly weeds out + // abstract types or types with inaccessible copy constructors. + + // C++0x [class.copymove]p31: + // When certain criteria are met, an implementation is allowed to omit the + // copy/move construction of a class object [...] + // + // - in a throw-expression, when the operand is the name of a + // non-volatile automatic object (other than a function or + // catch-clause + // parameter) whose scope does not extend beyond the end of the + // innermost enclosing try-block (if there is one), the copy/move + // operation from the operand to the exception object (15.1) can be + // omitted by constructing the automatic object directly into the + // exception object + const VarDecl *NRVOVariable = nullptr; + if (IsThrownVarInScope) + NRVOVariable = getCopyElisionCandidate(QualType(), Ex, false); + + InitializedEntity Entity = InitializedEntity::InitializeException( + OpLoc, ExceptionObjectTy, + /*NRVO=*/NRVOVariable != nullptr); + ExprResult Res = PerformMoveOrCopyInitialization( + Entity, NRVOVariable, QualType(), Ex, IsThrownVarInScope); + if (Res.isInvalid()) + return ExprError(); + Ex = Res.get(); } - + return new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope); } @@ -707,9 +734,8 @@ } /// CheckCXXThrowOperand - Validate the operand of a throw. -ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, - bool IsThrownVarInScope) { - QualType ExceptionObjectTy = Context.getExceptionObjectType(E->getType()); +bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, + QualType ExceptionObjectTy, Expr *E) { // If the type of the exception would be an incomplete type or a pointer // to an incomplete type other than (cv) void the program is ill-formed. QualType Ty = ExceptionObjectTy; @@ -720,48 +746,20 @@ } if (!isPointer || !Ty->isVoidType()) { if (RequireCompleteType(ThrowLoc, Ty, - isPointer? diag::err_throw_incomplete_ptr - : diag::err_throw_incomplete, + isPointer ? diag::err_throw_incomplete_ptr + : diag::err_throw_incomplete, E->getSourceRange())) - return ExprError(); + return true; if (RequireNonAbstractType(ThrowLoc, ExceptionObjectTy, diag::err_throw_abstract_type, E)) - return ExprError(); + return true; } - // Initialize the exception result. This implicitly weeds out - // abstract types or types with inaccessible copy constructors. - - // C++0x [class.copymove]p31: - // When certain criteria are met, an implementation is allowed to omit the - // copy/move construction of a class object [...] - // - // - in a throw-expression, when the operand is the name of a - // non-volatile automatic object (other than a function or catch-clause - // parameter) whose scope does not extend beyond the end of the - // innermost enclosing try-block (if there is one), the copy/move - // operation from the operand to the exception object (15.1) can be - // omitted by constructing the automatic object directly into the - // exception object - const VarDecl *NRVOVariable = nullptr; - if (IsThrownVarInScope) - NRVOVariable = getCopyElisionCandidate(QualType(), E, false); - - InitializedEntity Entity = - InitializedEntity::InitializeException(ThrowLoc, ExceptionObjectTy, - /*NRVO=*/NRVOVariable != nullptr); - ExprResult Res = PerformMoveOrCopyInitialization( - Entity, NRVOVariable, QualType(), E, IsThrownVarInScope); - if (Res.isInvalid()) - return ExprError(); - E = Res.get(); - // If the exception has class type, we need additional handling. - const RecordType *RecordTy = Ty->getAs(); - if (!RecordTy) - return E; - CXXRecordDecl *RD = cast(RecordTy->getDecl()); + CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + if (!RD) + return false; // If we are throwing a polymorphic class type or pointer thereof, // exception handling will make use of the vtable. @@ -769,7 +767,7 @@ // If a pointer is thrown, the referenced object will not be destroyed. if (isPointer) - return E; + return false; // If the class has a destructor, we must be able to call it. if (!RD->hasIrrelevantDestructor()) { @@ -778,7 +776,7 @@ CheckDestructorAccess(E->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_exception) << Ty); if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) - return ExprError(); + return true; } } @@ -831,7 +829,7 @@ } } - return E; + return false; } QualType Sema::getCurrentThisType() { Index: test/CodeGenCXX/microsoft-abi-throw.cpp =================================================================== --- test/CodeGenCXX/microsoft-abi-throw.cpp +++ test/CodeGenCXX/microsoft-abi-throw.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm -o - -triple=i386-pc-win32 -std=c++11 %s -fcxx-exceptions | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -o - -triple=i386-pc-win32 -std=c++11 %s -fcxx-exceptions -fms-extensions | FileCheck %s // CHECK-DAG: @"\01??_R0?AUY@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUY@@\00" }, comdat // CHECK-DAG: @"_CT??_R0?AUY@@@8??0Y@@QAE@ABU0@@Z8" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 4, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUY@@@8" to i8*), i32 0, i32 -1, i32 0, i32 8, i8* bitcast (%struct.Y* (%struct.Y*, %struct.Y*, i32)* @"\01??0Y@@QAE@ABU0@@Z" to i8*) }, section ".xdata", comdat @@ -87,3 +87,14 @@ void j(TemplateWithDefault &twd) { throw twd; } + +namespace std { +template +void *__GetExceptionInfo(T); +} + +void *GetExceptionInfo_test0() { +// CHECK-LABEL: @"\01?GetExceptionInfo_test0@@YAPAXXZ" +// CHECK: ret i8* bitcast (%eh.ThrowInfo* @_TI1H to i8*) + return std::__GetExceptionInfo(0); +}