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 | 4124c4924d6349e2d8ddfe2b4df57030d23e4c4e (patch) | |
tree | 3204ea3f05dd96408cadbc06bc5d04fbf729a6e7 /clang | |
parent | 3634f34659968deb782e319abdf6298616911b3d (diff) | |
download | bcm5719-llvm-4124c4924d6349e2d8ddfe2b4df57030d23e4c4e.tar.gz bcm5719-llvm-4124c4924d6349e2d8ddfe2b4df57030d23e4c4e.zip |
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.
llvm-svn: 142219
Diffstat (limited to 'clang')
21 files changed, 645 insertions, 200 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 33175a29e5e..9590debd744 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/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/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h index e69bebd56cf..13eae181e44 100644 --- a/clang/include/clang/Sema/Initialization.h +++ b/clang/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/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4f244db7377..1b1e07abbf9 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/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/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index b20732a5f72..925f468cfd2 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ddcbb6d6b1b..6376f1f2d90 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index a23ba4921c8..cc9e8b3758f 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/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/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index c566b236e4f..f449c7d70d5 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/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/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 931f60fbc77..44395c59df1 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/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; +/// without this, they will be immediately diagnosed as errors +/// +/// Return true on unrecoverable error. +static bool checkPlaceholderForOverload(Sema &S, Expr *&E, + UnbridgedCastsSet *unbridgedCasts = 0) { + // ObjCProperty l-values are placeholder-like. + if (E->getObjectKind() == OK_ObjCProperty) { + ExprResult result = S.ConvertPropertyForRValue(E); + if (result.isInvalid()) + return true; + + E = result.take(); + return false; + } + + // Handle true placeholders. + if (const BuiltinType *placeholder = E->getType()->getAsPlaceholderType()) { + // We can't handle overloaded expressions here because overload + // resolution might reasonably tweak them. + if (placeholder->getKind() == BuiltinType::Overload) return false; + + // If the context potentially accepts unbridged ARC casts, strip + // the unbridged cast and add it to the collection for later restoration. + if (placeholder->getKind() == BuiltinType::ARCUnbridgedCast && + unbridgedCasts) { + unbridgedCasts->save(S, E); + return false; + } + + // Go ahead and check everything else. + ExprResult result = S.CheckPlaceholderExpr(E); + if (result.isInvalid()) + return true; + + E = result.take(); + return false; + } + + // Nothing to do. + return false; +} + +/// checkArgPlaceholdersForOverload - Check a set of call operands for +/// placeholders. +static bool checkArgPlaceholdersForOverload(Sema &S, Expr **args, + unsigned numArgs, + UnbridgedCastsSet &unbridged) { + for (unsigned i = 0; i != numArgs; ++i) + if (checkPlaceholderForOverload(S, args[i], &unbridged)) + return true; + + return false; +} + // IsOverload - Determine whether the given New declaration is an // overload of the declarations in Old. This routine returns false if // New and Old cannot be overloaded, e.g., if New has the same @@ -8574,6 +8656,10 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, "std is associated namespace but not doing ADL"); #endif + UnbridgedCastsSet UnbridgedCasts; + if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts)) + return ExprError(); + OverloadCandidateSet CandidateSet(Fn->getExprLoc()); // Add the functions denoted by the callee to the set of candidate @@ -8600,14 +8686,15 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, RParenLoc, /*EmptyLookup=*/true); } + UnbridgedCasts.restore(); + OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) { case OR_Success: { FunctionDecl *FDecl = Best->Function; MarkDeclarationReferenced(Fn->getExprLoc(), FDecl); CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); - DiagnoseUseOfDecl(FDecl? FDecl : Best->FoundDecl.getDecl(), - ULE->getNameLoc()); + DiagnoseUseOfDecl(FDecl, ULE->getNameLoc()); Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc, ExecConfig); @@ -8684,12 +8771,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // TODO: provide better source location info. DeclarationNameInfo OpNameInfo(OpName, OpLoc); - if (Input->getObjectKind() == OK_ObjCProperty) { - ExprResult Result = ConvertPropertyForRValue(Input); - if (Result.isInvalid()) - return ExprError(); - Input = Result.take(); - } + if (checkPlaceholderForOverload(*this, Input)) + return ExprError(); Expr *Args[2] = { Input, 0 }; unsigned NumArgs = 1; @@ -8922,13 +9005,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, OpLoc)); } - // Always do property rvalue conversions on the RHS. - if (Args[1]->getObjectKind() == OK_ObjCProperty) { - ExprResult Result = ConvertPropertyForRValue(Args[1]); - if (Result.isInvalid()) - return ExprError(); - Args[1] = Result.take(); - } + // Always do placeholder-like conversions on the RHS. + if (checkPlaceholderForOverload(*this, Args[1])) + return ExprError(); // The LHS is more complicated. if (Args[0]->getObjectKind() == OK_ObjCProperty) { @@ -8962,6 +9041,10 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Args[0] = Result.take(); } + // Handle all the other placeholders. + if (checkPlaceholderForOverload(*this, Args[0])) + return ExprError(); + // If this is the assignment operator, we only perform overload resolution // if the left-hand side is a class or enumeration type. This is actually // a hack. The standard requires that we do overload resolution between the @@ -9184,18 +9267,11 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, RLoc)); } - if (Args[0]->getObjectKind() == OK_ObjCProperty) { - ExprResult Result = ConvertPropertyForRValue(Args[0]); - if (Result.isInvalid()) - return ExprError(); - Args[0] = Result.take(); - } - if (Args[1]->getObjectKind() == OK_ObjCProperty) { - ExprResult Result = ConvertPropertyForRValue(Args[1]); - if (Result.isInvalid()) - return ExprError(); - Args[1] = Result.take(); - } + // Handle placeholders on both operands. + if (checkPlaceholderForOverload(*this, Args[0])) + return ExprError(); + if (checkPlaceholderForOverload(*this, Args[1])) + return ExprError(); // Build an empty overload set. OverloadCandidateSet CandidateSet(LLoc); @@ -9396,6 +9472,10 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, return MaybeBindToTemporary(call); } + UnbridgedCastsSet UnbridgedCasts; + if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts)) + return ExprError(); + MemberExpr *MemExpr; CXXMethodDecl *Method = 0; DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_public); @@ -9405,6 +9485,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Method = cast<CXXMethodDecl>(MemExpr->getMemberDecl()); FoundDecl = MemExpr->getFoundDecl(); Qualifier = MemExpr->getQualifier(); + UnbridgedCasts.restore(); } else { UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr); Qualifier = UnresExpr->getQualifier(); @@ -9458,6 +9539,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, DeclarationName DeclName = UnresExpr->getMemberName(); + UnbridgedCasts.restore(); + OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, UnresExpr->getLocStart(), Best)) { @@ -9569,12 +9652,13 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc) { + if (checkPlaceholderForOverload(*this, Obj)) + return ExprError(); ExprResult Object = Owned(Obj); - if (Object.get()->getObjectKind() == OK_ObjCProperty) { - Object = ConvertPropertyForRValue(Object.take()); - if (Object.isInvalid()) - return ExprError(); - } + + UnbridgedCastsSet UnbridgedCasts; + if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts)) + return ExprError(); assert(Object.get()->getType()->isRecordType() && "Requires object type argument"); const RecordType *Record = Object.get()->getType()->getAs<RecordType>(); @@ -9696,6 +9780,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, if (Best == CandidateSet.end()) return true; + UnbridgedCasts.restore(); + if (Best->Function == 0) { // Since there is no function declaration, this is one of the // surrogate candidates. Dig out the conversion function. @@ -9845,12 +9931,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { assert(Base->getType()->isRecordType() && "left-hand side must have class type"); - if (Base->getObjectKind() == OK_ObjCProperty) { - ExprResult Result = ConvertPropertyForRValue(Base); - if (Result.isInvalid()) - return ExprError(); - Base = Result.take(); - } + if (checkPlaceholderForOverload(*this, Base)) + return ExprError(); SourceLocation Loc = Base->getExprLoc(); diff --git a/clang/test/ARCMT/checking.m b/clang/test/ARCMT/checking.m index 7c24dc485a2..0e441cb1eb6 100644 --- a/clang/test/ARCMT/checking.m +++ b/clang/test/ARCMT/checking.m @@ -62,8 +62,8 @@ void test1(A *a, BOOL b, struct UnsafeS *unsafeS) { CFStringRef cfstr; NSString *str = (NSString *)cfstr; // expected-error {{cast of C pointer type 'CFStringRef' (aka 'const struct __CFString *') to Objective-C pointer type 'NSString *' requires a bridged cast}} \ - // expected-note{{use __bridge to convert directly (no change in ownership)}} \ - // expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}} + // expected-note {{use __bridge to convert directly (no change in ownership)}} \ + // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}} \ str = (NSString *)kUTTypePlainText; str = b ? kUTTypeRTF : kUTTypePlainText; str = (NSString *)(b ? kUTTypeRTF : kUTTypePlainText); @@ -120,11 +120,11 @@ void * cvt(id arg) (void)(__autoreleasing id**)voidp_val; (void)(void*)voidp_val; (void)(void**)arg; // expected-error {{disallowed}} - cvt((void*)arg); // expected-error {{requires a bridged cast}} expected-error {{disallowed}} \ - // expected-note {{use __bridge}} expected-note {{use __bridge_retained}} + cvt((void*)arg); // expected-error 2 {{requires a bridged cast}} \ + // expected-note 2 {{use __bridge to}} expected-note {{use __bridge_transfer}} expected-note {{use __bridge_retained}} cvt(0); (void)(__strong id**)(0); - return arg; // expected-error {{disallowed}} + return arg; // expected-error {{requires a bridged cast}} expected-note {{use __bridge}} expected-note {{use __bridge_retained}} } diff --git a/clang/test/ARCMT/nonobjc-to-objc-cast-2.m b/clang/test/ARCMT/nonobjc-to-objc-cast-2.m index 5dba61f023f..2900b9a1fed 100644 --- a/clang/test/ARCMT/nonobjc-to-objc-cast-2.m +++ b/clang/test/ARCMT/nonobjc-to-objc-cast-2.m @@ -14,7 +14,7 @@ void f(BOOL b) { NSString *str = (NSString *)cfstr; // expected-error {{cast of C pointer type 'CFStringRef' (aka 'const struct __CFString *') to Objective-C pointer type 'NSString *' requires a bridged cast}} \ // expected-note{{use __bridge to convert directly (no change in ownership)}} \ // expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}} - void *vp = str; // expected-error {{disallowed}} + void *vp = str; // expected-error {{requires a bridged cast}} expected-note {{use __bridge}} expected-note {{use __bridge}} } void f2(NSString *s) { diff --git a/clang/test/CXX/over/over.over/p2-resolve-single-template-id.cpp b/clang/test/CXX/over/over.over/p2-resolve-single-template-id.cpp index d2a23ce96df..1bd0d340748 100644 --- a/clang/test/CXX/over/over.over/p2-resolve-single-template-id.cpp +++ b/clang/test/CXX/over/over.over/p2-resolve-single-template-id.cpp @@ -165,8 +165,8 @@ namespace member_pointers { { bool b = &S::f<char>; } { bool b = &S::f<int>; } // These next two errors are terrible. - { bool b = s.f<char>; } // expected-error {{cannot initialize}} - { bool b = s.f<int>; } // expected-error {{cannot initialize}} + { bool b = s.f<char>; } // expected-error {{reference to non-static member function must be called}} + { bool b = s.f<int>; } // expected-error {{reference to non-static member function must be called}} { bool b = &s.f<char>; } // expected-error {{cannot create a non-constant pointer to member function}} { bool b = &s.f<int>; } // expected-error {{cannot create a non-constant pointer to member function}} diff --git a/clang/test/SemaCXX/addr-of-overloaded-function.cpp b/clang/test/SemaCXX/addr-of-overloaded-function.cpp index a36fd582db2..c3360cc0599 100644 --- a/clang/test/SemaCXX/addr-of-overloaded-function.cpp +++ b/clang/test/SemaCXX/addr-of-overloaded-function.cpp @@ -57,8 +57,7 @@ struct B struct C { C &getC() { - // FIXME: this error message is terrible - return makeAC; // expected-error{{cannot bind to a value of unrelated type}} + return makeAC; // expected-error{{reference to non-static member function must be called}} } C &makeAC(); diff --git a/clang/test/SemaCXX/member-pointer.cpp b/clang/test/SemaCXX/member-pointer.cpp index cf6481015a8..4e8b4a813ba 100644 --- a/clang/test/SemaCXX/member-pointer.cpp +++ b/clang/test/SemaCXX/member-pointer.cpp @@ -278,7 +278,7 @@ namespace PR9973 { typedef R T::*F; F f_; template<class U> int & call(U u) - { return u->*f_; } // expected-error{{non-const lvalue reference to type 'int' cannot bind to a temporary of type '<bound member function type>'}} + { return u->*f_; } // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}} expected-error {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} template<class U> int operator()(U u) { call(u); } // expected-note{{in instantiation of}} diff --git a/clang/test/SemaCXX/overloaded-name.cpp b/clang/test/SemaCXX/overloaded-name.cpp index a5ec51ced23..6da03544009 100644 --- a/clang/test/SemaCXX/overloaded-name.cpp +++ b/clang/test/SemaCXX/overloaded-name.cpp @@ -21,11 +21,10 @@ namespace rdar9623945 { public: const char* text(void); void g(void) { - // FIXME: why 2x? f(text()); - f(text); // expected-error 2{{reference to non-static member function must be called; did you mean to call it with no arguments?}} + f(text); // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}} f(text()); - f(text); // expected-error 2{{reference to non-static member function must be called; did you mean to call it with no arguments?}} + f(text); // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}} } }; } diff --git a/clang/test/SemaCXX/overloaded-operator.cpp b/clang/test/SemaCXX/overloaded-operator.cpp index 1e4a3b7514b..d9b75f74f6f 100644 --- a/clang/test/SemaCXX/overloaded-operator.cpp +++ b/clang/test/SemaCXX/overloaded-operator.cpp @@ -392,7 +392,7 @@ namespace rdar9136502 { }; struct Y { - Y &operator<<(int); // expected-note{{candidate function not viable: no known conversion from '<bound member function type>' to 'int'}} + Y &operator<<(int); }; void f(X x, Y y) { diff --git a/clang/test/SemaCXX/unknown-anytype.cpp b/clang/test/SemaCXX/unknown-anytype.cpp index ba52122bc49..a07ec83d10a 100644 --- a/clang/test/SemaCXX/unknown-anytype.cpp +++ b/clang/test/SemaCXX/unknown-anytype.cpp @@ -14,9 +14,9 @@ namespace test1 { // making sure that these locations check for placeholder types // properly. - int x = foo; // expected-error {{cannot initialize}} + int x = foo; // expected-error {{'foo' has unknown type}} int y = 0 + foo; // expected-error {{'foo' has unknown type}} - return foo; // expected-error {{cannot initialize}} + return foo; // expected-error {{'foo' has unknown type}} } } diff --git a/clang/test/SemaObjC/arc-type-conversion.m b/clang/test/SemaObjC/arc-type-conversion.m index 01f61bd4b67..c626cedcc5e 100644 --- a/clang/test/SemaObjC/arc-type-conversion.m +++ b/clang/test/SemaObjC/arc-type-conversion.m @@ -12,12 +12,15 @@ void * cvt(id arg) (void)(void*)voidp_val; (void)(void**)arg; // expected-error {{cast of an Objective-C pointer to 'void **' is disallowed with ARC}} cvt((void*)arg); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}} \ - // expected-error {{implicit conversion of a non-Objective-C pointer type 'void *' to 'id' is disallowed with ARC}} \ - // expected-note{{use __bridge to convert directly (no change in ownership)}} \ - // expected-note{{use __bridge_retained to make an ARC object available as a +1 'void *'}} + // expected-error {{implicit conversion of C pointer type 'void *' to Objective-C pointer type 'id' requires a bridged cast}} \ + // expected-note 2 {{use __bridge to convert directly (no change in ownership)}} \ + // expected-note {{use __bridge_retained to make an ARC object available as a +1 'void *'}} \ + // expected-note {{use __bridge_transfer to transfer ownership of a +1 'void *' into ARC}} cvt(0); (void)(__strong id**)(0); - return arg; // expected-error {{implicit conversion of an Objective-C pointer to 'void *' is disallowed with ARC}} + return arg; // expected-error {{implicit conversion of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}} \ + // expected-note {{use __bridge to convert directly (no change in ownership)}} \ + // expected-note {{use __bridge_retained to make an ARC object available as a +1 'void *'}} } void to_void(__strong id *sip, __weak id *wip, diff --git a/clang/test/SemaObjC/arc-unbridged-cast.m b/clang/test/SemaObjC/arc-unbridged-cast.m index 8b835a14986..2a8a24d36f8 100644 --- a/clang/test/SemaObjC/arc-unbridged-cast.m +++ b/clang/test/SemaObjC/arc-unbridged-cast.m @@ -70,3 +70,50 @@ void test1(int cond) { x = (id) (cond ? (void*) 0 : [object newString]); x = (id) (cond ? (CFStringRef) @"help" : [object newString]); // a bit questionable } + +// rdar://problem/10246264 +@interface CFTaker +- (void) takeOrdinary: (CFStringRef) arg; +- (void) takeVariadic: (int) n, ...; +- (void) takeConsumed: (CFStringRef __attribute__((cf_consumed))) arg; +@end +void testCFTaker(CFTaker *taker, id string) { + [taker takeOrdinary: (CFStringRef) string]; + [taker takeVariadic: 1, (CFStringRef) string]; + [taker takeConsumed: (CFStringRef) string]; // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} +} + +void takeCFOrdinaryUnaudited(CFStringRef arg); +void takeCFVariadicUnaudited(int n, ...); +void takeCFConsumedUnaudited(CFStringRef __attribute__((cf_consumed)) arg); +#pragma clang arc_cf_code_audited begin +void takeCFOrdinaryAudited(CFStringRef arg); +void takeCFVariadicAudited(int n, ...); +void takeCFConsumedAudited(CFStringRef __attribute__((cf_consumed)) arg); +#pragma clang arc_cf_code_audited end + +void testTakerFunctions(id string) { + takeCFOrdinaryUnaudited((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} + takeCFVariadicUnaudited(1, (CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} + takeCFConsumedUnaudited((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} + + void (*taker)(CFStringRef) = 0; + taker((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} + + takeCFOrdinaryAudited((CFStringRef) string); + takeCFVariadicAudited(1, (CFStringRef) string); + takeCFConsumedAudited((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} +} + +void testTakerFunctions_parens(id string) { + takeCFOrdinaryUnaudited(((CFStringRef) string)); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} + takeCFVariadicUnaudited(1, ((CFStringRef) string)); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} + takeCFConsumedUnaudited(((CFStringRef) string)); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} + + void (*taker)(CFStringRef) = 0; + taker(((CFStringRef) string)); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} + + takeCFOrdinaryAudited(((CFStringRef) string)); + takeCFVariadicAudited(1, ((CFStringRef) string)); + takeCFConsumedAudited(((CFStringRef) string)); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} +} diff --git a/clang/test/SemaObjC/arc.m b/clang/test/SemaObjC/arc.m index ed6e60d8dc2..3f4c406458f 100644 --- a/clang/test/SemaObjC/arc.m +++ b/clang/test/SemaObjC/arc.m @@ -263,8 +263,8 @@ void test11(id op, void *vp) { b = (vp == nil); b = (nil == vp); - b = (vp == op); // expected-error {{implicit conversion of an Objective-C pointer to 'void *'}} - b = (op == vp); // expected-error {{implicit conversion of a non-Objective-C pointer type 'void *' to 'id'}} + b = (vp == op); // expected-error {{implicit conversion of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}} expected-note {{use __bridge}} expected-note {{use __bridge_retained}} + b = (op == vp); // expected-error {{implicit conversion of C pointer type 'void *' to Objective-C pointer type 'id' requires a bridged cast}} expected-note {{use __bridge}} expected-note {{use __bridge_transfer}} } void test12(id collection) { diff --git a/clang/test/SemaObjCXX/arc-type-conversion.mm b/clang/test/SemaObjCXX/arc-type-conversion.mm index 48d1e4833b4..fd42513d5ff 100644 --- a/clang/test/SemaObjCXX/arc-type-conversion.mm +++ b/clang/test/SemaObjCXX/arc-type-conversion.mm @@ -12,10 +12,7 @@ void * cvt(id arg) // expected-note{{candidate function not viable: cannot conve (void)(__autoreleasing id**)voidp_val; (void)(void*)voidp_val; (void)(void**)arg; // expected-error {{cast of an Objective-C pointer to 'void **' is disallowed}} - cvt((void*)arg); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}} \ - // expected-error {{no matching function for call to 'cvt'}} \ - // expected-note{{use __bridge to convert directly (no change in ownership)}} \ - // expected-note{{use __bridge_retained to make an ARC object available as a +1 'void *'}} + cvt((void*)arg); // expected-error {{no matching function for call to 'cvt'}} cvt(0); (void)(__strong id**)(0); diff --git a/clang/test/SemaObjCXX/arc-unbridged-cast.mm b/clang/test/SemaObjCXX/arc-unbridged-cast.mm new file mode 100644 index 00000000000..81f329106d6 --- /dev/null +++ b/clang/test/SemaObjCXX/arc-unbridged-cast.mm @@ -0,0 +1,106 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify %s + +typedef const struct __CFString * CFStringRef; + +@interface Object +@property CFStringRef property; +- (CFStringRef) implicitProperty; +- (CFStringRef) newString; +- (CFStringRef) makeString; +@end + +extern Object *object; + +// rdar://9744349 +id test0(void) { + id p1 = (id)[object property]; + id p2 = (__bridge_transfer id)[object property]; + id p3 = (__bridge id)[object property]; + return (id) object.property; +} + +// rdar://10140692 +CFStringRef unauditedString(void); +CFStringRef plusOneString(void) __attribute__((cf_returns_retained)); + +#pragma clang arc_cf_code_audited begin +CFStringRef auditedString(void); +CFStringRef auditedCreateString(void); +#pragma clang arc_cf_code_audited end + +void test1(int cond) { + id x; + x = (id) auditedString(); + x = (id) (cond ? auditedString() : (void*) 0); + x = (id) (cond ? (void*) 0 : auditedString()); + x = (id) (cond ? (CFStringRef) @"help" : auditedString()); + + x = (id) unauditedString(); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}} + x = (id) (cond ? unauditedString() : (void*) 0); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}} + x = (id) (cond ? (void*) 0 : unauditedString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}} + x = (id) (cond ? (CFStringRef) @"help" : unauditedString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}} + + x = (id) auditedCreateString(); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}} + x = (id) (cond ? auditedCreateString() : (void*) 0); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}} + x = (id) (cond ? (void*) 0 : auditedCreateString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}} + x = (id) (cond ? (CFStringRef) @"help" : auditedCreateString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}} + + x = (id) [object property]; + x = (id) (cond ? [object property] : (void*) 0); + x = (id) (cond ? (void*) 0 : [object property]); + x = (id) (cond ? (CFStringRef) @"help" : [object property]); + + x = (id) object.property; + x = (id) (cond ? object.property : (void*) 0); + x = (id) (cond ? (void*) 0 : object.property); + x = (id) (cond ? (CFStringRef) @"help" : object.property); + + x = (id) object.implicitProperty; + x = (id) (cond ? object.implicitProperty : (void*) 0); + x = (id) (cond ? (void*) 0 : object.implicitProperty); + x = (id) (cond ? (CFStringRef) @"help" : object.implicitProperty); + + x = (id) [object makeString]; + x = (id) (cond ? [object makeString] : (void*) 0); + x = (id) (cond ? (void*) 0 : [object makeString]); + x = (id) (cond ? (CFStringRef) @"help" : [object makeString]); + + x = (id) [object newString]; + x = (id) (cond ? [object newString] : (void*) 0); + x = (id) (cond ? (void*) 0 : [object newString]); + x = (id) (cond ? (CFStringRef) @"help" : [object newString]); // a bit questionable +} + +// rdar://problem/10246264 +@interface CFTaker +- (void) takeOrdinary: (CFStringRef) arg; +- (void) takeVariadic: (int) n, ...; +- (void) takeConsumed: (CFStringRef __attribute__((cf_consumed))) arg; +@end +void testCFTaker(CFTaker *taker, id string) { + [taker takeOrdinary: (CFStringRef) string]; + [taker takeVariadic: 1, (CFStringRef) string]; + [taker takeConsumed: (CFStringRef) string]; // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} +} + +void takeCFOrdinaryUnaudited(CFStringRef arg); +void takeCFVariadicUnaudited(int n, ...); +void takeCFConsumedUnaudited(CFStringRef __attribute__((cf_consumed)) arg); +#pragma clang arc_cf_code_audited begin +void takeCFOrdinaryAudited(CFStringRef arg); +void takeCFVariadicAudited(int n, ...); +void takeCFConsumedAudited(CFStringRef __attribute__((cf_consumed)) arg); +#pragma clang arc_cf_code_audited end + +void testTakerFunctions(id string) { + takeCFOrdinaryUnaudited((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} + takeCFVariadicUnaudited(1, (CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} + takeCFConsumedUnaudited((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} + + void (*taker)(CFStringRef) = 0; + taker((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} + + takeCFOrdinaryAudited((CFStringRef) string); + takeCFVariadicAudited(1, (CFStringRef) string); + takeCFConsumedAudited((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use __bridge_retained to}} +} |