diff options
author | John McCall <rjmccall@apple.com> | 2011-07-22 08:53:00 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-07-22 08:53:00 +0000 |
commit | dc7c5ad7a15914b7ae24f31f18a20ad2f8ecd0bc (patch) | |
tree | 23cf6002f7ceff79c1c2eedeb9e3371ad4734800 /lib | |
parent | 159a7b3c531d09d98176699f212928da9bed8602 (diff) |
Document the existing objc_precise_lifetime attribute.
Introduce and document a new objc_returns_inner_pointer
attribute, and consume it by performing a retain+autorelease
on message receivers when they're not immediately loaded from
an object with precise lifetime.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135764 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 86 | ||||
-rw-r--r-- | lib/Sema/AttributeList.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 30 |
3 files changed, 99 insertions, 18 deletions
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index fd686cc6a0..8e3532659d 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -80,6 +80,53 @@ static RValue AdjustRelatedResultType(CodeGenFunction &CGF, CGF.ConvertType(E->getType()))); } +/// Decide whether to extend the lifetime of the receiver of a +/// returns-inner-pointer message. +static bool +shouldExtendReceiverForInnerPointerMessage(const ObjCMessageExpr *message) { + switch (message->getReceiverKind()) { + + // For a normal instance message, we should extend unless the + // receiver is loaded from a variable with precise lifetime. + case ObjCMessageExpr::Instance: { + const Expr *receiver = message->getInstanceReceiver(); + const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(receiver); + if (!ice || ice->getCastKind() != CK_LValueToRValue) return true; + receiver = ice->getSubExpr()->IgnoreParens(); + + // Only __strong variables. + if (receiver->getType().getObjCLifetime() != Qualifiers::OCL_Strong) + return true; + + // All ivars and fields have precise lifetime. + if (isa<MemberExpr>(receiver) || isa<ObjCIvarRefExpr>(receiver)) + return false; + + // Otherwise, check for variables. + const DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(ice->getSubExpr()); + if (!declRef) return true; + const VarDecl *var = dyn_cast<VarDecl>(declRef->getDecl()); + if (!var) return true; + + // All variables have precise lifetime except local variables with + // automatic storage duration that aren't specially marked. + return (var->hasLocalStorage() && + !var->hasAttr<ObjCPreciseLifetimeAttr>()); + } + + case ObjCMessageExpr::Class: + case ObjCMessageExpr::SuperClass: + // It's never necessary for class objects. + return false; + + case ObjCMessageExpr::SuperInstance: + // We generally assume that 'self' lives throughout a method call. + return false; + } + + llvm_unreachable("invalid receiver kind"); +} + RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, ReturnValueSlot Return) { // Only the lookup mechanism and first two arguments of the method @@ -88,6 +135,8 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, bool isDelegateInit = E->isDelegateInitCall(); + const ObjCMethodDecl *method = E->getMethodDecl(); + // We don't retain the receiver in delegate init calls, and this is // safe because the receiver value is always loaded from 'self', // which we zero out. We don't want to Block_copy block receivers, @@ -95,8 +144,8 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, bool retainSelf = (!isDelegateInit && CGM.getLangOptions().ObjCAutoRefCount && - E->getMethodDecl() && - E->getMethodDecl()->hasAttr<NSConsumesSelfAttr>()); + method && + method->hasAttr<NSConsumesSelfAttr>()); CGObjCRuntime &Runtime = CGM.getObjCRuntime(); bool isSuperMessage = false; @@ -112,8 +161,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, TryEmitResult ter = tryEmitARCRetainScalarExpr(*this, E->getInstanceReceiver()); Receiver = ter.getPointer(); - if (!ter.getInt()) - Receiver = EmitARCRetainNonBlock(Receiver); + if (ter.getInt()) retainSelf = false; } else Receiver = EmitScalarExpr(E->getInstanceReceiver()); break; @@ -126,9 +174,6 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, assert(OID && "Invalid Objective-C class message send"); Receiver = Runtime.GetClass(Builder, OID); isClassMessage = true; - - if (retainSelf) - Receiver = EmitARCRetainNonBlock(Receiver); break; } @@ -136,9 +181,6 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, ReceiverType = E->getSuperType(); Receiver = LoadObjCSelf(); isSuperMessage = true; - - if (retainSelf) - Receiver = EmitARCRetainNonBlock(Receiver); break; case ObjCMessageExpr::SuperClass: @@ -146,17 +188,25 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, Receiver = LoadObjCSelf(); isSuperMessage = true; isClassMessage = true; - - if (retainSelf) - Receiver = EmitARCRetainNonBlock(Receiver); break; } + if (retainSelf) + Receiver = EmitARCRetainNonBlock(Receiver); + + // In ARC, we sometimes want to "extend the lifetime" + // (i.e. retain+autorelease) of receivers of returns-inner-pointer + // messages. + if (getLangOptions().ObjCAutoRefCount && method && + method->hasAttr<ObjCReturnsInnerPointerAttr>() && + shouldExtendReceiverForInnerPointerMessage(E)) + Receiver = EmitARCRetainAutorelease(ReceiverType, Receiver); + QualType ResultType = - E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType(); + method ? method->getResultType() : E->getType(); CallArgList Args; - EmitCallArgs(Args, E->getMethodDecl(), E->arg_begin(), E->arg_end()); + EmitCallArgs(Args, method, E->arg_begin(), E->arg_end()); // For delegate init calls in ARC, do an unsafe store of null into // self. This represents the call taking direct ownership of that @@ -189,12 +239,12 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, Receiver, isClassMessage, Args, - E->getMethodDecl()); + method); } else { result = Runtime.GenerateMessageSend(*this, Return, ResultType, E->getSelector(), Receiver, Args, OID, - E->getMethodDecl()); + method); } // For delegate init calls in ARC, implicitly store the result of @@ -213,7 +263,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, Builder.CreateStore(newSelf, selfAddr); } - return AdjustRelatedResultType(*this, E, E->getMethodDecl(), result); + return AdjustRelatedResultType(*this, E, method, result); } namespace { diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index 5a8330bbfd..21068538e8 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -163,6 +163,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("vec_type_hint", IgnoredAttribute) .Case("objc_exception", AT_objc_exception) .Case("objc_method_family", AT_objc_method_family) + .Case("objc_returns_inner_pointer", AT_objc_returns_inner_pointer) .Case("ext_vector_type", AT_ext_vector_type) .Case("neon_vector_type", AT_neon_vector_type) .Case("neon_polyvector_type", AT_neon_polyvector_type) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 61b7b3ee05..ad9b6ddba9 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -2767,6 +2767,33 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, }; } +static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, + const AttributeList &attr) { + SourceLocation loc = attr.getLoc(); + + ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D); + + if (!isa<ObjCMethodDecl>(method)) { + S.Diag(method->getLocStart(), diag::err_attribute_wrong_decl_type) + << SourceRange(loc, loc) << attr.getName() << 13 /* methods */; + return; + } + + // Check that the method returns a normal pointer. + QualType resultType = method->getResultType(); + if (!resultType->isPointerType() || resultType->isObjCRetainableType()) { + S.Diag(method->getLocStart(), diag::warn_ns_attribute_wrong_return_type) + << SourceRange(loc) + << attr.getName() << /*method*/ 1 << /*non-retainable pointer*/ 2; + + // Drop the attribute. + return; + } + + method->addAttr( + ::new (S.Context) ObjCReturnsInnerPointerAttr(loc, S.Context)); +} + static void handleObjCOwnershipAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (hasDeclarator(D)) return; @@ -2969,6 +2996,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_objc_precise_lifetime: handleObjCPreciseLifetimeAttr(S, D, Attr); break; + case AttributeList::AT_objc_returns_inner_pointer: + handleObjCReturnsInnerPointerAttr(S, D, Attr); break; + // Checker-specific. case AttributeList::AT_cf_consumed: case AttributeList::AT_ns_consumed: handleNSConsumedAttr (S, D, Attr); break; |