/// 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. bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { // 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->isPointerType() || SrcType->isMemberPointerType()) && "Source type is not pointer or pointer to member."); assert((DestType->isPointerType() || DestType->isMemberPointerType()) && "Destination type is not pointer or pointer to member."); QualType UnwrappedSrcType = SrcType, UnwrappedDestType = DestType; llvm::SmallVector<unsigned, 8> cv1, cv2; // Find the qualifications. while (Self.UnwrapSimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) { cv1.push_back(UnwrappedSrcType.getCVRQualifiers()); cv2.push_back(UnwrappedDestType.getCVRQualifiers()); } assert(cv1.size() > 0 && "Must have at least one pointer level."); // Construct void pointers with those qualifiers (in reverse order of // unwrapping, of course). QualType SrcConstruct = Self.Context.VoidTy; QualType DestConstruct = Self.Context.VoidTy; for (llvm::SmallVector<unsigned, 8>::reverse_iterator i1 = cv1.rbegin(), i2 = cv2.rbegin(); i1 != cv1.rend(); ++i1, ++i2) { SrcConstruct = Self.Context.getPointerType( SrcConstruct.getQualifiedType(*i1)); DestConstruct = Self.Context.getPointerType( DestConstruct.getQualifiedType(*i2)); } // Test if they're compatible. return SrcConstruct != DestConstruct && !Self.IsQualificationConversion(SrcConstruct, DestConstruct); }
/// CheckConstCast - Check that a const_cast\<DestType\>(SrcExpr) is valid. /// Refer to C++ 5.2.11 for details. const_cast is typically used in code /// like this: /// const char *str = "literal"; /// legacy_function(const_cast\<char*\>(str)); void CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, const SourceRange &DestRange) { QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); DestType = Self.Context.getCanonicalType(DestType); QualType SrcType = SrcExpr->getType(); if (const LValueReferenceType *DestTypeTmp = DestType->getAsLValueReferenceType()) { if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { // Cannot cast non-lvalue to lvalue reference type. Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) << "const_cast" << OrigDestType << SrcExpr->getSourceRange(); return; } // C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2 // [...] if a pointer to T1 can be [cast] to the type pointer to T2. DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); SrcType = Self.Context.getPointerType(SrcType); } else { // C++ 5.2.11p1: Otherwise, the result is an rvalue and the // lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard // conversions are performed on the expression. Self.DefaultFunctionArrayConversion(SrcExpr); SrcType = SrcExpr->getType(); } // C++ 5.2.11p5: For a const_cast involving pointers to data members [...] // the rules for const_cast are the same as those used for pointers. if (!DestType->isPointerType() && !DestType->isMemberPointerType()) { // Cannot cast to non-pointer, non-reference type. Note that, if DestType // was a reference type, we converted it to a pointer above. // The status of rvalue references isn't entirely clear, but it looks like // conversion to them is simply invalid. // C++ 5.2.11p3: For two pointer types [...] Self.Diag(OpRange.getBegin(), diag::err_bad_const_cast_dest) << OrigDestType << DestRange; return; } if (DestType->isFunctionPointerType() || DestType->isMemberFunctionPointerType()) { // Cannot cast direct function pointers. // C++ 5.2.11p2: [...] where T is any object type or the void type [...] // T is the ultimate pointee of source and target type. Self.Diag(OpRange.getBegin(), diag::err_bad_const_cast_dest) << OrigDestType << DestRange; return; } SrcType = Self.Context.getCanonicalType(SrcType); // Unwrap the pointers. Ignore qualifiers. Terminate early if the types are // completely equal. // FIXME: const_cast should probably not be able to convert between pointers // to different address spaces. // 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.UnwrapSimilarPointerTypes(SrcType, DestType)) { SrcType = SrcType.getUnqualifiedType(); DestType = DestType.getUnqualifiedType(); } // Doug Gregor said to disallow this until users complain. #if 0 // If we end up with constant arrays of equal size, unwrap those too. A cast // from const int [N] to int (&)[N] is invalid by my reading of the // standard, but g++ accepts it even with -ansi -pedantic. // No more than one level, though, so don't embed this in the unwrap loop // above. const ConstantArrayType *SrcTypeArr, *DestTypeArr; if ((SrcTypeArr = Self.Context.getAsConstantArrayType(SrcType)) && (DestTypeArr = Self.Context.getAsConstantArrayType(DestType))) { if (SrcTypeArr->getSize() != DestTypeArr->getSize()) { // Different array sizes. Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic) << "const_cast" << OrigDestType << OrigSrcType << OpRange; return; } SrcType = SrcTypeArr->getElementType().getUnqualifiedType(); DestType = DestTypeArr->getElementType().getUnqualifiedType(); } #endif // Since we're dealing in canonical types, the remainder must be the same. if (SrcType != DestType) { // Cast between unrelated types. Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic) << "const_cast" << OrigDestType << OrigSrcType << OpRange; return; } }
/// TryConstCast - See if a const_cast from source to destination is allowed, /// and perform it if it is. static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, unsigned &msg) { DestType = Self.Context.getCanonicalType(DestType); QualType SrcType = SrcExpr->getType(); if (const LValueReferenceType *DestTypeTmp = DestType->getAs<LValueReferenceType>()) { if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { // Cannot const_cast non-lvalue to lvalue reference type. But if this // is C-style, static_cast might find a way, so we simply suggest a // message and tell the parent to keep searching. msg = diag::err_bad_cxx_cast_rvalue; return TC_NotApplicable; } // C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2 // [...] if a pointer to T1 can be [cast] to the type pointer to T2. DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); SrcType = Self.Context.getPointerType(SrcType); } // C++ 5.2.11p5: For a const_cast involving pointers to data members [...] // the rules for const_cast are the same as those used for pointers. if (!DestType->isPointerType() && !DestType->isMemberPointerType()) { // Cannot cast to non-pointer, non-reference type. Note that, if DestType // was a reference type, we converted it to a pointer above. // The status of rvalue references isn't entirely clear, but it looks like // conversion to them is simply invalid. // C++ 5.2.11p3: For two pointer types [...] if (!CStyle) msg = diag::err_bad_const_cast_dest; return TC_NotApplicable; } if (DestType->isFunctionPointerType() || DestType->isMemberFunctionPointerType()) { // Cannot cast direct function pointers. // C++ 5.2.11p2: [...] where T is any object type or the void type [...] // T is the ultimate pointee of source and target type. if (!CStyle) 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. // FIXME: const_cast should probably not be able to convert between pointers // to different address spaces. // 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.UnwrapSimilarPointerTypes(SrcType, DestType)) { SrcType = SrcType.getUnqualifiedType(); DestType = DestType.getUnqualifiedType(); } // Since we're dealing in canonical types, the remainder must be the same. if (SrcType != DestType) return TC_NotApplicable; return TC_Success; }