diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 3d4b345ff56b..e81b44a8ede7 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2327,68 +2327,7 @@ public: private: Stmt *Op; - void CheckCastConsistency() const { -#ifndef NDEBUG - switch (getCastKind()) { - case CK_DerivedToBase: - case CK_UncheckedDerivedToBase: - case CK_DerivedToBaseMemberPointer: - case CK_BaseToDerived: - case CK_BaseToDerivedMemberPointer: - assert(!path_empty() && "Cast kind should have a base path!"); - break; - - // These should not have an inheritance path. - case CK_BitCast: - case CK_Dynamic: - case CK_ToUnion: - case CK_ArrayToPointerDecay: - case CK_FunctionToPointerDecay: - case CK_NullToMemberPointer: - case CK_NullToPointer: - case CK_ConstructorConversion: - case CK_IntegralToPointer: - case CK_PointerToIntegral: - case CK_ToVoid: - case CK_VectorSplat: - case CK_IntegralCast: - case CK_IntegralToFloating: - case CK_FloatingToIntegral: - case CK_FloatingCast: - case CK_AnyPointerToObjCPointerCast: - case CK_AnyPointerToBlockPointerCast: - case CK_ObjCObjectLValueCast: - case CK_FloatingRealToComplex: - case CK_FloatingComplexToReal: - case CK_FloatingComplexCast: - case CK_FloatingComplexToIntegralComplex: - case CK_IntegralRealToComplex: - case CK_IntegralComplexToReal: - case CK_IntegralComplexCast: - case CK_IntegralComplexToFloatingComplex: - case CK_ObjCProduceObject: - case CK_ObjCConsumeObject: - case CK_ObjCReclaimReturnedObject: - assert(!getType()->isBooleanType() && "unheralded conversion to bool"); - // fallthrough to check for null base path - - case CK_Dependent: - case CK_LValueToRValue: - case CK_GetObjCProperty: - case CK_NoOp: - case CK_PointerToBoolean: - case CK_IntegralToBoolean: - case CK_FloatingToBoolean: - case CK_MemberPointerToBoolean: - case CK_FloatingComplexToBoolean: - case CK_IntegralComplexToBoolean: - case CK_LValueBitCast: // -> bool& - case CK_UserDefinedConversion: // operator bool() - assert(path_empty() && "Cast kind should not have a base path!"); - break; - } -#endif - } + void CheckCastConsistency() const; const CXXBaseSpecifier * const *path_buffer() const { return const_cast(this)->path_buffer(); @@ -2419,7 +2358,9 @@ protected: assert(kind != CK_Invalid && "creating cast with invalid cast kind"); CastExprBits.Kind = kind; setBasePathSize(BasePathSize); +#ifndef NDEBUG CheckCastConsistency(); +#endif } /// \brief Construct an empty cast. diff --git a/clang/include/clang/AST/ExprObjC.h b/clang/include/clang/AST/ExprObjC.h index 725253e45cb2..4420f7527cf2 100644 --- a/clang/include/clang/AST/ExprObjC.h +++ b/clang/include/clang/AST/ExprObjC.h @@ -989,10 +989,10 @@ class ObjCBridgedCastExpr : public ExplicitCastExpr { public: ObjCBridgedCastExpr(SourceLocation LParenLoc, ObjCBridgeCastKind Kind, - SourceLocation BridgeKeywordLoc, TypeSourceInfo *TSInfo, - Expr *Operand) + CastKind CK, SourceLocation BridgeKeywordLoc, + TypeSourceInfo *TSInfo, Expr *Operand) : ExplicitCastExpr(ObjCBridgedCastExprClass, TSInfo->getType(), VK_RValue, - CK_BitCast, Operand, 0, TSInfo), + CK, Operand, 0, TSInfo), LParenLoc(LParenLoc), BridgeKeywordLoc(BridgeKeywordLoc), Kind(Kind) { } /// \brief Construct an empty Objective-C bridged cast. diff --git a/clang/include/clang/AST/OperationKinds.h b/clang/include/clang/AST/OperationKinds.h index 92ff6041371c..fa9adec4ef5a 100644 --- a/clang/include/clang/AST/OperationKinds.h +++ b/clang/include/clang/AST/OperationKinds.h @@ -31,9 +31,12 @@ enum CastKind { /// to be reinterpreted as a bit pattern of another type. Generally /// the operands must have equivalent size and unrelated types. /// - /// The pointer conversion char* -> int* is a bitcast. Many other - /// pointer conversions which are "physically" bitcasts are given - /// special cast kinds. + /// The pointer conversion char* -> int* is a bitcast. A conversion + /// from any pointer type to a C pointer type is a bitcast unless + /// it's actually BaseToDerived or DerivedToBase. A conversion to a + /// block pointer or ObjC pointer type is a bitcast only if the + /// operand has the same type kind; otherwise, it's one of the + /// specialized casts below. /// /// Vector coercions are bitcasts. CK_BitCast, @@ -186,12 +189,16 @@ enum CastKind { /// (float) ld CK_FloatingCast, - /// CK_AnyPointerToObjCPointerCast - Casting any other pointer kind - /// to an Objective-C pointer. - CK_AnyPointerToObjCPointerCast, + /// CK_CPointerToObjCPointerCast - Casting a C pointer kind to an + /// Objective-C pointer. + CK_CPointerToObjCPointerCast, - /// CK_AnyPointerToBlockPointerCast - Casting any other pointer kind - /// to a block pointer. + /// CK_BlockPointerToObjCPointerCast - Casting a block pointer to an + /// ObjC pointer. + CK_BlockPointerToObjCPointerCast, + + /// CK_AnyPointerToBlockPointerCast - Casting any non-block pointer + /// to a block pointer. Block-to-block casts are bitcasts. CK_AnyPointerToBlockPointerCast, /// \brief Converting between two Objective-C object types, which diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 8a826e592aea..e68d206f21da 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1458,7 +1458,9 @@ public: Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const; enum ScalarTypeKind { - STK_Pointer, + STK_CPointer, + STK_BlockPointer, + STK_ObjCObjectPointer, STK_MemberPointer, STK_Bool, STK_Integral, diff --git a/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp b/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp index 7e922f3a2726..5f9159416b0d 100644 --- a/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp +++ b/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -61,7 +61,7 @@ public: } bool VisitCastExpr(CastExpr *E) { - if (E->getCastKind() != CK_AnyPointerToObjCPointerCast + if (E->getCastKind() != CK_CPointerToObjCPointerCast && E->getCastKind() != CK_BitCast) return true; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index a3df189a6137..25e7de77fbd0 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1013,6 +1013,93 @@ SourceRange MemberExpr::getSourceRange() const { return SourceRange(StartLoc, EndLoc); } +void CastExpr::CheckCastConsistency() const { + switch (getCastKind()) { + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + case CK_DerivedToBaseMemberPointer: + case CK_BaseToDerived: + case CK_BaseToDerivedMemberPointer: + assert(!path_empty() && "Cast kind should have a base path!"); + break; + + case CK_CPointerToObjCPointerCast: + assert(getType()->isObjCObjectPointerType()); + assert(getSubExpr()->getType()->isPointerType()); + goto CheckNoBasePath; + + case CK_BlockPointerToObjCPointerCast: + assert(getType()->isObjCObjectPointerType()); + assert(getSubExpr()->getType()->isBlockPointerType()); + goto CheckNoBasePath; + + case CK_BitCast: + // Arbitrary casts to C pointer types count as bitcasts. + // Otherwise, we should only have block and ObjC pointer casts + // here if they stay within the type kind. + if (!getType()->isPointerType()) { + assert(getType()->isObjCObjectPointerType() == + getSubExpr()->getType()->isObjCObjectPointerType()); + assert(getType()->isBlockPointerType() == + getSubExpr()->getType()->isBlockPointerType()); + } + goto CheckNoBasePath; + + case CK_AnyPointerToBlockPointerCast: + assert(getType()->isBlockPointerType()); + assert(getSubExpr()->getType()->isAnyPointerType() && + !getSubExpr()->getType()->isBlockPointerType()); + goto CheckNoBasePath; + + // These should not have an inheritance path. + case CK_Dynamic: + case CK_ToUnion: + case CK_ArrayToPointerDecay: + case CK_FunctionToPointerDecay: + case CK_NullToMemberPointer: + case CK_NullToPointer: + case CK_ConstructorConversion: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_ToVoid: + case CK_VectorSplat: + case CK_IntegralCast: + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + case CK_FloatingCast: + case CK_ObjCObjectLValueCast: + case CK_FloatingRealToComplex: + case CK_FloatingComplexToReal: + case CK_FloatingComplexCast: + case CK_FloatingComplexToIntegralComplex: + case CK_IntegralRealToComplex: + case CK_IntegralComplexToReal: + case CK_IntegralComplexCast: + case CK_IntegralComplexToFloatingComplex: + case CK_ObjCProduceObject: + case CK_ObjCConsumeObject: + case CK_ObjCReclaimReturnedObject: + assert(!getType()->isBooleanType() && "unheralded conversion to bool"); + goto CheckNoBasePath; + + case CK_Dependent: + case CK_LValueToRValue: + case CK_GetObjCProperty: + case CK_NoOp: + case CK_PointerToBoolean: + case CK_IntegralToBoolean: + case CK_FloatingToBoolean: + case CK_MemberPointerToBoolean: + case CK_FloatingComplexToBoolean: + case CK_IntegralComplexToBoolean: + case CK_LValueBitCast: // -> bool& + case CK_UserDefinedConversion: // operator bool() + CheckNoBasePath: + assert(path_empty() && "Cast kind should not have a base path!"); + break; + } +} + const char *CastExpr::getCastKindName() const { switch (getCastKind()) { case CK_Dependent: @@ -1077,8 +1164,10 @@ const char *CastExpr::getCastKindName() const { return "FloatingToBoolean"; case CK_MemberPointerToBoolean: return "MemberPointerToBoolean"; - case CK_AnyPointerToObjCPointerCast: - return "AnyPointerToObjCPointerCast"; + case CK_CPointerToObjCPointerCast: + return "CPointerToObjCPointerCast"; + case CK_BlockPointerToObjCPointerCast: + return "BlockPointerToObjCPointerCast"; case CK_AnyPointerToBlockPointerCast: return "AnyPointerToBlockPointerCast"; case CK_ObjCObjectLValueCast: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index ce7aca9337bb..eb35dd7c989f 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -674,7 +674,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { case CK_NoOp: case CK_BitCast: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: return Visit(SubExpr); @@ -1808,7 +1809,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_VectorSplat: case CK_IntegralToFloating: case CK_FloatingCast: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_FloatingRealToComplex: @@ -2325,7 +2327,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_FloatingComplexToReal: diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 16aeb451624f..ca58ec05ac5b 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -833,14 +833,16 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { const Type *T = CanonicalType.getTypePtr(); if (const BuiltinType *BT = dyn_cast(T)) { if (BT->getKind() == BuiltinType::Bool) return STK_Bool; - if (BT->getKind() == BuiltinType::NullPtr) return STK_Pointer; + if (BT->getKind() == BuiltinType::NullPtr) return STK_CPointer; if (BT->isInteger()) return STK_Integral; if (BT->isFloatingPoint()) return STK_Floating; llvm_unreachable("unknown scalar builtin type"); - } else if (isa(T) || - isa(T) || - isa(T)) { - return STK_Pointer; + } else if (isa(T)) { + return STK_CPointer; + } else if (isa(T)) { + return STK_BlockPointer; + } else if (isa(T)) { + return STK_ObjCObjectPointer; } else if (isa(T)) { return STK_MemberPointer; } else if (isa(T)) { @@ -853,7 +855,6 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { } llvm_unreachable("unknown scalar type"); - return STK_Pointer; } /// \brief Determines whether the type is a C++ aggregate type or C diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 9364ade96df1..daaf7a588714 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2077,7 +2077,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_ConstructorConversion: case CK_UserDefinedConversion: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: return EmitLValue(E->getSubExpr()); case CK_UncheckedDerivedToBase: diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index bd788d0b0a3b..fe6dfcd28fd4 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -365,7 +365,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_FloatingRealToComplex: diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index c7b9a3071659..90e288a45083 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -403,7 +403,8 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op, case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_FloatingComplexToReal: diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 5c15ec470fbf..b51ff3865628 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -571,7 +571,8 @@ public: case CK_NoOp: return C; - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_LValueBitCast: case CK_BitCast: diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index f4a2695ec9d5..35876d8c319b 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1028,7 +1028,8 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy)); } - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_BitCast: { Value *Src = Visit(const_cast(E)); diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 01748ee82573..17ace4fc1ac8 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -1997,7 +1997,8 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) { // These casts can change the type, so remember that and // soldier on. We only need to remember the outermost such // cast, though. - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_BitCast: if (!resultType) diff --git a/clang/lib/Rewrite/RewriteObjC.cpp b/clang/lib/Rewrite/RewriteObjC.cpp index 645883606a0f..83eba54c9db3 100644 --- a/clang/lib/Rewrite/RewriteObjC.cpp +++ b/clang/lib/Rewrite/RewriteObjC.cpp @@ -1854,9 +1854,15 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { std::string syncBuf; syncBuf += " objc_sync_exit("; - Expr *syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, - S->getSynchExpr()); + + Expr *syncExpr = S->getSynchExpr(); + CastKind CK = syncExpr->getType()->isObjCObjectPointerType() + ? CK_BitCast : + syncExpr->getType()->isBlockPointerType() + ? CK_BlockPointerToObjCPointerCast + : CK_CPointerToObjCPointerCast; + syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CK, syncExpr); std::string syncExprBufS; llvm::raw_string_ostream syncExprBuf(syncExprBufS); syncExpr->printPretty(syncExprBuf, *Context, 0, @@ -2709,7 +2715,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { SourceLocation()); // cast to NSConstantString * CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), - CK_BitCast, Unop); + CK_CPointerToObjCPointerCast, Unop); ReplaceStmt(Exp, cast); // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. return cast; @@ -2849,7 +2855,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // (Class)objc_getClass("CurrentClass") CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCClassType(), - CK_BitCast, Cls); + CK_CPointerToObjCPointerCast, Cls); ClsExprs.clear(); ClsExprs.push_back(ArgExpr); Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, @@ -3051,19 +3057,41 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // Make sure we convert "type (^)(...)" to "type (*)(...)". (void)convertBlockPointerToFunctionPointer(type); const Expr *SubExpr = ICE->IgnoreParenImpCasts(); - bool integral = SubExpr->getType()->isIntegralType(*Context); - userExpr = NoTypeInfoCStyleCastExpr(Context, type, - (integral && type->isBooleanType()) - ? CK_IntegralToBoolean : CK_BitCast, - userExpr); + CastKind CK; + if (SubExpr->getType()->isIntegralType(*Context) && + type->isBooleanType()) { + CK = CK_IntegralToBoolean; + } else if (type->isObjCObjectPointerType()) { + if (SubExpr->getType()->isBlockPointerType()) { + CK = CK_BlockPointerToObjCPointerCast; + } else if (SubExpr->getType()->isPointerType()) { + CK = CK_CPointerToObjCPointerCast; + } else { + CK = CK_BitCast; + } + } else { + CK = CK_BitCast; + } + + userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, userExpr); } // Make id cast into an 'id' cast. else if (CStyleCastExpr *CE = dyn_cast(userExpr)) { if (CE->getType()->isObjCQualifiedIdType()) { while ((CE = dyn_cast(userExpr))) userExpr = CE->getSubExpr(); + CastKind CK; + if (userExpr->getType()->isIntegralType(*Context)) { + CK = CK_IntegralToPointer; + } else if (userExpr->getType()->isBlockPointerType()) { + CK = CK_BlockPointerToObjCPointerCast; + } else if (userExpr->getType()->isPointerType()) { + CK = CK_CPointerToObjCPointerCast; + } else { + CK = CK_BitCast; + } userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CK_BitCast, userExpr); + CK, userExpr); } } MsgExprs.push_back(userExpr); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 7bd0a4a3308d..4e4f80bd0bcc 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -261,7 +261,9 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) { switch (ScalarTy->getScalarTypeKind()) { case Type::STK_Bool: return CK_NoOp; - case Type::STK_Pointer: return CK_PointerToBoolean; + case Type::STK_CPointer: return CK_PointerToBoolean; + case Type::STK_BlockPointer: return CK_PointerToBoolean; + case Type::STK_ObjCObjectPointer: return CK_PointerToBoolean; case Type::STK_MemberPointer: return CK_MemberPointerToBoolean; case Type::STK_Integral: return CK_IntegralToBoolean; case Type::STK_Floating: return CK_FloatingToBoolean; diff --git a/clang/lib/Sema/SemaCXXCast.cpp b/clang/lib/Sema/SemaCXXCast.cpp index 708433f62caa..48f022063ad6 100644 --- a/clang/lib/Sema/SemaCXXCast.cpp +++ b/clang/lib/Sema/SemaCXXCast.cpp @@ -871,7 +871,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, else if (DestType->isObjCObjectPointerType()) { // allow both c-style cast and static_cast of objective-c pointers as // they are pervasive. - Kind = CK_AnyPointerToObjCPointerCast; + Kind = CK_CPointerToObjCPointerCast; return TC_Success; } else if (CStyle && DestType->isBlockPointerType()) { @@ -1630,16 +1630,34 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, (DestType->isBlockPointerType() && SrcType->isObjCObjectPointerType())) return TC_NotApplicable; + 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; + } + } else if (DestType->isBlockPointerType()) { + if (!SrcType->isBlockPointerType()) { + Kind = CK_AnyPointerToBlockPointerCast; + } else { + Kind = CK_BitCast; + } + } else { + Kind = CK_BitCast; + } + // Any pointer can be cast to an Objective-C pointer type with a C-style // cast. if (CStyle && DestType->isObjCObjectPointerType()) { - Kind = CK_AnyPointerToObjCPointerCast; return TC_Success; } // Not casting away constness, so the only remaining check is for compatible // pointer categories. - Kind = IsLValueCast? CK_LValueBitCast : CK_BitCast; if (SrcType->isFunctionPointerType()) { if (DestType->isFunctionPointerType()) { diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 8dfdeb4b6075..94de7992ba1a 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -1767,11 +1767,16 @@ static bool matchTypes(ASTContext &Context, Sema::MethodMatchStrategy strategy, if (!left->isScalarType() || !right->isScalarType()) return tryMatchRecordTypes(Context, strategy, left, right); - // Make scalars agree in kind, except count bools as chars. + // Make scalars agree in kind, except count bools as chars, and group + // all non-member pointers together. Type::ScalarTypeKind leftSK = left->getScalarTypeKind(); Type::ScalarTypeKind rightSK = right->getScalarTypeKind(); if (leftSK == Type::STK_Bool) leftSK = Type::STK_Integral; if (rightSK == Type::STK_Bool) rightSK = Type::STK_Integral; + if (leftSK == Type::STK_CPointer || leftSK == Type::STK_BlockPointer) + leftSK = Type::STK_ObjCObjectPointer; + if (rightSK == Type::STK_CPointer || rightSK == Type::STK_BlockPointer) + rightSK = Type::STK_ObjCObjectPointer; // Note that data member pointers and function member pointers don't // intermix because of the size differences. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d20dee44d3d6..f10bb3413cbf 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3808,16 +3808,26 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { if (S.Context.hasSameUnqualifiedType(SrcTy, DestTy)) return CK_NoOp; - switch (SrcTy->getScalarTypeKind()) { + switch (Type::ScalarTypeKind SrcKind = SrcTy->getScalarTypeKind()) { case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); - case Type::STK_Pointer: + case Type::STK_CPointer: + case Type::STK_BlockPointer: + case Type::STK_ObjCObjectPointer: switch (DestTy->getScalarTypeKind()) { - case Type::STK_Pointer: - return DestTy->isObjCObjectPointerType() ? - CK_AnyPointerToObjCPointerCast : - CK_BitCast; + case Type::STK_CPointer: + return CK_BitCast; + case Type::STK_BlockPointer: + return (SrcKind == Type::STK_BlockPointer + ? CK_BitCast : CK_AnyPointerToBlockPointerCast); + case Type::STK_ObjCObjectPointer: + if (SrcKind == Type::STK_ObjCObjectPointer) + return CK_BitCast; + else if (SrcKind == Type::STK_CPointer) + return CK_CPointerToObjCPointerCast; + else + return CK_BlockPointerToObjCPointerCast; case Type::STK_Bool: return CK_PointerToBoolean; case Type::STK_Integral: @@ -3833,7 +3843,9 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { case Type::STK_Bool: // casting from bool is like casting from an integer case Type::STK_Integral: switch (DestTy->getScalarTypeKind()) { - case Type::STK_Pointer: + case Type::STK_CPointer: + case Type::STK_ObjCObjectPointer: + case Type::STK_BlockPointer: if (Src.get()->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) return CK_NullToPointer; @@ -3877,7 +3889,9 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { DestTy->getAs()->getElementType(), CK_FloatingToIntegral); return CK_IntegralRealToComplex; - case Type::STK_Pointer: + case Type::STK_CPointer: + case Type::STK_ObjCObjectPointer: + case Type::STK_BlockPointer: llvm_unreachable("valid float->pointer cast?"); case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); @@ -3904,7 +3918,9 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { SrcTy->getAs()->getElementType(), CK_FloatingComplexToReal); return CK_FloatingToIntegral; - case Type::STK_Pointer: + case Type::STK_CPointer: + case Type::STK_ObjCObjectPointer: + case Type::STK_BlockPointer: llvm_unreachable("valid complex float->pointer cast?"); case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); @@ -3931,7 +3947,9 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { SrcTy->getAs()->getElementType(), CK_IntegralComplexToReal); return CK_IntegralToFloating; - case Type::STK_Pointer: + case Type::STK_CPointer: + case Type::STK_ObjCObjectPointer: + case Type::STK_BlockPointer: llvm_unreachable("valid complex int->pointer cast?"); case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); @@ -3940,7 +3958,6 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { } llvm_unreachable("Unhandled scalar cast"); - return CK_BitCast; } /// CheckCastTypes - Check type constraints for casting between types. @@ -4497,12 +4514,12 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, QualType lhptee, rhptee; // Get the pointee types. - if (LHSTy->isBlockPointerType()) { - lhptee = LHSTy->getAs()->getPointeeType(); - rhptee = RHSTy->getAs()->getPointeeType(); + if (const BlockPointerType *LHSBTy = LHSTy->getAs()) { + lhptee = LHSBTy->getPointeeType(); + rhptee = RHSTy->castAs()->getPointeeType(); } else { - lhptee = LHSTy->getAs()->getPointeeType(); - rhptee = RHSTy->getAs()->getPointeeType(); + lhptee = LHSTy->castAs()->getPointeeType(); + rhptee = RHSTy->castAs()->getPointeeType(); } if (!S.Context.typesAreCompatible(lhptee.getUnqualifiedType(), @@ -4752,23 +4769,23 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, // redefinition type if an attempt is made to access its fields. if (LHSTy->isObjCClassType() && (Context.hasSameType(RHSTy, Context.getObjCClassRedefinitionType()))) { - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_CPointerToObjCPointerCast); return LHSTy; } if (RHSTy->isObjCClassType() && (Context.hasSameType(LHSTy, Context.getObjCClassRedefinitionType()))) { - LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_CPointerToObjCPointerCast); return RHSTy; } // And the same for struct objc_object* / id if (LHSTy->isObjCIdType() && (Context.hasSameType(RHSTy, Context.getObjCIdRedefinitionType()))) { - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_CPointerToObjCPointerCast); return LHSTy; } if (RHSTy->isObjCIdType() && (Context.hasSameType(LHSTy, Context.getObjCIdRedefinitionType()))) { - LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_CPointerToObjCPointerCast); return RHSTy; } // And the same for struct objc_selector* / SEL @@ -4789,8 +4806,8 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, // Two identical object pointer types are always compatible. return LHSTy; } - const ObjCObjectPointerType *LHSOPT = LHSTy->getAs(); - const ObjCObjectPointerType *RHSOPT = RHSTy->getAs(); + const ObjCObjectPointerType *LHSOPT = LHSTy->castAs(); + const ObjCObjectPointerType *RHSOPT = RHSTy->castAs(); QualType compositeType = LHSTy; // If both operands are interfaces and either operand can be @@ -5356,7 +5373,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, if (isa(RHSType)) { // - conversions to void* if (LHSPointer->getPointeeType()->isVoidType()) { - Kind = CK_AnyPointerToObjCPointerCast; + Kind = CK_BitCast; return Compatible; } @@ -5387,7 +5404,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, if (isa(LHSType)) { // U^ -> T^ if (RHSType->isBlockPointerType()) { - Kind = CK_AnyPointerToBlockPointerCast; + Kind = CK_BitCast; return checkBlockPointerTypesForAssignment(*this, LHSType, RHSType); } @@ -5436,9 +5453,10 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, // In general, C pointers are not compatible with ObjC object pointers, // with two exceptions: if (isa(RHSType)) { + Kind = CK_CPointerToObjCPointerCast; + // - conversions from 'void*' if (RHSType->isVoidPointerType()) { - Kind = CK_AnyPointerToObjCPointerCast; return Compatible; } @@ -5446,17 +5464,15 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, if (LHSType->isObjCClassType() && Context.hasSameType(RHSType, Context.getObjCClassRedefinitionType())) { - Kind = CK_BitCast; return Compatible; } - Kind = CK_AnyPointerToObjCPointerCast; return IncompatiblePointer; } // T^ -> A* if (RHSType->isBlockPointerType()) { - Kind = CK_AnyPointerToObjCPointerCast; + Kind = CK_BlockPointerToObjCPointerCast; return Compatible; } @@ -5553,7 +5569,7 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, // 1) void pointer // 2) null pointer constant if (RHSType->isPointerType()) - if (RHSType->getAs()->getPointeeType()->isVoidType()) { + if (RHSType->castAs()->getPointeeType()->isVoidType()) { RHS = ImpCastExprToType(RHS.take(), it->getType(), CK_BitCast); InitField = *it; break; @@ -6452,9 +6468,9 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // when handling null pointer constants. if (LHSType->isPointerType() && RHSType->isPointerType()) { // C99 6.5.8p2 QualType LCanPointeeTy = - Context.getCanonicalType(LHSType->getAs()->getPointeeType()); + LHSType->castAs()->getPointeeType().getCanonicalType(); QualType RCanPointeeTy = - Context.getCanonicalType(RHSType->getAs()->getPointeeType()); + RHSType->castAs()->getPointeeType().getCanonicalType(); if (getLangOptions().CPlusPlus) { if (LCanPointeeTy == RCanPointeeTy) @@ -6560,8 +6576,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // Handle block pointer types. if (!IsRelational && LHSType->isBlockPointerType() && RHSType->isBlockPointerType()) { - QualType lpointee = LHSType->getAs()->getPointeeType(); - QualType rpointee = RHSType->getAs()->getPointeeType(); + QualType lpointee = LHSType->castAs()->getPointeeType(); + QualType rpointee = RHSType->castAs()->getPointeeType(); if (!LHSIsNull && !RHSIsNull && !Context.typesAreCompatible(lpointee, rpointee)) { @@ -6587,9 +6603,13 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, << RHS.get()->getSourceRange(); } if (LHSIsNull && !RHSIsNull) - LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSType, + RHSType->isPointerType() ? CK_BitCast + : CK_AnyPointerToBlockPointerCast); else - RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, + LHSType->isPointerType() ? CK_BitCast + : CK_AnyPointerToBlockPointerCast); return ResultTy; } @@ -6607,9 +6627,11 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, /*isError*/false); } if (LHSIsNull && !RHSIsNull) - LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSType, + RPT ? CK_BitCast :CK_CPointerToObjCPointerCast); else - RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, + LPT ? CK_BitCast :CK_CPointerToObjCPointerCast); return ResultTy; } if (LHSType->isObjCObjectPointerType() && diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 9f2696e12888..f6ace99bf6c0 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -1357,7 +1357,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, << Receiver->getSourceRange(); if (ReceiverType->isPointerType()) Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), - CK_BitCast).take(); + CK_CPointerToObjCPointerCast).take(); else { // TODO: specialized warning on null receivers? bool IsNull = Receiver->isNullPointerConstant(Context, @@ -1594,7 +1594,8 @@ namespace { case CK_NoOp: case CK_LValueToRValue: case CK_BitCast: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: return Visit(e->getSubExpr()); default: @@ -1836,11 +1837,16 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, QualType T = TSInfo->getType(); QualType FromType = SubExpr->getType(); + CastKind CK; + bool MustConsume = false; if (T->isDependentType() || SubExpr->isTypeDependent()) { // Okay: we'll build a dependent expression type. + CK = CK_Dependent; } else if (T->isObjCARCBridgableType() && FromType->isCARCBridgableType()) { // Casting CF -> id + CK = (T->isBlockPointerType() ? CK_AnyPointerToBlockPointerCast + : CK_CPointerToObjCPointerCast); switch (Kind) { case OBC_Bridge: break; @@ -1870,6 +1876,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, } } else if (T->isCARCBridgableType() && FromType->isObjCARCBridgableType()) { // Okay: id -> CF + CK = CK_BitCast; switch (Kind) { case OBC_Bridge: // Reclaiming a value that's going to be __bridge-casted to CF @@ -1910,7 +1917,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, return ExprError(); } - Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind, + Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind, CK, BridgeKeywordLoc, TSInfo, SubExpr); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 4f36189ce567..c0b83d9b47ae 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -2133,8 +2133,8 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, PDiag(diag::warn_impcast_bool_to_null_pointer) << ToType << From->getSourceRange()); - if (const PointerType *FromPtrType = FromType->getAs()) - if (const PointerType *ToPtrType = ToType->getAs()) { + if (const PointerType *ToPtrType = ToType->getAs()) { + if (const PointerType *FromPtrType = FromType->getAs()) { QualType FromPointeeType = FromPtrType->getPointeeType(), ToPointeeType = ToPtrType->getPointeeType(); @@ -2152,16 +2152,23 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, Kind = CK_DerivedToBase; } } - if (const ObjCObjectPointerType *FromPtrType = - FromType->getAs()) { - if (const ObjCObjectPointerType *ToPtrType = - ToType->getAs()) { + } else if (const ObjCObjectPointerType *ToPtrType = + ToType->getAs()) { + if (const ObjCObjectPointerType *FromPtrType = + FromType->getAs()) { // Objective-C++ conversions are always okay. // FIXME: We should have a different class of conversions for the // Objective-C++ implicit conversions. if (FromPtrType->isObjCBuiltinType() || ToPtrType->isObjCBuiltinType()) return false; + } else if (FromType->isBlockPointerType()) { + Kind = CK_BlockPointerToObjCPointerCast; + } else { + Kind = CK_CPointerToObjCPointerCast; } + } else if (ToType->isBlockPointerType()) { + if (!FromType->isBlockPointerType()) + Kind = CK_AnyPointerToBlockPointerCast; } // We shouldn't fall into this case unless it's valid for other diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 47debad09c3d..1d7cd0d53f62 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -248,7 +248,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_IntegralComplexToBoolean: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: - case CK_AnyPointerToObjCPointerCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: { // Delegate to SValBuilder to process.