static bool isCallbackArg(SVal V, QualType T) { // If the parameter is 0, it's harmless. if (V.isZeroConstant()) return false; // If a parameter is a block or a callback, assume it can modify pointer. if (T->isBlockPointerType() || T->isFunctionPointerType() || T->isObjCSelType()) return true; // Check if a callback is passed inside a struct (for both, struct passed by // reference and by value). Dig just one level into the struct for now. if (isa<PointerType>(T) || isa<ReferenceType>(T)) T = T->getPointeeType(); if (const RecordType *RT = T->getAsStructureType()) { const RecordDecl *RD = RT->getDecl(); for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I) { QualType FieldT = I->getType(); if (FieldT->isBlockPointerType() || FieldT->isFunctionPointerType()) return true; } } return false; }
static bool isCallback(QualType T) { // If a parameter is a block or a callback, assume it can modify pointer. if (T->isBlockPointerType() || T->isFunctionPointerType() || T->isObjCSelType()) return true; // Check if a callback is passed inside a struct (for both, struct passed by // reference and by value). Dig just one level into the struct for now. if (T->isAnyPointerType() || T->isReferenceType()) T = T->getPointeeType(); if (const RecordType *RT = T->getAsStructureType()) { const RecordDecl *RD = RT->getDecl(); for (const auto *I : RD->fields()) { QualType FieldT = I->getType(); if (FieldT->isBlockPointerType() || FieldT->isFunctionPointerType()) return true; } } return false; }
SVal ValueManager::getConjuredSymbolVal(const Expr* E, unsigned Count) { QualType T = E->getType(); SymbolRef sym = SymMgr.getConjuredSymbol(E, Count); // If T is of function pointer type, create a CodeTextRegion wrapping a // symbol. if (T->isFunctionPointerType()) { return Loc::MakeVal(MemMgr.getCodeTextRegion(sym, T)); } if (Loc::IsLocType(T)) return Loc::MakeVal(MemMgr.getSymbolicRegion(sym)); if (T->isIntegerType() && T->isScalarType()) return makeNonLoc(sym); return UnknownVal(); }
SVal ValueManager::getConjuredSymbolVal(const Expr* E, unsigned Count) { QualType T = E->getType(); if (!SymbolManager::canSymbolicate(T)) return UnknownVal(); SymbolRef sym = SymMgr.getConjuredSymbol(E, Count); // If T is of function pointer type or a block pointer type, create a // CodeTextRegion wrapping a symbol. if (T->isFunctionPointerType() || T->isBlockPointerType()) return loc::MemRegionVal(MemMgr.getCodeTextRegion(sym, T)); if (Loc::IsLocType(T)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); return nonloc::SymbolVal(sym); }
SVal ValueManager::getRegionValueSymbolVal(const MemRegion* R, QualType T) { if (T.isNull()) { const TypedRegion* TR = cast<TypedRegion>(R); T = TR->getValueType(SymMgr.getContext()); } if (!SymbolManager::canSymbolicate(T)) return UnknownVal(); SymbolRef sym = SymMgr.getRegionValueSymbol(R, T); // If T is of function pointer type or a block pointer type, create a // CodeTextRegion wrapping that symbol. if (T->isFunctionPointerType() || T->isBlockPointerType()) return loc::MemRegionVal(MemMgr.getCodeTextRegion(sym, T)); if (Loc::IsLocType(T)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); return nonloc::SymbolVal(sym); }
SVal ValueManager::getRegionValueSymbolVal(const MemRegion* R) { SymbolRef sym = SymMgr.getRegionValueSymbol(R); if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) { QualType T = TR->getValueType(SymMgr.getContext()); // If T is of function pointer type, create a CodeTextRegion wrapping a // symbol. if (T->isFunctionPointerType()) { return Loc::MakeVal(MemMgr.getCodeTextRegion(sym, T)); } if (Loc::IsLocType(T)) return Loc::MakeVal(MemMgr.getSymbolicRegion(sym)); // Only handle integers for now. if (T->isIntegerType() && T->isScalarType()) return makeNonLoc(sym); } return UnknownVal(); }
// FIXME: should rewrite according to the cast kind. SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { castTy = Context.getCanonicalType(castTy); originalTy = Context.getCanonicalType(originalTy); if (val.isUnknownOrUndef() || castTy == originalTy) return val; if (castTy->isBooleanType()) { if (val.isUnknownOrUndef()) return val; if (val.isConstant()) return makeTruthVal(!val.isZeroConstant(), castTy); if (!Loc::isLocType(originalTy) && !originalTy->isIntegralOrEnumerationType() && !originalTy->isMemberPointerType()) return UnknownVal(); if (SymbolRef Sym = val.getAsSymbol(true)) { BasicValueFactory &BVF = getBasicValueFactory(); // FIXME: If we had a state here, we could see if the symbol is known to // be zero, but we don't. return makeNonLoc(Sym, BO_NE, BVF.getValue(0, Sym->getType()), castTy); } // Loc values are not always true, they could be weakly linked functions. if (Optional<Loc> L = val.getAs<Loc>()) return evalCastFromLoc(*L, castTy); Loc L = val.castAs<nonloc::LocAsInteger>().getLoc(); return evalCastFromLoc(L, castTy); } // For const casts, casts to void, just propagate the value. if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType()) if (shouldBeModeledWithNoOp(Context, Context.getPointerType(castTy), Context.getPointerType(originalTy))) return val; // Check for casts from pointers to integers. if (castTy->isIntegralOrEnumerationType() && Loc::isLocType(originalTy)) return evalCastFromLoc(val.castAs<Loc>(), castTy); // Check for casts from integers to pointers. if (Loc::isLocType(castTy) && originalTy->isIntegralOrEnumerationType()) { if (Optional<nonloc::LocAsInteger> LV = val.getAs<nonloc::LocAsInteger>()) { if (const MemRegion *R = LV->getLoc().getAsRegion()) { StoreManager &storeMgr = StateMgr.getStoreManager(); R = storeMgr.castRegion(R, castTy); return R ? SVal(loc::MemRegionVal(R)) : UnknownVal(); } return LV->getLoc(); } return dispatchCast(val, castTy); } // Just pass through function and block pointers. if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) { assert(Loc::isLocType(castTy)); return val; } // Check for casts from array type to another type. if (const ArrayType *arrayT = dyn_cast<ArrayType>(originalTy.getCanonicalType())) { // We will always decay to a pointer. QualType elemTy = arrayT->getElementType(); val = StateMgr.ArrayToPointer(val.castAs<Loc>(), elemTy); // Are we casting from an array to a pointer? If so just pass on // the decayed value. if (castTy->isPointerType() || castTy->isReferenceType()) return val; // Are we casting from an array to an integer? If so, cast the decayed // pointer value to an integer. assert(castTy->isIntegralOrEnumerationType()); // FIXME: Keep these here for now in case we decide soon that we // need the original decayed type. // QualType elemTy = cast<ArrayType>(originalTy)->getElementType(); // QualType pointerTy = C.getPointerType(elemTy); return evalCastFromLoc(val.castAs<Loc>(), castTy); } // Check for casts from a region to a specific type. if (const MemRegion *R = val.getAsRegion()) { // Handle other casts of locations to integers. if (castTy->isIntegralOrEnumerationType()) return evalCastFromLoc(loc::MemRegionVal(R), castTy); // FIXME: We should handle the case where we strip off view layers to get // to a desugared type. if (!Loc::isLocType(castTy)) { // FIXME: There can be gross cases where one casts the result of a function // (that returns a pointer) to some other value that happens to fit // within that pointer value. We currently have no good way to // model such operations. When this happens, the underlying operation // is that the caller is reasoning about bits. Conceptually we are // layering a "view" of a location on top of those bits. Perhaps // we need to be more lazy about mutual possible views, even on an // SVal? This may be necessary for bit-level reasoning as well. return UnknownVal(); } // We get a symbolic function pointer for a dereference of a function // pointer, but it is of function type. Example: // struct FPRec { // void (*my_func)(int * x); // }; // // int bar(int x); // // int f1_a(struct FPRec* foo) { // int x; // (*foo->my_func)(&x); // return bar(x)+1; // no-warning // } assert(Loc::isLocType(originalTy) || originalTy->isFunctionType() || originalTy->isBlockPointerType() || castTy->isReferenceType()); StoreManager &storeMgr = StateMgr.getStoreManager(); // Delegate to store manager to get the result of casting a region to a // different type. If the MemRegion* returned is NULL, this expression // Evaluates to UnknownVal. R = storeMgr.castRegion(R, castTy); return R ? SVal(loc::MemRegionVal(R)) : UnknownVal(); } return dispatchCast(val, castTy); }
// FIXME: should rewrite according to the cast kind. SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { castTy = Context.getCanonicalType(castTy); originalTy = Context.getCanonicalType(originalTy); if (val.isUnknownOrUndef() || castTy == originalTy) return val; // For const casts, just propagate the value. if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType()) if (haveSimilarTypes(Context, Context.getPointerType(castTy), Context.getPointerType(originalTy))) return val; // Check for casts from pointers to integers. if (castTy->isIntegerType() && Loc::isLocType(originalTy)) return evalCastFromLoc(cast<Loc>(val), castTy); // Check for casts from integers to pointers. if (Loc::isLocType(castTy) && originalTy->isIntegerType()) { if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&val)) { if (const MemRegion *R = LV->getLoc().getAsRegion()) { StoreManager &storeMgr = StateMgr.getStoreManager(); R = storeMgr.castRegion(R, castTy); return R ? SVal(loc::MemRegionVal(R)) : UnknownVal(); } return LV->getLoc(); } return dispatchCast(val, castTy); } // Just pass through function and block pointers. if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) { assert(Loc::isLocType(castTy)); return val; } // Check for casts from array type to another type. if (originalTy->isArrayType()) { // We will always decay to a pointer. val = StateMgr.ArrayToPointer(cast<Loc>(val)); // Are we casting from an array to a pointer? If so just pass on // the decayed value. if (castTy->isPointerType()) return val; // Are we casting from an array to an integer? If so, cast the decayed // pointer value to an integer. assert(castTy->isIntegerType()); // FIXME: Keep these here for now in case we decide soon that we // need the original decayed type. // QualType elemTy = cast<ArrayType>(originalTy)->getElementType(); // QualType pointerTy = C.getPointerType(elemTy); return evalCastFromLoc(cast<Loc>(val), castTy); } // Check for casts from a region to a specific type. if (const MemRegion *R = val.getAsRegion()) { // Handle other casts of locations to integers. if (castTy->isIntegerType()) return evalCastFromLoc(loc::MemRegionVal(R), castTy); // FIXME: We should handle the case where we strip off view layers to get // to a desugared type. if (!Loc::isLocType(castTy)) { // FIXME: There can be gross cases where one casts the result of a function // (that returns a pointer) to some other value that happens to fit // within that pointer value. We currently have no good way to // model such operations. When this happens, the underlying operation // is that the caller is reasoning about bits. Conceptually we are // layering a "view" of a location on top of those bits. Perhaps // we need to be more lazy about mutual possible views, even on an // SVal? This may be necessary for bit-level reasoning as well. return UnknownVal(); } // We get a symbolic function pointer for a dereference of a function // pointer, but it is of function type. Example: // struct FPRec { // void (*my_func)(int * x); // }; // // int bar(int x); // // int f1_a(struct FPRec* foo) { // int x; // (*foo->my_func)(&x); // return bar(x)+1; // no-warning // } assert(Loc::isLocType(originalTy) || originalTy->isFunctionType() || originalTy->isBlockPointerType() || castTy->isReferenceType()); StoreManager &storeMgr = StateMgr.getStoreManager(); // Delegate to store manager to get the result of casting a region to a // different type. If the MemRegion* returned is NULL, this expression // Evaluates to UnknownVal. R = storeMgr.castRegion(R, castTy); return R ? SVal(loc::MemRegionVal(R)) : UnknownVal(); } return dispatchCast(val, castTy); }
// We need to artificially create: // cling::valuePrinterInternal::Select((void*) raw_ostream, // (ASTContext)Ctx, (Expr*)E, &i); Expr* ValuePrinterSynthesizer::SynthesizeCppVP(Expr* E) { QualType QT = E->getType(); // For now we skip void and function pointer types. if (QT.isNull() || QT->isVoidType()) return 0; // 1. Call gCling->getValuePrinterStream() // 1.1. Find gCling SourceLocation NoSLoc = SourceLocation(); NamespaceDecl* NSD = utils::Lookup::Namespace(m_Sema, "cling"); NSD = utils::Lookup::Namespace(m_Sema, "valuePrinterInternal", NSD); DeclarationName PVName = &m_Context->Idents.get("Select"); LookupResult R(*m_Sema, PVName, NoSLoc, Sema::LookupOrdinaryName, Sema::ForRedeclaration); assert(NSD && "There must be a valid namespace."); m_Sema->LookupQualifiedName(R, NSD); assert(!R.empty() && "Cannot find valuePrinterInternal::Select(...)"); CXXScopeSpec CSS; Expr* UnresolvedLookup = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).take(); // 2.4. Prepare the params // 2.4.1 Lookup the llvm::raw_ostream CXXRecordDecl* RawOStreamRD = dyn_cast<CXXRecordDecl>(utils::Lookup::Named(m_Sema, "raw_ostream", utils::Lookup::Namespace(m_Sema, "llvm"))); assert(RawOStreamRD && "Declaration of the expr not found!"); QualType RawOStreamRDTy = m_Context->getTypeDeclType(RawOStreamRD); // 2.4.2 Lookup the expr type CXXRecordDecl* ExprRD = dyn_cast<CXXRecordDecl>(utils::Lookup::Named(m_Sema, "Expr", utils::Lookup::Namespace(m_Sema, "clang"))); assert(ExprRD && "Declaration of the expr not found!"); QualType ExprRDTy = m_Context->getTypeDeclType(ExprRD); // 2.4.3 Lookup ASTContext type CXXRecordDecl* ASTContextRD = dyn_cast<CXXRecordDecl>(utils::Lookup::Named(m_Sema, "ASTContext", utils::Lookup::Namespace(m_Sema, "clang"))); assert(ASTContextRD && "Declaration of the expr not found!"); QualType ASTContextRDTy = m_Context->getTypeDeclType(ASTContextRD); Expr* RawOStreamTy = utils::Synthesize::CStyleCastPtrExpr(m_Sema, RawOStreamRDTy, (uint64_t)m_ValuePrinterStream.get() ); Expr* ExprTy = utils::Synthesize::CStyleCastPtrExpr(m_Sema, ExprRDTy, (uint64_t)E); Expr* ASTContextTy = utils::Synthesize::CStyleCastPtrExpr(m_Sema, ASTContextRDTy, (uint64_t)m_Context); // E might contain temporaries. This means that the topmost expr is // ExprWithCleanups. This contains the information about the temporaries and // signals when they should be destroyed. // Here we replace E with call to value printer and we must extend the life // time of those temporaries to the end of the new CallExpr. bool NeedsCleanup = false; if (ExprWithCleanups* EWC = dyn_cast<ExprWithCleanups>(E)) { E = EWC->getSubExpr(); NeedsCleanup = true; } if (QT->isFunctionPointerType()) { // convert func ptr to void*: E = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy, E); } llvm::SmallVector<Expr*, 4> CallArgs; CallArgs.push_back(RawOStreamTy); CallArgs.push_back(ExprTy); CallArgs.push_back(ASTContextTy); CallArgs.push_back(E); Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext); // Here we expect a template instantiation. We need to open the transaction // that we are currently work with. Transaction::State oldState = getTransaction()->getState(); getTransaction()->setState(Transaction::kCollecting); Expr* Result = m_Sema->ActOnCallExpr(S, UnresolvedLookup, NoSLoc, CallArgs, NoSLoc).take(); getTransaction()->setState(oldState); Result = m_Sema->ActOnFinishFullExpr(Result).take(); if (NeedsCleanup && !isa<ExprWithCleanups>(Result)) { llvm::ArrayRef<ExprWithCleanups::CleanupObject> Cleanups; ExprWithCleanups* EWC = ExprWithCleanups::Create(*m_Context, Result, Cleanups); Result = EWC; } assert(Result && "Cannot create value printer!"); return Result; }
/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is /// valid. /// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code /// like this: /// char *bytes = reinterpret_cast\<char*\>(int_ptr); void CheckReinterpretCast(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 reference type. Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) << "reinterpret_cast" << OrigDestType << SrcExpr->getSourceRange(); return; } // C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the // same effect as the conversion *reinterpret_cast<T*>(&x) with the // built-in & and * operators. // This code does this transformation for the checked types. DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); SrcType = Self.Context.getPointerType(SrcType); } else if (const RValueReferenceType *DestTypeTmp = DestType->getAsRValueReferenceType()) { // Both the reference conversion and the rvalue rules apply. Self.DefaultFunctionArrayConversion(SrcExpr); SrcType = SrcExpr->getType(); DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); SrcType = Self.Context.getPointerType(SrcType); } else { // C++ 5.2.10p1: [...] the lvalue-to-rvalue, array-to-pointer, and // function-to-pointer standard conversions are performed on the // expression v. Self.DefaultFunctionArrayConversion(SrcExpr); SrcType = SrcExpr->getType(); } // Canonicalize source for comparison. SrcType = Self.Context.getCanonicalType(SrcType); const MemberPointerType *DestMemPtr = DestType->getAsMemberPointerType(), *SrcMemPtr = SrcType->getAsMemberPointerType(); if (DestMemPtr && SrcMemPtr) { // C++ 5.2.10p9: An rvalue of type "pointer to member of X of type T1" // can be explicitly converted to an rvalue of type "pointer to member // of Y of type T2" if T1 and T2 are both function types or both object // types. if (DestMemPtr->getPointeeType()->isFunctionType() != SrcMemPtr->getPointeeType()->isFunctionType()) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic) << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange; return; } // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away // constness. if (CastsAwayConstness(Self, SrcType, DestType)) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away) << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange; return; } // A valid member pointer cast. return; } // See below for the enumeral issue. if (SrcType->isNullPtrType() && DestType->isIntegralType() && !DestType->isEnumeralType()) { // C++0x 5.2.10p4: A pointer can be explicitly converted to any integral // type large enough to hold it. A value of std::nullptr_t can be // converted to an integral type; the conversion has the same meaning // and validity as a conversion of (void*)0 to the integral type. if (Self.Context.getTypeSize(SrcType) > Self.Context.getTypeSize(DestType)) { Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_small_int) << OrigDestType << DestRange; } return; } bool destIsPtr = DestType->isPointerType(); bool srcIsPtr = SrcType->isPointerType(); if (!destIsPtr && !srcIsPtr) { // Except for std::nullptr_t->integer and lvalue->reference, which are // handled above, at least one of the two arguments must be a pointer. Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic) << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange; return; } if (SrcType == DestType) { // C++ 5.2.10p2 has a note that mentions that, subject to all other // restrictions, a cast to the same type is allowed. The intent is not // entirely clear here, since all other paragraphs explicitly forbid casts // to the same type. However, the behavior of compilers is pretty consistent // on this point: allow same-type conversion if the involved types are // pointers, disallow otherwise. return; } // Note: Clang treats enumeration types as integral types. If this is ever // changed for C++, the additional check here will be redundant. if (DestType->isIntegralType() && !DestType->isEnumeralType()) { assert(srcIsPtr && "One type must be a pointer"); // C++ 5.2.10p4: A pointer can be explicitly converted to any integral // type large enough to hold it. if (Self.Context.getTypeSize(SrcType) > Self.Context.getTypeSize(DestType)) { Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_small_int) << OrigDestType << DestRange; } return; } if (SrcType->isIntegralType() || SrcType->isEnumeralType()) { assert(destIsPtr && "One type must be a pointer"); // C++ 5.2.10p5: A value of integral or enumeration type can be explicitly // converted to a pointer. return; } if (!destIsPtr || !srcIsPtr) { // With the valid non-pointer conversions out of the way, we can be even // more stringent. Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic) << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange; return; } // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness. if (CastsAwayConstness(Self, SrcType, DestType)) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away) << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange; return; } // Not casting away constness, so the only remaining check is for compatible // pointer categories. if (SrcType->isFunctionPointerType()) { 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; } // C++0x 5.2.10p8: Converting a pointer to a function into a pointer to // an object type or vice versa is conditionally-supported. // Compilers support it in C++03 too, though, because it's necessary for // casting the return value of dlsym() and GetProcAddress(). // FIXME: Conditionally-supported behavior should be configurable in the // TargetInfo or similar. if (!Self.getLangOptions().CPlusPlus0x) { Self.Diag(OpRange.getBegin(), diag::ext_reinterpret_cast_fn_obj) << OpRange; } return; } if (DestType->isFunctionPointerType()) { // See above. if (!Self.getLangOptions().CPlusPlus0x) { Self.Diag(OpRange.getBegin(), diag::ext_reinterpret_cast_fn_obj) << OpRange; } return; } // C++ 5.2.10p7: A pointer to an object can be explicitly converted to // a pointer to an object of different type. // 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. }
/// 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; }