diff options
author | John McCall <rjmccall@apple.com> | 2011-09-10 01:16:55 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-09-10 01:16:55 +0000 |
commit | cd78e805e9c0d1a1b7ccbb67773aa51589c040f7 (patch) | |
tree | 0d46a178933812aaad4d14ba3d3449b2397061fb /clang/lib | |
parent | a51d74fc35aafa7c609e950cfc6e39146a8280cb (diff) | |
download | bcm5719-llvm-cd78e805e9c0d1a1b7ccbb67773aa51589c040f7.tar.gz bcm5719-llvm-cd78e805e9c0d1a1b7ccbb67773aa51589c040f7.zip |
When converting a block pointer to an Objective-C pointer type, extend
the lifetime of the block by copying it to the heap, or else we'll get
a dangling reference because the code working with the non-block-typed
object will not know it needs to copy.
There is some danger here, e.g. with assigning a block literal to an
unsafe variable, but, well, it's an unsafe variable.
llvm-svn: 139451
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/Expr.cpp | 3 | ||||
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprAgg.cpp | 1 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprComplex.cpp | 1 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprConstant.cpp | 1 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprScalar.cpp | 6 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGObjC.cpp | 70 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCXXCast.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 34 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 9 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 3 |
12 files changed, 130 insertions, 11 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 25e7de77fbd..63642b216fe 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1079,6 +1079,7 @@ void CastExpr::CheckCastConsistency() const { case CK_ObjCProduceObject: case CK_ObjCConsumeObject: case CK_ObjCReclaimReturnedObject: + case CK_ObjCExtendBlockObject: assert(!getType()->isBooleanType() && "unheralded conversion to bool"); goto CheckNoBasePath; @@ -1198,6 +1199,8 @@ const char *CastExpr::getCastKindName() const { return "ObjCProduceObject"; case CK_ObjCReclaimReturnedObject: return "ObjCReclaimReturnedObject"; + case CK_ObjCExtendBlockObject: + return "ObjCExtendBlockObject"; } llvm_unreachable("Unhandled cast kind!"); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index eb35dd7c989..7ae41864231 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1830,6 +1830,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_ObjCProduceObject: case CK_ObjCConsumeObject: case CK_ObjCReclaimReturnedObject: + case CK_ObjCExtendBlockObject: return false; case CK_LValueToRValue: @@ -2338,6 +2339,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_ObjCProduceObject: case CK_ObjCConsumeObject: case CK_ObjCReclaimReturnedObject: + case CK_ObjCExtendBlockObject: llvm_unreachable("invalid cast kind for complex value"); case CK_LValueToRValue: diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 7ae95331ad5..520b1bbfb8a 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2061,7 +2061,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_AnyPointerToBlockPointerCast: case CK_ObjCProduceObject: case CK_ObjCConsumeObject: - case CK_ObjCReclaimReturnedObject: { + case CK_ObjCReclaimReturnedObject: + case CK_ObjCExtendBlockObject: { // These casts only produce lvalues when we're binding a reference to a // temporary realized from a (converted) pure rvalue. Emit the expression // as a value, copy it into a temporary, and return an lvalue referring to diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index fe6dfcd28fd..93c7bd8af6f 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -382,6 +382,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CK_ObjCProduceObject: case CK_ObjCConsumeObject: case CK_ObjCReclaimReturnedObject: + case CK_ObjCExtendBlockObject: llvm_unreachable("cast kind invalid for aggregate types"); } } diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index 90e288a4508..326fcfa15bf 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -414,6 +414,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op, case CK_ObjCProduceObject: case CK_ObjCConsumeObject: case CK_ObjCReclaimReturnedObject: + case CK_ObjCExtendBlockObject: llvm_unreachable("invalid cast kind for complex value"); case CK_FloatingRealToComplex: diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index b51ff386562..7ab77709e03 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -589,6 +589,7 @@ public: case CK_ObjCProduceObject: case CK_ObjCConsumeObject: case CK_ObjCReclaimReturnedObject: + case CK_ObjCExtendBlockObject: return 0; // These might need to be supported for constexpr. diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 35876d8c319..6741f433660 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1027,7 +1027,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { ConvertType(CGF.getContext().getPointerType(DestTy))); return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy)); } - + case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: @@ -1124,6 +1124,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { value = CGF.EmitARCRetainAutoreleasedReturnValue(value); return CGF.EmitObjCConsumeObject(E->getType(), value); } + case CK_ObjCExtendBlockObject: { + llvm::Value *value = CGF.EmitARCRetainScalarExpr(E); + return CGF.EmitObjCConsumeObject(E->getType(), value); + } case CK_FloatingRealToComplex: case CK_FloatingComplexCast: diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 17ace4fc1ac..037eed04305 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -1959,6 +1959,42 @@ static llvm::Value *emitARCRetainAfterCall(CodeGenFunction &CGF, } } +/// Determine whether it might be important to emit a separate +/// objc_retain_block on the result of the given expression, or +/// whether it's okay to just emit it in a +1 context. +static bool shouldEmitSeparateBlockRetain(const Expr *e) { + assert(e->getType()->isBlockPointerType()); + e = e->IgnoreParens(); + + // For future goodness, emit block expressions directly in +1 + // contexts if we can. + if (isa<BlockExpr>(e)) + return false; + + if (const CastExpr *cast = dyn_cast<CastExpr>(e)) { + switch (cast->getCastKind()) { + // Emitting these operations in +1 contexts is goodness. + case CK_LValueToRValue: + case CK_ObjCReclaimReturnedObject: + case CK_ObjCConsumeObject: + case CK_ObjCProduceObject: + return false; + + // These operations preserve a block type. + case CK_NoOp: + case CK_BitCast: + return shouldEmitSeparateBlockRetain(cast->getSubExpr()); + + // These operations are known to be bad (or haven't been considered). + case CK_AnyPointerToBlockPointerCast: + default: + return true; + } + } + + return true; +} + static TryEmitResult tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) { // Look through cleanups. @@ -2015,6 +2051,40 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) { return TryEmitResult(result, true); } + // Block extends are net +0. Naively, we could just recurse on + // the subexpression, but actually we need to ensure that the + // value is copied as a block, so there's a little filter here. + case CK_ObjCExtendBlockObject: { + llvm::Value *result; // will be a +0 value + + // If we can't safely assume the sub-expression will produce a + // block-copied value, emit the sub-expression at +0. + if (shouldEmitSeparateBlockRetain(ce->getSubExpr())) { + result = CGF.EmitScalarExpr(ce->getSubExpr()); + + // Otherwise, try to emit the sub-expression at +1 recursively. + } else { + TryEmitResult subresult + = tryEmitARCRetainScalarExpr(CGF, ce->getSubExpr()); + result = subresult.getPointer(); + + // If that produced a retained value, just use that, + // possibly casting down. + if (subresult.getInt()) { + if (resultType) + result = CGF.Builder.CreateBitCast(result, resultType); + return TryEmitResult(result, true); + } + + // Otherwise it's +0. + } + + // Retain the object as a block, then cast down. + result = CGF.EmitARCRetainBlock(result); + if (resultType) result = CGF.Builder.CreateBitCast(result, resultType); + return TryEmitResult(result, true); + } + // For reclaims, emit the subexpression as a retained call and // skip the consumption. case CK_ObjCReclaimReturnedObject: { diff --git a/clang/lib/Sema/SemaCXXCast.cpp b/clang/lib/Sema/SemaCXXCast.cpp index 48f022063ad..46f71be0601 100644 --- a/clang/lib/Sema/SemaCXXCast.cpp +++ b/clang/lib/Sema/SemaCXXCast.cpp @@ -1633,13 +1633,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, if (IsLValueCast) { Kind = CK_LValueBitCast; } else if (DestType->isObjCObjectPointerType()) { - if (SrcType->isObjCObjectPointerType()) { - Kind = CK_BitCast; - } else if (SrcType->isBlockPointerType()) { - Kind = CK_BlockPointerToObjCPointerCast; - } else { - Kind = CK_CPointerToObjCPointerCast; - } + Kind = Self.PrepareCastToObjCObjectPointer(SrcExpr); } else if (DestType->isBlockPointerType()) { if (!SrcType->isBlockPointerType()) { Kind = CK_AnyPointerToBlockPointerCast; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 75e03c131fe..ab699e8c8a8 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3783,6 +3783,35 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, return Owned(E); } +/// Do an explicit extend of the given block pointer if we're in ARC. +static void maybeExtendBlockObject(Sema &S, ExprResult &E) { + assert(E.get()->getType()->isBlockPointerType()); + assert(E.get()->isRValue()); + + // Only do this in an r-value context. + if (!S.getLangOptions().ObjCAutoRefCount) return; + + E = ImplicitCastExpr::Create(S.Context, E.get()->getType(), + CK_ObjCExtendBlockObject, E.get(), + /*base path*/ 0, VK_RValue); + S.ExprNeedsCleanups = true; +} + +/// Prepare a conversion of the given expression to an ObjC object +/// pointer type. +CastKind Sema::PrepareCastToObjCObjectPointer(ExprResult &E) { + QualType type = E.get()->getType(); + if (type->isObjCObjectPointerType()) { + return CK_BitCast; + } else if (type->isBlockPointerType()) { + maybeExtendBlockObject(*this, E); + return CK_BlockPointerToObjCPointerCast; + } else { + assert(type->isPointerType()); + return CK_CPointerToObjCPointerCast; + } +} + /// Prepares for a scalar cast, performing all the necessary stages /// except the final cast and returning the kind required. static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { @@ -3812,8 +3841,10 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { return CK_BitCast; else if (SrcKind == Type::STK_CPointer) return CK_CPointerToObjCPointerCast; - else + else { + maybeExtendBlockObject(S, Src); return CK_BlockPointerToObjCPointerCast; + } case Type::STK_Bool: return CK_PointerToBoolean; case Type::STK_Integral: @@ -5458,6 +5489,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, // T^ -> A* if (RHSType->isBlockPointerType()) { + maybeExtendBlockObject(*this, RHS); Kind = CK_BlockPointerToObjCPointerCast; return Compatible; } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 1d903379c01..b8b722503a6 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -2388,6 +2388,15 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, CXXCastPath BasePath; if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) return ExprError(); + + // Make sure we extend blocks if necessary. + // FIXME: doing this here is really ugly. + if (Kind == CK_BlockPointerToObjCPointerCast) { + ExprResult E = From; + (void) PrepareCastToObjCObjectPointer(E); + From = E.take(); + } + From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) .take(); break; diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 1d7cd0d53f6..db4dc2f2fec 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -213,7 +213,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, // since it understands retain/release semantics already. case CK_ObjCProduceObject: case CK_ObjCConsumeObject: - case CK_ObjCReclaimReturnedObject: // Fall-through. + case CK_ObjCReclaimReturnedObject: + case CK_ObjCExtendBlockObject: // Fall-through. // True no-ops. case CK_NoOp: case CK_FunctionToPointerDecay: { |