diff options
author | John McCall <rjmccall@apple.com> | 2011-10-17 18:40:02 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-10-17 18:40:02 +0000 |
commit | 5acb0c98b363400f6ade0ae7250f0102224e806b (patch) | |
tree | 2ae3fbf8345dac9706834b7e51f017e952e13490 | |
parent | 0ddaeb9b031070ec64afe92d9892875ac44df427 (diff) |
Teach the ARC compiler to not require __bridge casts when
passing/receiving CF objects at +0 to/from Objective-C methods
or audited C functions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142219 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 5 | ||||
-rw-r--r-- | include/clang/Sema/Initialization.h | 5 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 10 | ||||
-rw-r--r-- | lib/Sema/SemaCast.cpp | 94 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 82 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 263 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 158 | ||||
-rw-r--r-- | test/ARCMT/checking.m | 10 | ||||
-rw-r--r-- | test/ARCMT/nonobjc-to-objc-cast-2.m | 2 | ||||
-rw-r--r-- | test/CXX/over/over.over/p2-resolve-single-template-id.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/addr-of-overloaded-function.cpp | 3 | ||||
-rw-r--r-- | test/SemaCXX/member-pointer.cpp | 2 | ||||
-rw-r--r-- | test/SemaCXX/overloaded-name.cpp | 5 | ||||
-rw-r--r-- | test/SemaCXX/overloaded-operator.cpp | 2 | ||||
-rw-r--r-- | test/SemaCXX/unknown-anytype.cpp | 4 | ||||
-rw-r--r-- | test/SemaObjC/arc-type-conversion.m | 11 | ||||
-rw-r--r-- | test/SemaObjC/arc-unbridged-cast.m | 47 | ||||
-rw-r--r-- | test/SemaObjC/arc.m | 4 | ||||
-rw-r--r-- | test/SemaObjCXX/arc-type-conversion.mm | 5 | ||||
-rw-r--r-- | test/SemaObjCXX/arc-unbridged-cast.mm | 106 |
21 files changed, 645 insertions, 200 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 33175a29e5..9590debd74 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3053,8 +3053,9 @@ def err_arc_bridge_cast_wrong_kind : Error< "%select{Objective-C|block|C}2 pointer type %3 cannot use %select{__bridge|" "__bridge_transfer|__bridge_retained}4">; def err_arc_cast_requires_bridge : Error< - "cast of %select{Objective-C|block|C}0 pointer type %1 to " - "%select{Objective-C|block|C}2 pointer type %3 requires a bridged cast">; + "%select{cast|implicit conversion}0 of %select{Objective-C|block|C}1 " + "pointer type %2 to %select{Objective-C|block|C}3 pointer type %4 " + "requires a bridged cast">; def note_arc_bridge : Note< "use __bridge to convert directly (no change in ownership)">; def note_arc_bridge_transfer : Note< diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index e69bebd56c..13eae181e4 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -642,7 +642,10 @@ public: /// \brief Initialization of an incomplete type. FK_Incomplete, /// \brief List initialization failed at some point. - FK_ListInitializationFailed + FK_ListInitializationFailed, + /// \brief Initializer has a placeholder type which cannot be + /// resolved by initialization. + FK_PlaceholderType }; private: diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 4f244db737..1b1e07abbf 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -5794,10 +5794,16 @@ public: Expr *CastExpr, SourceLocation RParenLoc); + enum ARCConversionResult { ACR_okay, ACR_unbridged }; + /// \brief Checks for invalid conversions and casts between /// retainable pointers and other pointer kinds. - void CheckObjCARCConversion(SourceRange castRange, QualType castType, - Expr *&op, CheckedConversionKind CCK); + ARCConversionResult CheckObjCARCConversion(SourceRange castRange, + QualType castType, Expr *&op, + CheckedConversionKind CCK); + + Expr *stripARCUnbridgedCast(Expr *e); + void diagnoseARCUnbridgedCast(Expr *e); bool CheckObjCARCUnavailableWeakConversion(QualType castType, QualType ExprType); diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index b20732a5f7..925f468cfd 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -49,7 +49,7 @@ namespace { : Self(S), SrcExpr(src), DestType(destType), ResultType(destType.getNonLValueExprType(S.Context)), ValueKind(Expr::getValueKindForType(destType)), - Kind(CK_Dependent) { + Kind(CK_Dependent), IsARCUnbridgedCast(false) { if (const BuiltinType *placeholder = src.get()->getType()->getAsPlaceholderType()) { @@ -67,6 +67,7 @@ namespace { CastKind Kind; BuiltinType::Kind PlaceholderKind; CXXCastPath BasePath; + bool IsARCUnbridgedCast; SourceRange OpRange; SourceRange DestRange; @@ -79,6 +80,20 @@ namespace { void CheckCXXCStyleCast(bool FunctionalCast); void CheckCStyleCast(); + /// Complete an apparently-successful cast operation that yields + /// the given expression. + ExprResult complete(CastExpr *castExpr) { + // If this is an unbridged cast, wrap the result in an implicit + // cast that yields the unbridged-cast placeholder type. + if (IsARCUnbridgedCast) { + castExpr = ImplicitCastExpr::Create(Self.Context, + Self.Context.ARCUnbridgedCastTy, + CK_Dependent, castExpr, 0, + castExpr->getValueKind()); + } + return Self.Owned(castExpr); + } + // Internal convenience methods. /// Try to handle the given placeholder expression kind. Return @@ -103,8 +118,12 @@ namespace { } void checkObjCARCConversion(Sema::CheckedConversionKind CCK) { + assert(Self.getLangOptions().ObjCAutoRefCount); + Expr *src = SrcExpr.get(); - Self.CheckObjCARCConversion(OpRange, DestType, src, CCK); + if (Self.CheckObjCARCConversion(OpRange, DestType, src, CCK) == + Sema::ACR_unbridged) + IsARCUnbridgedCast = true; SrcExpr = src; } @@ -237,9 +256,9 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXConstCastExpr::Create(Context, Op.ResultType, Op.ValueKind, - Op.SrcExpr.take(), DestTInfo, OpLoc, - Parens.getEnd())); + return Op.complete(CXXConstCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, Op.SrcExpr.take(), DestTInfo, + OpLoc, Parens.getEnd())); case tok::kw_dynamic_cast: { if (!TypeDependent) { @@ -247,10 +266,10 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXDynamicCastExpr::Create(Context, Op.ResultType, - Op.ValueKind, Op.Kind, - Op.SrcExpr.take(), &Op.BasePath, - DestTInfo, OpLoc, Parens.getEnd())); + return Op.complete(CXXDynamicCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, Op.Kind, Op.SrcExpr.take(), + &Op.BasePath, DestTInfo, + OpLoc, Parens.getEnd())); } case tok::kw_reinterpret_cast: { if (!TypeDependent) { @@ -258,11 +277,10 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXReinterpretCastExpr::Create(Context, Op.ResultType, - Op.ValueKind, Op.Kind, - Op.SrcExpr.take(), 0, - DestTInfo, OpLoc, - Parens.getEnd())); + return Op.complete(CXXReinterpretCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, Op.Kind, Op.SrcExpr.take(), + 0, DestTInfo, OpLoc, + Parens.getEnd())); } case tok::kw_static_cast: { if (!TypeDependent) { @@ -271,10 +289,10 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, return ExprError(); } - return Owned(CXXStaticCastExpr::Create(Context, Op.ResultType, Op.ValueKind, - Op.Kind, Op.SrcExpr.take(), - &Op.BasePath, DestTInfo, OpLoc, - Parens.getEnd())); + return Op.complete(CXXStaticCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, Op.Kind, Op.SrcExpr.take(), + &Op.BasePath, DestTInfo, + OpLoc, Parens.getEnd())); } } @@ -1841,24 +1859,13 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle) { void CastOperation::CheckCStyleCast() { assert(!Self.getLangOptions().CPlusPlus); - // Handle placeholders. - if (isPlaceholder()) { - // C-style casts can resolve __unknown_any types. - if (claimPlaceholder(BuiltinType::UnknownAny)) { - SrcExpr = Self.checkUnknownAnyCast(DestRange, DestType, - SrcExpr.get(), Kind, - ValueKind, BasePath); - return; - } - - // We allow overloads in C, but we don't allow them to be resolved - // by anything except calls. - SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take()); - if (SrcExpr.isInvalid()) - return; - } - - assert(!isPlaceholder()); + // C-style casts can resolve __unknown_any types. + if (claimPlaceholder(BuiltinType::UnknownAny)) { + SrcExpr = Self.checkUnknownAnyCast(DestRange, DestType, + SrcExpr.get(), Kind, + ValueKind, BasePath); + return; + } // C99 6.5.4p2: the cast type needs to be void or scalar and the expression // type needs to be scalar. @@ -1877,6 +1884,7 @@ void CastOperation::CheckCStyleCast() { if (SrcExpr.isInvalid()) return; QualType SrcType = SrcExpr.get()->getType(); + assert(!SrcType->isPlaceholderType()); if (Self.RequireCompleteType(OpRange.getBegin(), DestType, diag::err_typecheck_cast_to_incomplete)) { @@ -2044,9 +2052,9 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, if (Op.SrcExpr.isInvalid()) return ExprError(); - return Owned(CStyleCastExpr::Create(Context, Op.ResultType, Op.ValueKind, - Op.Kind, Op.SrcExpr.take(), &Op.BasePath, - CastTypeInfo, LPLoc, RPLoc)); + return Op.complete(CStyleCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, Op.Kind, Op.SrcExpr.take(), + &Op.BasePath, CastTypeInfo, LPLoc, RPLoc)); } ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, @@ -2061,9 +2069,7 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, if (Op.SrcExpr.isInvalid()) return ExprError(); - return Owned(CXXFunctionalCastExpr::Create(Context, Op.ResultType, - Op.ValueKind, CastTypeInfo, - Op.DestRange.getBegin(), - Op.Kind, Op.SrcExpr.take(), - &Op.BasePath, RPLoc)); + return Op.complete(CXXFunctionalCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, CastTypeInfo, Op.DestRange.getBegin(), + Op.Kind, Op.SrcExpr.take(), &Op.BasePath, RPLoc)); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index ddcbb6d6b1..6376f1f2d9 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -520,11 +520,23 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) { /// interfaces passed by value. ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, FunctionDecl *FDecl) { - ExprResult ExprRes = CheckPlaceholderExpr(E); - if (ExprRes.isInvalid()) - return ExprError(); + if (const BuiltinType *PlaceholderTy = E->getType()->getAsPlaceholderType()) { + // Strip the unbridged-cast placeholder expression off, if applicable. + if (PlaceholderTy->getKind() == BuiltinType::ARCUnbridgedCast && + (CT == VariadicMethod || + (FDecl && FDecl->hasAttr<CFAuditedTransferAttr>()))) { + E = stripARCUnbridgedCast(E); + + // Otherwise, do normal placeholder checking. + } else { + ExprResult ExprRes = CheckPlaceholderExpr(E); + if (ExprRes.isInvalid()) + return ExprError(); + E = ExprRes.take(); + } + } - ExprRes = DefaultArgumentPromotion(E); + ExprResult ExprRes = DefaultArgumentPromotion(E); if (ExprRes.isInvalid()) return ExprError(); E = ExprRes.take(); @@ -3421,6 +3433,12 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, if (FDecl && i < FDecl->getNumParams()) Param = FDecl->getParamDecl(i); + // Strip the unbridged-cast placeholder expression off, if applicable. + if (Arg->getType() == Context.ARCUnbridgedCastTy && + FDecl && FDecl->hasAttr<CFAuditedTransferAttr>() && + (!Param || !Param->hasAttr<CFConsumedAttr>())) + Arg = stripARCUnbridgedCast(Arg); + InitializedEntity Entity = Param? InitializedEntity::InitializeParameter(Context, Param) : InitializedEntity::InitializeParameter(Context, ProtoArgType, @@ -10029,11 +10047,13 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) { /// Check for operands with placeholder types and complain if found. /// Returns true if there was an error and no recovery was possible. ExprResult Sema::CheckPlaceholderExpr(Expr *E) { - // Placeholder types are always *exactly* the appropriate builtin type. - QualType type = E->getType(); + const BuiltinType *placeholderType = E->getType()->getAsPlaceholderType(); + if (!placeholderType) return Owned(E); + + switch (placeholderType->getKind()) { // Overloaded expressions. - if (type == Context.OverloadTy) { + case BuiltinType::Overload: { // Try to resolve a single function template specialization. // This is obligatory. ExprResult result = Owned(E); @@ -10049,19 +10069,57 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { } // Bound member functions. - if (type == Context.BoundMemberTy) { + case BuiltinType::BoundMember: { ExprResult result = Owned(E); tryToRecoverWithCall(result, PDiag(diag::err_bound_member_function), /*complain*/ true); return result; - } + } + + // ARC unbridged casts. + case BuiltinType::ARCUnbridgedCast: { + Expr *realCast = stripARCUnbridgedCast(E); + diagnoseARCUnbridgedCast(realCast); + return Owned(realCast); + } // Expressions of unknown type. - if (type == Context.UnknownAnyTy) + case BuiltinType::UnknownAny: return diagnoseUnknownAnyExpr(*this, E); - assert(!type->isPlaceholderType()); - return Owned(E); + // Everything else should be impossible. TODO: metaprogram this. + case BuiltinType::Void: + case BuiltinType::Bool: + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::WChar_U: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::UShort: + case BuiltinType::UInt: + case BuiltinType::ULong: + case BuiltinType::ULongLong: + case BuiltinType::UInt128: + case BuiltinType::Char_S: + case BuiltinType::SChar: + case BuiltinType::WChar_S: + case BuiltinType::Short: + case BuiltinType::Int: + case BuiltinType::Long: + case BuiltinType::LongLong: + case BuiltinType::Int128: + case BuiltinType::Float: + case BuiltinType::Double: + case BuiltinType::LongDouble: + case BuiltinType::NullPtr: + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + case BuiltinType::Dependent: + break; + } + + llvm_unreachable("invalid placeholder type!"); } bool Sema::CheckCaseExpression(Expr *E) { diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index a23ba4921c..cc9e8b3758 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -409,17 +409,23 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, Expr *argExpr = Args[i]; - ParmVarDecl *Param = Method->param_begin()[i]; + ParmVarDecl *param = Method->param_begin()[i]; assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); + // Strip the unbridged-cast placeholder expression off unless it's + // a consumed argument. + if (argExpr->hasPlaceholderType(BuiltinType::ARCUnbridgedCast) && + !param->hasAttr<CFConsumedAttr>()) + argExpr = stripARCUnbridgedCast(argExpr); + if (RequireCompleteType(argExpr->getSourceRange().getBegin(), - Param->getType(), + param->getType(), PDiag(diag::err_call_incomplete_argument) << argExpr->getSourceRange())) return true; InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, - Param); + param); ExprResult ArgE = PerformCopyInitialization(Entity, lbrac, Owned(argExpr)); if (ArgE.isInvalid()) IsError = true; @@ -1213,6 +1219,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // If we have a receiver expression, perform appropriate promotions // and determine receiver type. if (Receiver) { + if (Receiver->hasPlaceholderType()) { + ExprResult result = CheckPlaceholderExpr(Receiver); + if (result.isInvalid()) return ExprError(); + Receiver = result.take(); + } + if (Receiver->isTypeDependent()) { // If the receiver is type-dependent, we can't type-check anything // at this point. Build a dependent expression. @@ -1836,7 +1848,90 @@ namespace { }; } -void +static void +diagnoseObjCARCConversion(Sema &S, SourceRange castRange, + QualType castType, ARCConversionTypeClass castACTC, + Expr *castExpr, ARCConversionTypeClass exprACTC, + Sema::CheckedConversionKind CCK) { + SourceLocation loc = + (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc()); + + if (S.makeUnavailableInSystemHeader(loc, + "converts between Objective-C and C pointers in -fobjc-arc")) + return; + + QualType castExprType = castExpr->getType(); + + unsigned srcKind = 0; + switch (exprACTC) { + case ACTC_none: + case ACTC_coreFoundation: + case ACTC_voidPtr: + srcKind = (castExprType->isPointerType() ? 1 : 0); + break; + case ACTC_retainable: + srcKind = (castExprType->isBlockPointerType() ? 2 : 3); + break; + case ACTC_indirectRetainable: + srcKind = 4; + break; + } + + // Check whether this could be fixed with a bridge cast. + SourceLocation afterLParen = S.PP.getLocForEndOfToken(castRange.getBegin()); + SourceLocation noteLoc = afterLParen.isValid() ? afterLParen : loc; + + // Bridge from an ARC type to a CF type. + if (castACTC == ACTC_retainable && isAnyRetainable(exprACTC)) { + S.Diag(loc, diag::err_arc_cast_requires_bridge) + << unsigned(CCK == Sema::CCK_ImplicitConversion) // cast|implicit + << 2 // of C pointer type + << castExprType + << unsigned(castType->isBlockPointerType()) // to ObjC|block type + << castType + << castRange + << castExpr->getSourceRange(); + + S.Diag(noteLoc, diag::note_arc_bridge) + << (CCK != Sema::CCK_CStyleCast ? FixItHint() : + FixItHint::CreateInsertion(afterLParen, "__bridge ")); + S.Diag(noteLoc, diag::note_arc_bridge_transfer) + << castExprType + << (CCK != Sema::CCK_CStyleCast ? FixItHint() : + FixItHint::CreateInsertion(afterLParen, "__bridge_transfer ")); + + return; + } + + // Bridge from a CF type to an ARC type. + if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) { + S.Diag(loc, diag::err_arc_cast_requires_bridge) + << unsigned(CCK == Sema::CCK_ImplicitConversion) // cast|implicit + << unsigned(castExprType->isBlockPointerType()) // of ObjC|block type + << castExprType + << 2 // to C pointer type + << castType + << castRange + << castExpr->getSourceRange(); + + S.Diag(noteLoc, diag::note_arc_bridge) + << (CCK != Sema::CCK_CStyleCast ? FixItHint() : + FixItHint::CreateInsertion(afterLParen, "__bridge ")); + S.Diag(noteLoc, diag::note_arc_bridge_retained) + << castType + << (CCK != Sema::CCK_CStyleCast ? FixItHint() : + FixItHint::CreateInsertion(afterLParen, "__bridge_retained ")); + + return; + } + + S.Diag(loc, diag::err_arc_mismatched_cast) + << (CCK != Sema::CCK_ImplicitConversion) + << srcKind << castExprType << castType + << castRange << castExpr->getSourceRange(); +} + +Sema::ARCConversionResult Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, Expr *&castExpr, CheckedConversionKind CCK) { QualType castExprType = castExpr->getType(); @@ -1849,22 +1944,22 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType); ARCConversionTypeClass castACTC = classifyTypeForARCConversion(effCastType); - if (exprACTC == castACTC) return; - if (isAnyCLike(exprACTC) && isAnyCLike(castACTC)) return; + if (exprACTC == castACTC) return ACR_okay; + if (isAnyCLike(exprACTC) && isAnyCLike(castACTC)) return ACR_okay; // Allow all of these types to be cast to integer types (but not // vice-versa). if (castACTC == ACTC_none && castType->isIntegralType(Context)) - return; + return ACR_okay; // Allow casts between pointers to lifetime types (e.g., __strong id*) // and pointers to void (e.g., cv void *). Casting from void* to lifetime* // must be explicit. if (exprACTC == ACTC_indirectRetainable && castACTC == ACTC_voidPtr) - return; + return ACR_okay; if (castACTC == ACTC_indirectRetainable && exprACTC == ACTC_voidPtr && CCK != CCK_ImplicitConversion) - return; + return ACR_okay; switch (ARCCastChecker(Context, exprACTC, castACTC).Visit(castExpr)) { // For invalid casts, fall through. @@ -1874,7 +1969,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, // Do nothing for both bottom and +0. case ACC_bottom: case ACC_plusZero: - return; + return ACR_okay; // If the result is +1, consume it here. case ACC_plusOne: @@ -1882,74 +1977,94 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, CK_ARCConsumeObject, castExpr, 0, VK_RValue); ExprNeedsCleanups = true; - return; + return ACR_okay; } - - SourceLocation loc = - (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc()); - - if (makeUnavailableInSystemHeader(loc, - "converts between Objective-C and C pointers in -fobjc-arc")) - return; - - unsigned srcKind = 0; - switch (exprACTC) { - case ACTC_none: - case ACTC_coreFoundation: - case ACTC_voidPtr: - srcKind = (castExprType->isPointerType() ? 1 : 0); - break; - case ACTC_retainable: - srcKind = (castExprType->isBlockPointerType() ? 2 : 3); - break; - case ACTC_indirectRetainable: - srcKind = 4; - break; + + // If this is a non-implicit cast from id or block type to a + // CoreFoundation type, delay complaining in case the cast is used + // in an acceptable context. + if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC) && + CCK != CCK_ImplicitConversion) + return ACR_unbridged; + + diagnoseObjCARCConversion(*this, castRange, castType, castACTC, + castExpr, exprACTC, CCK); + return ACR_okay; +} + +/// Given that we saw an expression with the ARCUnbridgedCastTy +/// placeholder type, complain bitterly. +void Sema::diagnoseARCUnbridgedCast(Expr *e) { + // We expect the spurious ImplicitCastExpr to already have been stripped. + assert(!e->hasPlaceholderType(BuiltinType::ARCUnbridgedCast)); + CastExpr *realCast = cast<CastExpr>(e->IgnoreParens()); + + SourceRange castRange; + QualType castType; + CheckedConversionKind CCK; + + if (CStyleCastExpr *cast = dyn_cast<CStyleCastExpr>(realCast)) { + castRange = SourceRange(cast->getLParenLoc(), cast->getRParenLoc()); + castType = cast->getTypeAsWritten(); + CCK = CCK_CStyleCast; + } else if (ExplicitCastExpr *cast = dyn_cast<ExplicitCastExpr>(realCast)) { + castRange = cast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange(); + castType = cast->getTypeAsWritten(); + CCK = CCK_OtherCast; + } else { + castType = cast->getType(); + CCK = CCK_ImplicitConversion; } - - if (CCK == CCK_CStyleCast) { - // Check whether this could be fixed with a bridge cast. - SourceLocation AfterLParen = PP.getLocForEndOfToken(castRange.getBegin()); - SourceLocation NoteLoc = AfterLParen.isValid()? AfterLParen : loc; - - if (castACTC == ACTC_retainable && isAnyRetainable(exprACTC)) { - Diag(loc, diag::err_arc_cast_requires_bridge) - << 2 - << castExprType - << (castType->isBlockPointerType()? 1 : 0) - << castType - << castRange - << castExpr->getSourceRange(); - Diag(NoteLoc, diag::note_arc_bridge) - << FixItHint::CreateInsertion(AfterLParen, "__bridge "); - Diag(NoteLoc, diag::note_arc_bridge_transfer) - << castExprType - << FixItHint::CreateInsertion(AfterLParen, "__bridge_transfer "); - - return; - } - - if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) { - Diag(loc, diag::err_arc_cast_requires_bridge) - << (castExprType->isBlockPointerType()? 1 : 0) - << castExprType - << 2 - << castType - << castRange - << castExpr->getSourceRange(); - - Diag(NoteLoc, diag::note_arc_bridge) - << FixItHint::CreateInsertion(AfterLParen, "__bridge "); - Diag(NoteLoc, diag::note_arc_bridge_retained) - << castType - << FixItHint::CreateInsertion(AfterLParen, "__bridge_retained "); - return; + + ARCConversionTypeClass castACTC = + classifyTypeForARCConversion(castType.getNonReferenceType()); + + Expr *castExpr = realCast->getSubExpr(); + assert(classifyTypeForARCConversion(castExpr->getType()) == ACTC_retainable); + + diagnoseObjCARCConversion(*this, castRange, castType, castACTC, + castExpr, ACTC_retainable, CCK); +} + +/// stripARCUnbridgedCast - Given an expression of ARCUnbridgedCast +/// type, remove the placeholder cast. +Expr *Sema::stripARCUnbridgedCast(Expr *e) { + assert(e->hasPlaceholderType(BuiltinType::ARCUnbridgedCast)); + + if (ParenExpr *pe = dyn_cast<ParenExpr>(e)) { + Expr *sub = stripARCUnbridgedCast(pe->getSubExpr()); + return new (Context) ParenExpr(pe->getLParen(), pe->getRParen(), sub); + } else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) { + assert(uo->getOpcode() == UO_Extension); + Expr *sub = stripARCUnbridgedCast(uo->getSubExpr()); + return new (Context) UnaryOperator(sub, UO_Extension, sub->getType(), + sub->getValueKind(), sub->getObjectKind(), + uo->getOperatorLoc()); + } else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) { + assert(!gse->isResultDependent()); + + unsigned n = gse->getNumAssocs(); + SmallVector<Expr*, 4> subExprs(n); + SmallVector<TypeSourceInfo*, 4> subTypes(n); + for (unsigned i = 0; i != n; ++i) { + subTypes[i] = gse->getAssocTypeSourceInfo(i); + Expr *sub = gse->getAssocExpr(i); + if (i == gse->getResultIndex()) + sub = stripARCUnbridgedCast(sub); + subExprs[i] = sub; } + + return new (Context) GenericSelectionExpr(Context, gse->getGenericLoc(), + gse->getControllingExpr(), + subTypes.data(), subExprs.data(), + n, gse->getDefaultLoc(), + gse->getRParenLoc(), + gse->containsUnexpandedParameterPack(), + gse->getResultIndex()); + } else { + assert(isa<ImplicitCastExpr>(e) && "bad form of unbridged cast!"); + return cast<ImplicitCastExpr>(e)->getSubExpr(); } - - Diag(loc, diag::err_arc_mismatched_cast) - << (CCK != CCK_ImplicitConversion) << srcKind << castExprType << castType - << castRange << castExpr->getSourceRange(); } bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType, diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index c566b236e4..f449c7d70d 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2427,6 +2427,7 @@ bool InitializationSequence::isAmbiguous() const { case FK_ArrayTypeMismatch: case FK_NonConstantArrayInit: case FK_ListInitializationFailed: + case FK_PlaceholderType: return false; case FK_ReferenceInitOverloadFailed: @@ -3793,8 +3794,20 @@ InitializationSequence::InitializationSequence(Sema &S, return; } Args[I] = Result.take(); + } else if (const BuiltinType *PlaceholderTy + = Args[I]->getType()->getAsPlaceholderType()) { + // FIXME: should we be doing this here? + if (PlaceholderTy->getKind() != BuiltinType::Overload) { + ExprResult result = S.CheckPlaceholderExpr(Args[I]); + if (result.isInvalid()) { + SetFailed(FK_PlaceholderType); + return; + } + Args[I] = result.take(); + } } + QualType SourceType; Expr *Initializer = 0; if (NumArgs == 1) { @@ -5200,6 +5213,11 @@ bool InitializationSequence::Diagnose(Sema &S, "Inconsistent init list check result."); break; } + + case FK_PlaceholderType: { + // FIXME: Already diagnosed! + break; + } } PrintInitLocationNote(S, Entity); @@ -5297,6 +5315,11 @@ void InitializationSequence::dump(raw_ostream &OS) const { case FK_ListInitializationFailed: OS << "list initialization checker failure"; + break; + + case FK_PlaceholderType: + OS << "initializer expression isn't contextually valid"; + break; } OS << '\n'; return; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 931f60fbc7..44395c59df 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -542,6 +542,88 @@ void OverloadCandidateSet::clear() { Functions.clear(); } +namespace { + class UnbridgedCastsSet { + struct Entry { + Expr **Addr; + Expr *Saved; + }; + SmallVector<Entry, 2> Entries; + + public: + void save(Sema &S, Expr *&E) { + assert(E->hasPlaceholderType(BuiltinType::ARCUnbridgedCast)); + Entry entry = { &E, E }; + Entries.push_back(entry); + E = S.stripARCUnbridgedCast(E); + } + + void restore() { + for (SmallVectorImpl<Entry>::iterator + i = Entries.begin(), e = Entries.end(); i != e; ++i) + *i->Addr = i->Saved; + } + }; +} + +/// checkPlaceholderForOverload - Do any interesting placeholder-like +/// preprocessing on the given expression. +/// +/// \param unbridgedCasts a collection to which to add unbridged casts;< |