forked from OSchip/llvm-project
Support catching Objective C pointers in C++ under the non-fragile NeXT runtime.
Diagnose attempts to do this under the GNU or fragile NeXT runtimes. llvm-svn: 109298
This commit is contained in:
parent
72cdffa401
commit
2ca705eb13
|
@ -2266,7 +2266,13 @@ def warn_register_objc_catch_parm : Warning<
|
|||
"'register' storage specifier on @catch parameter will be ignored">;
|
||||
def err_qualified_objc_catch_parm : Error<
|
||||
"@catch parameter declarator cannot be qualified">;
|
||||
|
||||
def err_objc_pointer_cxx_catch_gnu : Error<
|
||||
"can't catch Objective C exceptions in C++ in the GNU runtime">;
|
||||
def err_objc_pointer_cxx_catch_fragile : Error<
|
||||
"can't catch Objective C exceptions in C++ in the non-unified "
|
||||
"exception model">;
|
||||
def err_objc_object_catch : Error<
|
||||
"can't catch an Objective C object by value">;
|
||||
|
||||
def warn_setter_getter_impl_required : Warning<
|
||||
"property %0 requires method %1 to be defined - "
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "llvm/Intrinsics.h"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
|
||||
#include "CGObjCRuntime.h"
|
||||
#include "CodeGenFunction.h"
|
||||
#include "CGException.h"
|
||||
#include "TargetInfo.h"
|
||||
|
@ -617,7 +618,12 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
|
|||
// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388
|
||||
QualType CaughtType = C->getCaughtType();
|
||||
CaughtType = CaughtType.getNonReferenceType().getUnqualifiedType();
|
||||
llvm::Value *TypeInfo = CGM.GetAddrOfRTTIDescriptor(CaughtType, true);
|
||||
|
||||
llvm::Value *TypeInfo = 0;
|
||||
if (CaughtType->isObjCObjectPointerType())
|
||||
TypeInfo = CGM.getObjCRuntime().GetEHType(CaughtType);
|
||||
else
|
||||
TypeInfo = CGM.GetAddrOfRTTIDescriptor(CaughtType, true);
|
||||
CatchScope->setHandler(I, TypeInfo, Handler);
|
||||
} else {
|
||||
// No exception decl indicates '...', a catch-all.
|
||||
|
|
|
@ -167,6 +167,7 @@ public:
|
|||
bool lval = false);
|
||||
virtual llvm::Value *GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
|
||||
*Method);
|
||||
virtual llvm::Constant *GetEHType(QualType T);
|
||||
|
||||
virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
|
||||
const ObjCContainerDecl *CD);
|
||||
|
@ -403,6 +404,11 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
|
|||
return Builder.CreateLoad(Sel);
|
||||
}
|
||||
|
||||
llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
|
||||
llvm_unreachable("asking for catch type for ObjC type in GNU runtime");
|
||||
return 0;
|
||||
}
|
||||
|
||||
llvm::Constant *CGObjCGNU::MakeConstantString(const std::string &Str,
|
||||
const std::string &Name) {
|
||||
llvm::Constant *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str());
|
||||
|
|
|
@ -1184,6 +1184,8 @@ public:
|
|||
virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
|
||||
const ObjCMethodDecl *Method);
|
||||
|
||||
virtual llvm::Constant *GetEHType(QualType T);
|
||||
|
||||
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
|
||||
|
||||
virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
|
||||
|
@ -1354,7 +1356,7 @@ private:
|
|||
|
||||
/// GetInterfaceEHType - Get the cached ehtype for the given Objective-C
|
||||
/// interface. The return value has type EHTypePtrTy.
|
||||
llvm::Value *GetInterfaceEHType(const ObjCInterfaceDecl *ID,
|
||||
llvm::Constant *GetInterfaceEHType(const ObjCInterfaceDecl *ID,
|
||||
bool ForDefinition);
|
||||
|
||||
const char *getMetaclassSymbolPrefix() const {
|
||||
|
@ -1429,6 +1431,8 @@ public:
|
|||
virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
|
||||
const ObjCProtocolDecl *PD);
|
||||
|
||||
virtual llvm::Constant *GetEHType(QualType T);
|
||||
|
||||
virtual llvm::Constant *GetPropertyGetFunction() {
|
||||
return ObjCTypes.getGetPropertyFn();
|
||||
}
|
||||
|
@ -1527,6 +1531,11 @@ llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
|
|||
return EmitSelector(Builder, Method->getSelector());
|
||||
}
|
||||
|
||||
llvm::Constant *CGObjCMac::GetEHType(QualType T) {
|
||||
llvm_unreachable("asking for catch type for ObjC type in fragile runtime");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Generate a constant CFString object.
|
||||
/*
|
||||
struct __builtin_CFString {
|
||||
|
@ -5777,6 +5786,31 @@ namespace {
|
|||
};
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
CGObjCNonFragileABIMac::GetEHType(QualType T) {
|
||||
// There's a particular fixed type info for 'id'.
|
||||
if (T->isObjCIdType() ||
|
||||
T->isObjCQualifiedIdType()) {
|
||||
llvm::Constant *IDEHType =
|
||||
CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
|
||||
if (!IDEHType)
|
||||
IDEHType =
|
||||
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
|
||||
false,
|
||||
llvm::GlobalValue::ExternalLinkage,
|
||||
0, "OBJC_EHTYPE_id");
|
||||
return IDEHType;
|
||||
}
|
||||
|
||||
// All other types should be Objective-C interface pointer types.
|
||||
const ObjCObjectPointerType *PT =
|
||||
T->getAs<ObjCObjectPointerType>();
|
||||
assert(PT && "Invalid @catch type.");
|
||||
const ObjCInterfaceType *IT = PT->getInterfaceType();
|
||||
assert(IT && "Invalid @catch type.");
|
||||
return GetInterfaceEHType(IT->getDecl(), false);
|
||||
}
|
||||
|
||||
void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
|
||||
const ObjCAtTryStmt &S) {
|
||||
// Jump destination for falling out of catch bodies.
|
||||
|
@ -5812,27 +5846,7 @@ void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
|
|||
break;
|
||||
}
|
||||
|
||||
// There's a particular fixed type info for 'id'.
|
||||
if (CatchDecl->getType()->isObjCIdType() ||
|
||||
CatchDecl->getType()->isObjCQualifiedIdType()) {
|
||||
llvm::Value *IDEHType =
|
||||
CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
|
||||
if (!IDEHType)
|
||||
IDEHType =
|
||||
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
|
||||
false,
|
||||
llvm::GlobalValue::ExternalLinkage,
|
||||
0, "OBJC_EHTYPE_id");
|
||||
Handler.TypeInfo = IDEHType;
|
||||
} else {
|
||||
// All other types should be Objective-C interface pointer types.
|
||||
const ObjCObjectPointerType *PT =
|
||||
CatchDecl->getType()->getAs<ObjCObjectPointerType>();
|
||||
assert(PT && "Invalid @catch type.");
|
||||
const ObjCInterfaceType *IT = PT->getInterfaceType();
|
||||
assert(IT && "Invalid @catch type.");
|
||||
Handler.TypeInfo = GetInterfaceEHType(IT->getDecl(), false);
|
||||
}
|
||||
Handler.TypeInfo = GetEHType(CatchDecl->getType());
|
||||
}
|
||||
|
||||
EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size());
|
||||
|
@ -5931,7 +5945,7 @@ void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
|
|||
CGF.Builder.ClearInsertionPoint();
|
||||
}
|
||||
|
||||
llvm::Value *
|
||||
llvm::Constant *
|
||||
CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
|
||||
bool ForDefinition) {
|
||||
llvm::GlobalVariable * &Entry = EHTypeReferences[ID->getIdentifier()];
|
||||
|
|
|
@ -103,6 +103,12 @@ public:
|
|||
virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
|
||||
const ObjCMethodDecl *Method) = 0;
|
||||
|
||||
/// Get the type constant to catch for the given ObjC pointer type.
|
||||
/// This is used externally to implement catching ObjC types in C++.
|
||||
/// Runtimes which don't support this should add the appropriate
|
||||
/// error to Sema.
|
||||
virtual llvm::Constant *GetEHType(QualType T) = 0;
|
||||
|
||||
/// Generate a constant string object.
|
||||
virtual llvm::Constant *GenerateConstantString(const StringLiteral *) = 0;
|
||||
|
||||
|
|
|
@ -5983,6 +5983,27 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
|
|||
AbstractVariableType))
|
||||
Invalid = true;
|
||||
|
||||
// Only the non-fragile NeXT runtime currently supports C++ catches
|
||||
// of ObjC types, and no runtime supports catching ObjC types by value.
|
||||
if (!Invalid && getLangOptions().ObjC1) {
|
||||
QualType T = ExDeclType;
|
||||
if (const ReferenceType *RT = T->getAs<ReferenceType>())
|
||||
T = RT->getPointeeType();
|
||||
|
||||
if (T->isObjCObjectType()) {
|
||||
Diag(Loc, diag::err_objc_object_catch);
|
||||
Invalid = true;
|
||||
} else if (T->isObjCObjectPointerType()) {
|
||||
if (!getLangOptions().NeXTRuntime) {
|
||||
Diag(Loc, diag::err_objc_pointer_cxx_catch_gnu);
|
||||
Invalid = true;
|
||||
} else if (!getLangOptions().ObjCNonFragileABI) {
|
||||
Diag(Loc, diag::err_objc_pointer_cxx_catch_fragile);
|
||||
Invalid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc,
|
||||
Name, ExDeclType, TInfo, VarDecl::None,
|
||||
VarDecl::None);
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fexceptions -o - %s | FileCheck %s
|
||||
|
||||
@interface OCType @end
|
||||
void opaque();
|
||||
|
||||
namespace test0 {
|
||||
|
||||
// CHECK: define void @_ZN5test03fooEv
|
||||
void foo() {
|
||||
try {
|
||||
// CHECK: invoke void @_Z6opaquev
|
||||
opaque();
|
||||
} catch (OCType *T) {
|
||||
// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} @__objc_personality_v0 {{.*}} @"OBJC_EHTYPE_$_OCType"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
@interface NSException @end
|
||||
void opaque();
|
||||
|
||||
namespace test0 {
|
||||
void test() {
|
||||
try {
|
||||
} catch (NSException *e) { // expected-error {{can't catch Objective C exceptions in C++ in the non-unified exception model}}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue