diff options
Diffstat (limited to 'lib/Sema/SemaCast.cpp')
-rw-r--r-- | lib/Sema/SemaCast.cpp | 457 |
1 files changed, 259 insertions, 198 deletions
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index ad6348685b64e..b7f4629fbab75 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -33,10 +33,16 @@ using namespace clang; enum TryCastResult { TC_NotApplicable, ///< The cast method is not applicable. TC_Success, ///< The cast method is appropriate and successful. + TC_Extension, ///< The cast method is appropriate and accepted as a + ///< language extension. TC_Failed ///< The cast method is appropriate, but failed. A ///< diagnostic has been emitted. }; +static bool isValidCast(TryCastResult TCR) { + return TCR == TC_Success || TCR == TC_Extension; +} + enum CastType { CT_Const, ///< const_cast CT_Static, ///< static_cast @@ -83,6 +89,14 @@ namespace { void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization); void CheckCStyleCast(); + void updatePartOfExplicitCastFlags(CastExpr *CE) { + // Walk down from the CE to the OrigSrcExpr, and mark all immediate + // ImplicitCastExpr's as being part of ExplicitCastExpr. The original CE + // (which is a ExplicitCastExpr), and the OrigSrcExpr are not touched. + for (; auto *ICE = dyn_cast<ImplicitCastExpr>(CE->getSubExpr()); CE = ICE) + ICE->setIsPartOfExplicitCast(true); + } + /// Complete an apparently-successful cast operation that yields /// the given expression. ExprResult complete(CastExpr *castExpr) { @@ -94,6 +108,7 @@ namespace { CK_Dependent, castExpr, nullptr, castExpr->getValueKind()); } + updatePartOfExplicitCastFlags(castExpr); return castExpr; } @@ -267,6 +282,12 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, AngleBrackets)); case tok::kw_dynamic_cast: { + // OpenCL C++ 1.0 s2.9: dynamic_cast is not supported. + if (getLangOpts().OpenCLCPlusPlus) { + return ExprError(Diag(OpLoc, diag::err_openclcxx_not_supported) + << "dynamic_cast"); + } + if (!TypeDependent) { Op.CheckDynamicCast(); if (Op.SrcExpr.isInvalid()) @@ -425,95 +446,114 @@ static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType, } } -/// UnwrapDissimilarPointerTypes - Like Sema::UnwrapSimilarPointerTypes, -/// this removes one level of indirection from both types, provided that they're -/// the same kind of pointer (plain or to-member). Unlike the Sema function, -/// this one doesn't care if the two pointers-to-member don't point into the -/// same class. This is because CastsAwayConstness doesn't care. -/// And additionally, it handles C++ references. If both the types are -/// references, then their pointee types are returned, -/// else if only one of them is reference, it's pointee type is returned, -/// and the other type is returned as-is. -static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) { - const PointerType *T1PtrType = T1->getAs<PointerType>(), - *T2PtrType = T2->getAs<PointerType>(); - if (T1PtrType && T2PtrType) { - T1 = T1PtrType->getPointeeType(); - T2 = T2PtrType->getPointeeType(); - return true; - } - const ObjCObjectPointerType *T1ObjCPtrType = - T1->getAs<ObjCObjectPointerType>(), - *T2ObjCPtrType = - T2->getAs<ObjCObjectPointerType>(); - if (T1ObjCPtrType) { - if (T2ObjCPtrType) { - T1 = T1ObjCPtrType->getPointeeType(); - T2 = T2ObjCPtrType->getPointeeType(); - return true; - } - else if (T2PtrType) { - T1 = T1ObjCPtrType->getPointeeType(); - T2 = T2PtrType->getPointeeType(); - return true; - } - } - else if (T2ObjCPtrType) { - if (T1PtrType) { - T2 = T2ObjCPtrType->getPointeeType(); - T1 = T1PtrType->getPointeeType(); - return true; - } - } - - const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(), - *T2MPType = T2->getAs<MemberPointerType>(); - if (T1MPType && T2MPType) { - T1 = T1MPType->getPointeeType(); - T2 = T2MPType->getPointeeType(); - return true; - } - - const BlockPointerType *T1BPType = T1->getAs<BlockPointerType>(), - *T2BPType = T2->getAs<BlockPointerType>(); - if (T1BPType && T2BPType) { - T1 = T1BPType->getPointeeType(); - T2 = T2BPType->getPointeeType(); - return true; - } - - const LValueReferenceType *T1RefType = T1->getAs<LValueReferenceType>(), - *T2RefType = T2->getAs<LValueReferenceType>(); - if (T1RefType && T2RefType) { - T1 = T1RefType->getPointeeType(); - T2 = T2RefType->getPointeeType(); - return true; - } +namespace { +/// The kind of unwrapping we did when determining whether a conversion casts +/// away constness. +enum CastAwayConstnessKind { + /// The conversion does not cast away constness. + CACK_None = 0, + /// We unwrapped similar types. + CACK_Similar = 1, + /// We unwrapped dissimilar types with similar representations (eg, a pointer + /// versus an Objective-C object pointer). + CACK_SimilarKind = 2, + /// We unwrapped representationally-unrelated types, such as a pointer versus + /// a pointer-to-member. + CACK_Incoherent = 3, +}; +} - if (T1RefType) { - T1 = T1RefType->getPointeeType(); - // T2 = T2; - return true; +/// Unwrap one level of types for CastsAwayConstness. +/// +/// Like Sema::UnwrapSimilarTypes, this removes one level of indirection from +/// both types, provided that they're both pointer-like or array-like. Unlike +/// the Sema function, doesn't care if the unwrapped pieces are related. +/// +/// This function may remove additional levels as necessary for correctness: +/// the resulting T1 is unwrapped sufficiently that it is never an array type, +/// so that its qualifiers can be directly compared to those of T2 (which will +/// have the combined set of qualifiers from all indermediate levels of T2), +/// as (effectively) required by [expr.const.cast]p7 replacing T1's qualifiers +/// with those from T2. +static CastAwayConstnessKind +unwrapCastAwayConstnessLevel(ASTContext &Context, QualType &T1, QualType &T2) { + enum { None, Ptr, MemPtr, BlockPtr, Array }; + auto Classify = [](QualType T) { + if (T->isAnyPointerType()) return Ptr; + if (T->isMemberPointerType()) return MemPtr; + if (T->isBlockPointerType()) return BlockPtr; + // We somewhat-arbitrarily don't look through VLA types here. This is at + // least consistent with the behavior of UnwrapSimilarTypes. + if (T->isConstantArrayType() || T->isIncompleteArrayType()) return Array; + return None; + }; + + auto Unwrap = [&](QualType T) { + if (auto *AT = Context.getAsArrayType(T)) + return AT->getElementType(); + return T->getPointeeType(); + }; + + CastAwayConstnessKind Kind; + + if (T2->isReferenceType()) { + // Special case: if the destination type is a reference type, unwrap it as + // the first level. (The source will have been an lvalue expression in this + // case, so there is no corresponding "reference to" in T1 to remove.) This + // simulates removing a "pointer to" from both sides. + T2 = T2->getPointeeType(); + Kind = CastAwayConstnessKind::CACK_Similar; + } else if (Context.UnwrapSimilarTypes(T1, T2)) { + Kind = CastAwayConstnessKind::CACK_Similar; + } else { + // Try unwrapping mismatching levels. + int T1Class = Classify(T1); + if (T1Class == None) + return CastAwayConstnessKind::CACK_None; + + int T2Class = Classify(T2); + if (T2Class == None) + return CastAwayConstnessKind::CACK_None; + + T1 = Unwrap(T1); + T2 = Unwrap(T2); + Kind = T1Class == T2Class ? CastAwayConstnessKind::CACK_SimilarKind + : CastAwayConstnessKind::CACK_Incoherent; } - if (T2RefType) { - // T1 = T1; - T2 = T2RefType->getPointeeType(); - return true; + // We've unwrapped at least one level. If the resulting T1 is a (possibly + // multidimensional) array type, any qualifier on any matching layer of + // T2 is considered to correspond to T1. Decompose down to the element + // type of T1 so that we can compare properly. + while (true) { + Context.UnwrapSimilarArrayTypes(T1, T2); + + if (Classify(T1) != Array) + break; + + auto T2Class = Classify(T2); + if (T2Class == None) + break; + + if (T2Class != Array) + Kind = CastAwayConstnessKind::CACK_Incoherent; + else if (Kind != CastAwayConstnessKind::CACK_Incoherent) + Kind = CastAwayConstnessKind::CACK_SimilarKind; + + T1 = Unwrap(T1); + T2 = Unwrap(T2).withCVRQualifiers(T2.getCVRQualifiers()); } - return false; + return Kind; } -/// CastsAwayConstness - Check if the pointer conversion from SrcType to -/// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by -/// the cast checkers. Both arguments must denote pointer (possibly to member) -/// types. +/// Check if the pointer conversion from SrcType to DestType casts away +/// constness as defined in C++ [expr.const.cast]. This is used by the cast +/// checkers. Both arguments must denote pointer (possibly to member) types. /// /// \param CheckCVR Whether to check for const/volatile/restrict qualifiers. -/// /// \param CheckObjCLifetime Whether to check Objective-C lifetime qualifiers. -static bool +static CastAwayConstnessKind CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, bool CheckCVR, bool CheckObjCLifetime, QualType *TheOffendingSrcType = nullptr, @@ -521,33 +561,35 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, Qualifiers *CastAwayQualifiers = nullptr) { // If the only checking we care about is for Objective-C lifetime qualifiers, // and we're not in ObjC mode, there's nothing to check. - if (!CheckCVR && CheckObjCLifetime && - !Self.Context.getLangOpts().ObjC1) - return false; - - // Casting away constness is defined in C++ 5.2.11p8 with reference to - // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since - // the rules are non-trivial. So first we construct Tcv *...cv* as described - // in C++ 5.2.11p8. - assert((SrcType->isAnyPointerType() || SrcType->isMemberPointerType() || - SrcType->isBlockPointerType() || - DestType->isLValueReferenceType()) && - "Source type is not pointer or pointer to member."); - assert((DestType->isAnyPointerType() || DestType->isMemberPointerType() || - DestType->isBlockPointerType() || - DestType->isLValueReferenceType()) && - "Destination type is not pointer or pointer to member, or reference."); + if (!CheckCVR && CheckObjCLifetime && !Self.Context.getLangOpts().ObjC1) + return CastAwayConstnessKind::CACK_None; + + if (!DestType->isReferenceType()) { + assert((SrcType->isAnyPointerType() || SrcType->isMemberPointerType() || + SrcType->isBlockPointerType()) && + "Source type is not pointer or pointer to member."); + assert((DestType->isAnyPointerType() || DestType->isMemberPointerType() || + DestType->isBlockPointerType()) && + "Destination type is not pointer or pointer to member."); + } QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType), UnwrappedDestType = Self.Context.getCanonicalType(DestType); - SmallVector<Qualifiers, 8> cv1, cv2; // Find the qualifiers. We only care about cvr-qualifiers for the // purpose of this check, because other qualifiers (address spaces, // Objective-C GC, etc.) are part of the type's identity. QualType PrevUnwrappedSrcType = UnwrappedSrcType; QualType PrevUnwrappedDestType = UnwrappedDestType; - while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) { + auto WorstKind = CastAwayConstnessKind::CACK_Similar; + bool AllConstSoFar = true; + while (auto Kind = unwrapCastAwayConstnessLevel( + Self.Context, UnwrappedSrcType, UnwrappedDestType)) { + // Track the worst kind of unwrap we needed to do before we found a + // problem. + if (Kind > WorstKind) + WorstKind = Kind; + // Determine the relevant qualifiers at this level. Qualifiers SrcQuals, DestQuals; Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals); @@ -560,51 +602,71 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, UnwrappedDestType->isObjCObjectType()) SrcQuals.removeConst(); - Qualifiers RetainedSrcQuals, RetainedDestQuals; if (CheckCVR) { - RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers()); - RetainedDestQuals.setCVRQualifiers(DestQuals.getCVRQualifiers()); + Qualifiers SrcCvrQuals = + Qualifiers::fromCVRMask(SrcQuals.getCVRQualifiers()); + Qualifiers DestCvrQuals = + Qualifiers::fromCVRMask(DestQuals.getCVRQualifiers()); + + if (SrcCvrQuals != DestCvrQuals) { + if (CastAwayQualifiers) + *CastAwayQualifiers = SrcCvrQuals - DestCvrQuals; + + // If we removed a cvr-qualifier, this is casting away 'constness'. + if (!DestCvrQuals.compatiblyIncludes(SrcCvrQuals)) { + if (TheOffendingSrcType) + *TheOffendingSrcType = PrevUnwrappedSrcType; + if (TheOffendingDestType) + *TheOffendingDestType = PrevUnwrappedDestType; + return WorstKind; + } - if (RetainedSrcQuals != RetainedDestQuals && TheOffendingSrcType && - TheOffendingDestType && CastAwayQualifiers) { - *TheOffendingSrcType = PrevUnwrappedSrcType; - *TheOffendingDestType = PrevUnwrappedDestType; - *CastAwayQualifiers = RetainedSrcQuals - RetainedDestQuals; + // If any prior level was not 'const', this is also casting away + // 'constness'. We noted the outermost type missing a 'const' already. + if (!AllConstSoFar) + return WorstKind; } } - + if (CheckObjCLifetime && !DestQuals.compatiblyIncludesObjCLifetime(SrcQuals)) - return true; - - cv1.push_back(RetainedSrcQuals); - cv2.push_back(RetainedDestQuals); + return WorstKind; + + // If we found our first non-const-qualified type, this may be the place + // where things start to go wrong. + if (AllConstSoFar && !DestQuals.hasConst()) { + AllConstSoFar = false; + if (TheOffendingSrcType) + *TheOffendingSrcType = PrevUnwrappedSrcType; + if (TheOffendingDestType) + *TheOffendingDestType = PrevUnwrappedDestType; + } PrevUnwrappedSrcType = UnwrappedSrcType; PrevUnwrappedDestType = UnwrappedDestType; } - if (cv1.empty()) - return false; - // Construct void pointers with those qualifiers (in reverse order of - // unwrapping, of course). - QualType SrcConstruct = Self.Context.VoidTy; - QualType DestConstruct = Self.Context.VoidTy; - ASTContext &Context = Self.Context; - for (SmallVectorImpl<Qualifiers>::reverse_iterator i1 = cv1.rbegin(), - i2 = cv2.rbegin(); - i1 != cv1.rend(); ++i1, ++i2) { - SrcConstruct - = Context.getPointerType(Context.getQualifiedType(SrcConstruct, *i1)); - DestConstruct - = Context.getPointerType(Context.getQualifiedType(DestConstruct, *i2)); - } - - // Test if they're compatible. - bool ObjCLifetimeConversion; - return SrcConstruct != DestConstruct && - !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false, - ObjCLifetimeConversion); + return CastAwayConstnessKind::CACK_None; +} + +static TryCastResult getCastAwayConstnessCastKind(CastAwayConstnessKind CACK, + unsigned &DiagID) { + switch (CACK) { + case CastAwayConstnessKind::CACK_None: + llvm_unreachable("did not cast away constness"); + + case CastAwayConstnessKind::CACK_Similar: + // FIXME: Accept these as an extension too? + case CastAwayConstnessKind::CACK_SimilarKind: + DiagID = diag::err_bad_cxx_cast_qualifiers_away; + return TC_Failed; + + case CastAwayConstnessKind::CACK_Incoherent: + DiagID = diag::ext_bad_cxx_cast_qualifiers_away_incoherent; + return TC_Extension; + } + + llvm_unreachable("unexpected cast away constness kind"); } /// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid. @@ -772,12 +834,13 @@ void CastOperation::CheckConstCast() { return; unsigned msg = diag::err_bad_cxx_cast_generic; - if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success - && msg != 0) { + auto TCR = TryConstCast(Self, SrcExpr, DestType, /*CStyle*/ false, msg); + if (TCR != TC_Success && msg != 0) { Self.Diag(OpRange.getBegin(), msg) << CT_Const << SrcExpr.get()->getType() << DestType << OpRange; - SrcExpr = ExprError(); } + if (!isValidCast(TCR)) + SrcExpr = ExprError(); } /// Check that a reinterpret_cast\<DestType\>(SrcExpr) is not used as upcast @@ -890,8 +953,7 @@ void CastOperation::CheckReinterpretCast() { TryCastResult tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg, Kind); - if (tcr != TC_Success && msg != 0) - { + if (tcr != TC_Success && msg != 0) { if (SrcExpr.isInvalid()) // if conversion failed, don't report another error return; if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { @@ -905,11 +967,14 @@ void CastOperation::CheckReinterpretCast() { diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType, /*listInitialization=*/false); } - SrcExpr = ExprError(); - } else if (tcr == TC_Success) { + } + + if (isValidCast(tcr)) { if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()) checkObjCConversion(Sema::CCK_OtherCast); DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange); + } else { + SrcExpr = ExprError(); } } @@ -967,14 +1032,15 @@ void CastOperation::CheckStaticCast() { diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType, /*listInitialization=*/false); } - SrcExpr = ExprError(); - } else if (tcr == TC_Success) { + } + + if (isValidCast(tcr)) { if (Kind == CK_BitCast) checkCastAlign(); if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()) checkObjCConversion(Sema::CCK_OtherCast); - } else if (Kind == CK_BitCast) { - checkCastAlign(); + } else { + SrcExpr = ExprError(); } } @@ -1145,7 +1211,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, } } } - // Allow arbitray objective-c pointer conversion with static casts. + // Allow arbitrary objective-c pointer conversion with static casts. if (SrcType->isObjCObjectPointerType() && DestType->isObjCObjectPointerType()) { Kind = CK_BitCast; @@ -1663,29 +1729,14 @@ static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr, msg = diag::err_bad_const_cast_dest; return TC_NotApplicable; } - SrcType = Self.Context.getCanonicalType(SrcType); - - // Unwrap the pointers. Ignore qualifiers. Terminate early if the types are - // completely equal. - // C++ 5.2.11p3 describes the core semantics of const_cast. All cv specifiers - // in multi-level pointers may change, but the level count must be the same, - // as must be the final pointee type. - while (SrcType != DestType && - Self.Context.UnwrapSimilarPointerTypes(SrcType, DestType)) { - Qualifiers SrcQuals, DestQuals; - SrcType = Self.Context.getUnqualifiedArrayType(SrcType, SrcQuals); - DestType = Self.Context.getUnqualifiedArrayType(DestType, DestQuals); - - // const_cast is permitted to strip cvr-qualifiers, only. Make sure that - // the other qualifiers (e.g., address spaces) are identical. - SrcQuals.removeCVRQualifiers(); - DestQuals.removeCVRQualifiers(); - if (SrcQuals != DestQuals) - return TC_NotApplicable; - } - // Since we're dealing in canonical types, the remainder must be the same. - if (SrcType != DestType) + // C++ [expr.const.cast]p3: + // "For two similar types T1 and T2, [...]" + // + // We only allow a const_cast to change cvr-qualifiers, not other kinds of + // type qualifiers. (Likewise, we ignore other changes when determining + // whether a cast casts away constness.) + if (!Self.Context.hasCvrSimilarType(SrcType, DestType)) return TC_NotApplicable; if (NeedToMaterializeTemporary) @@ -1913,6 +1964,12 @@ static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType, return Result.isUsable(); } +static bool IsAddressSpaceConversion(QualType SrcType, QualType DestType) { + return SrcType->isPointerType() && DestType->isPointerType() && + SrcType->getAs<PointerType>()->getPointeeType().getAddressSpace() != + DestType->getAs<PointerType>()->getPointeeType().getAddressSpace(); +} + static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, SourceRange OpRange, @@ -1994,16 +2051,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, SrcMemPtr->isMemberFunctionPointer()) return TC_NotApplicable; - // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away - // constness. - // A reinterpret_cast followed by a const_cast can, though, so in C-style, - // we accept it. - if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle, - /*CheckObjCLifetime=*/CStyle)) { - msg = diag::err_bad_cxx_cast_qualifiers_away; - return TC_Failed; - } - if (Self.Context.getTargetInfo().getCXXABI().isMicrosoft()) { // We need to determine the inheritance model that the class will use if // haven't yet. @@ -2018,6 +2065,15 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_Failed; } + // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away + // constness. + // A reinterpret_cast followed by a const_cast can, though, so in C-style, + // we accept it. + if (auto CACK = + CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle, + /*CheckObjCLifetime=*/CStyle)) + return getCastAwayConstnessCastKind(CACK, msg); + // A valid member pointer cast. assert(!IsLValueCast); Kind = CK_ReinterpretMemberPointer; @@ -2134,19 +2190,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_NotApplicable; } - // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness. - // The C-style cast operator can. - if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle, - /*CheckObjCLifetime=*/CStyle)) { - msg = diag::err_bad_cxx_cast_qualifiers_away; - return TC_Failed; - } - // Cannot convert between block pointers and Objective-C object pointers. if ((SrcType->isBlockPointerType() && DestType->isObjCObjectPointerType()) || (DestType->isBlockPointerType() && SrcType->isObjCObjectPointerType())) return TC_NotApplicable; + // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness. + // The C-style cast operator can. + TryCastResult SuccessResult = TC_Success; + if (auto CACK = + CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle, + /*CheckObjCLifetime=*/CStyle)) + SuccessResult = getCastAwayConstnessCastKind(CACK, msg); + if (IsLValueCast) { Kind = CK_LValueBitCast; } else if (DestType->isObjCObjectPointerType()) { @@ -2157,6 +2213,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, } else { Kind = CK_BitCast; } + } else if (IsAddressSpaceConversion(SrcType, DestType)) { + Kind = CK_AddressSpaceConversion; } else { Kind = CK_BitCast; } @@ -2164,7 +2222,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // Any pointer can be cast to an Objective-C pointer type with a C-style // cast. if (CStyle && DestType->isObjCObjectPointerType()) { - return TC_Success; + return SuccessResult; } if (CStyle) DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType); @@ -2178,7 +2236,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, if (DestType->isFunctionPointerType()) { // C++ 5.2.10p6: A pointer to a function can be explicitly converted to // a pointer to a function of a different type. - return TC_Success; + return SuccessResult; } // C++0x 5.2.10p8: Converting a pointer to a function into a pointer to @@ -2191,7 +2249,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, Self.getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj) << OpRange; - return TC_Success; + return SuccessResult; } if (DestType->isFunctionPointerType()) { @@ -2200,7 +2258,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, Self.getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj) << OpRange; - return TC_Success; + return SuccessResult; } // C++ 5.2.10p7: A pointer to an object can be explicitly converted to @@ -2208,8 +2266,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // Void pointers are not specified, but supported by every compiler out there. // So we finish by allowing everything that remains - it's got to be two // object pointers. - return TC_Success; -} + return SuccessResult; +} void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, bool ListInitialization) { @@ -2289,7 +2347,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, /*CStyle*/true, msg); if (SrcExpr.isInvalid()) return; - if (tcr == TC_Success) + if (isValidCast(tcr)) Kind = CK_NoOp; Sema::CheckedConversionKind CCK @@ -2312,7 +2370,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, } if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && - tcr == TC_Success) + isValidCast(tcr)) checkObjCConversion(CCK); if (tcr != TC_Success && msg != 0) { @@ -2336,13 +2394,14 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, diagnoseBadCast(Self, msg, (FunctionalStyle ? CT_Functional : CT_CStyle), OpRange, SrcExpr.get(), DestType, ListInitialization); } - } else if (Kind == CK_BitCast) { - checkCastAlign(); } - // Clear out SrcExpr if there was a fatal error. - if (tcr != TC_Success) + if (isValidCast(tcr)) { + if (Kind == CK_BitCast) + checkCastAlign(); + } else { SrcExpr = ExprError(); + } } /// DiagnoseBadFunctionCast - Warn whenever a function call is cast to a @@ -2627,11 +2686,13 @@ static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr, QualType TheOffendingSrcType, TheOffendingDestType; Qualifiers CastAwayQualifiers; - if (!CastsAwayConstness(Self, SrcType, DestType, true, false, - &TheOffendingSrcType, &TheOffendingDestType, - &CastAwayQualifiers)) + if (CastsAwayConstness(Self, SrcType, DestType, true, false, + &TheOffendingSrcType, &TheOffendingDestType, + &CastAwayQualifiers) != + CastAwayConstnessKind::CACK_Similar) return; + // FIXME: 'restrict' is not properly handled here. int qualifiers = -1; if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) { qualifiers = 0; |