diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-06-11 01:09:30 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-06-11 01:09:30 +0000 |
commit | 926df6cfabf3eaa4afc990c097fa4619b76a9b57 (patch) | |
tree | f48a5ca74fa783c76ae30e190d130881fc5febe8 /lib/CodeGen/CGObjC.cpp | |
parent | 45937ae10a0f70f74508165aab4f2b63e18ea747 (diff) |
Implement Objective-C Related Result Type semantics.
Related result types apply Cocoa conventions to the type of message
sends and property accesses to Objective-C methods that are known to
always return objects whose type is the same as the type of the
receiving class (or a subclass thereof), such as +alloc and
-init. This tightens up static type safety for Objective-C, so that we
now diagnose mistakes like this:
t.m:4:10: warning: incompatible pointer types initializing 'NSSet *'
with an
expression of type 'NSArray *' [-Wincompatible-pointer-types]
NSSet *array = [[NSArray alloc] init];
^ ~~~~~~~~~~~~~~~~~~~~~~
/System/Library/Frameworks/Foundation.framework/Headers/NSObject.h:72:1:
note:
instance method 'init' is assumed to return an instance of its
receiver
type ('NSArray *')
- (id)init;
^
It also means that we get decent type inference when writing code in
Objective-C++0x:
auto array = [[NSMutableArray alloc] initWithObjects:@"one", @"two",nil];
// ^ now infers NSMutableArray* rather than id
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132868 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGObjC.cpp')
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 75 |
1 files changed, 52 insertions, 23 deletions
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 28e7e42885..fa42cd1f36 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -47,6 +47,23 @@ llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) { return CGM.getObjCRuntime().GenerateProtocolRef(Builder, E->getProtocol()); } +/// \brief Adjust the type of the result of an Objective-C message send +/// expression when the method has a related result type. +static RValue AdjustRelatedResultType(CodeGenFunction &CGF, + const Expr *E, + const ObjCMethodDecl *Method, + RValue Result) { + if (!Method) + return Result; + if (!Method->hasRelatedResultType() || + CGF.getContext().hasSameType(E->getType(), Method->getResultType()) || + !Result.isScalar()) + return Result; + + // We have applied a related result type. Cast the rvalue appropriately. + return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(), + CGF.ConvertType(E->getType()))); +} RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, ReturnValueSlot Return) { @@ -59,15 +76,17 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, bool isClassMessage = false; ObjCInterfaceDecl *OID = 0; // Find the receiver + QualType ReceiverType; llvm::Value *Receiver = 0; switch (E->getReceiverKind()) { case ObjCMessageExpr::Instance: Receiver = EmitScalarExpr(E->getInstanceReceiver()); + ReceiverType = E->getInstanceReceiver()->getType(); break; case ObjCMessageExpr::Class: { - const ObjCObjectType *ObjTy - = E->getClassReceiver()->getAs<ObjCObjectType>(); + ReceiverType = E->getClassReceiver(); + const ObjCObjectType *ObjTy = ReceiverType->getAs<ObjCObjectType>(); assert(ObjTy && "Invalid Objective-C class message send"); OID = ObjTy->getInterface(); assert(OID && "Invalid Objective-C class message send"); @@ -77,11 +96,13 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, } case ObjCMessageExpr::SuperInstance: + ReceiverType = E->getSuperType(); Receiver = LoadObjCSelf(); isSuperMessage = true; break; case ObjCMessageExpr::SuperClass: + ReceiverType = E->getSuperType(); Receiver = LoadObjCSelf(); isSuperMessage = true; isClassMessage = true; @@ -94,24 +115,27 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, QualType ResultType = E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType(); + RValue result; if (isSuperMessage) { // super is only valid in an Objective-C method const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext()); - return Runtime.GenerateMessageSendSuper(*this, Return, ResultType, - E->getSelector(), - OMD->getClassInterface(), - isCategoryImpl, - Receiver, - isClassMessage, - Args, - E->getMethodDecl()); + result = Runtime.GenerateMessageSendSuper(*this, Return, ResultType, + E->getSelector(), + OMD->getClassInterface(), + isCategoryImpl, + Receiver, + isClassMessage, + Args, + E->getMethodDecl()); + } else { + result = Runtime.GenerateMessageSend(*this, Return, ResultType, + E->getSelector(), + Receiver, Args, OID, + E->getMethodDecl()); } - - return Runtime.GenerateMessageSend(*this, Return, ResultType, - E->getSelector(), - Receiver, Args, OID, - E->getMethodDecl()); + + return AdjustRelatedResultType(*this, E, E->getMethodDecl(), result); } /// StartObjCMethod - Begin emission of an ObjCMethod. This generates @@ -711,26 +735,31 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV, const ObjCPropertyRefExpr *E = LV.getPropertyRefExpr(); QualType ResultType = E->getGetterResultType(); Selector S; + const ObjCMethodDecl *method; if (E->isExplicitProperty()) { const ObjCPropertyDecl *Property = E->getExplicitProperty(); S = Property->getGetterName(); + method = Property->getGetterMethodDecl(); } else { - const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter(); - S = Getter->getSelector(); + method = E->getImplicitPropertyGetter(); + S = method->getSelector(); } llvm::Value *Receiver = LV.getPropertyRefBaseAddr(); // Accesses to 'super' follow a different code path. if (E->isSuperReceiver()) - return GenerateMessageSendSuper(*this, Return, ResultType, - S, Receiver, CallArgList()); - + return AdjustRelatedResultType(*this, E, method, + GenerateMessageSendSuper(*this, Return, + ResultType, + S, Receiver, + CallArgList())); const ObjCInterfaceDecl *ReceiverClass = (E->isClassReceiver() ? E->getClassReceiver() : 0); - return CGM.getObjCRuntime(). - GenerateMessageSend(*this, Return, ResultType, S, - Receiver, CallArgList(), ReceiverClass); + return AdjustRelatedResultType(*this, E, method, + CGM.getObjCRuntime(). + GenerateMessageSend(*this, Return, ResultType, S, + Receiver, CallArgList(), ReceiverClass)); } void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src, |