forked from OSchip/llvm-project
[analyzer] Record whether a base object region represents a virtual base.
This allows MemRegion and MemRegionManager to avoid asking over and over again whether an class is a virtual base or a non-virtual base. Minor optimization/cleanup; no functionality change. llvm-svn: 175716
This commit is contained in:
parent
e6a8cedd2c
commit
599f85ab85
|
@ -1055,16 +1055,18 @@ public:
|
|||
class CXXBaseObjectRegion : public TypedValueRegion {
|
||||
friend class MemRegionManager;
|
||||
|
||||
const CXXRecordDecl *decl;
|
||||
llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Data;
|
||||
|
||||
CXXBaseObjectRegion(const CXXRecordDecl *d, const MemRegion *sReg)
|
||||
: TypedValueRegion(sReg, CXXBaseObjectRegionKind), decl(d) {}
|
||||
CXXBaseObjectRegion(const CXXRecordDecl *RD, bool IsVirtual,
|
||||
const MemRegion *SReg)
|
||||
: TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
|
||||
const CXXRecordDecl *decl, const MemRegion *sReg);
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD,
|
||||
bool IsVirtual, const MemRegion *SReg);
|
||||
|
||||
public:
|
||||
const CXXRecordDecl *getDecl() const { return decl; }
|
||||
const CXXRecordDecl *getDecl() const { return Data.getPointer(); }
|
||||
bool isVirtual() const { return Data.getInt(); }
|
||||
|
||||
QualType getValueType() const;
|
||||
|
||||
|
@ -1214,15 +1216,21 @@ public:
|
|||
const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex,
|
||||
LocationContext const *LC);
|
||||
|
||||
const CXXBaseObjectRegion *getCXXBaseObjectRegion(const CXXRecordDecl *decl,
|
||||
const MemRegion *superRegion);
|
||||
/// Create a CXXBaseObjectRegion with the given base class for region
|
||||
/// \p Super.
|
||||
///
|
||||
/// The type of \p Super is assumed be a class deriving from \p BaseClass.
|
||||
const CXXBaseObjectRegion *
|
||||
getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const MemRegion *Super,
|
||||
bool IsVirtual);
|
||||
|
||||
/// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different
|
||||
/// super region.
|
||||
const CXXBaseObjectRegion *
|
||||
getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg,
|
||||
const MemRegion *superRegion) {
|
||||
return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion);
|
||||
return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion,
|
||||
baseReg->isVirtual());
|
||||
}
|
||||
|
||||
const FunctionTextRegion *getFunctionTextRegion(const NamedDecl *FD);
|
||||
|
|
|
@ -136,7 +136,8 @@ public:
|
|||
SVal evalDerivedToBase(SVal Derived, const CXXBasePath &CastPath);
|
||||
|
||||
/// Evaluates a derived-to-base cast through a single level of derivation.
|
||||
SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType);
|
||||
SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType,
|
||||
bool IsVirtual);
|
||||
|
||||
/// \brief Evaluates C++ dynamic_cast cast.
|
||||
/// The callback may result in the following 3 scenarios:
|
||||
|
|
|
@ -487,8 +487,10 @@ void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
|
|||
SVal ThisVal = Pred->getState()->getSVal(ThisPtr);
|
||||
|
||||
// Create the base object region.
|
||||
QualType BaseTy = D.getBaseSpecifier()->getType();
|
||||
SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy);
|
||||
const CXXBaseSpecifier *Base = D.getBaseSpecifier();
|
||||
QualType BaseTy = Base->getType();
|
||||
SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy,
|
||||
Base->isVirtual());
|
||||
|
||||
VisitCXXDestructor(BaseTy, BaseVal.castAs<loc::MemRegionVal>().getRegion(),
|
||||
CurDtor->getBody(), /*IsBase=*/ true, Pred, Dst);
|
||||
|
|
|
@ -161,8 +161,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
|
|||
Target = ThisVal.getAsRegion();
|
||||
} else {
|
||||
// Cast to the base type.
|
||||
QualType BaseTy = CE->getType();
|
||||
SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy);
|
||||
bool IsVirtual =
|
||||
(CE->getConstructionKind() == CXXConstructExpr::CK_VirtualBase);
|
||||
SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, CE->getType(),
|
||||
IsVirtual);
|
||||
Target = BaseVal.getAsRegion();
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -234,7 +234,7 @@ QualType ObjCIvarRegion::getValueType() const {
|
|||
}
|
||||
|
||||
QualType CXXBaseObjectRegion::getValueType() const {
|
||||
return QualType(decl->getTypeForDecl(), 0);
|
||||
return QualType(getDecl()->getTypeForDecl(), 0);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -402,14 +402,16 @@ void CXXTempObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
|
|||
}
|
||||
|
||||
void CXXBaseObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
|
||||
const CXXRecordDecl *decl,
|
||||
const MemRegion *sReg) {
|
||||
ID.AddPointer(decl);
|
||||
ID.AddPointer(sReg);
|
||||
const CXXRecordDecl *RD,
|
||||
bool IsVirtual,
|
||||
const MemRegion *SReg) {
|
||||
ID.AddPointer(RD);
|
||||
ID.AddBoolean(IsVirtual);
|
||||
ID.AddPointer(SReg);
|
||||
}
|
||||
|
||||
void CXXBaseObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ProfileRegion(ID, decl, superRegion);
|
||||
ProfileRegion(ID, getDecl(), isVirtual(), superRegion);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -472,7 +474,7 @@ void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {
|
|||
}
|
||||
|
||||
void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const {
|
||||
os << "base{" << superRegion << ',' << decl->getName() << '}';
|
||||
os << "base{" << superRegion << ',' << getDecl()->getName() << '}';
|
||||
}
|
||||
|
||||
void CXXThisRegion::dumpToStream(raw_ostream &os) const {
|
||||
|
@ -885,41 +887,49 @@ MemRegionManager::getCXXTempObjectRegion(Expr const *E,
|
|||
return getSubRegion<CXXTempObjectRegion>(E, getStackLocalsRegion(SFC));
|
||||
}
|
||||
|
||||
const CXXBaseObjectRegion *
|
||||
MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *decl,
|
||||
const MemRegion *superRegion) {
|
||||
// Check that the base class is actually a direct base of this region.
|
||||
if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(superRegion)) {
|
||||
if (const CXXRecordDecl *Class = TVR->getValueType()->getAsCXXRecordDecl()){
|
||||
if (Class->isVirtuallyDerivedFrom(decl)) {
|
||||
// Virtual base regions should not be layered, since the layout rules
|
||||
// are different.
|
||||
while (const CXXBaseObjectRegion *Base =
|
||||
dyn_cast<CXXBaseObjectRegion>(superRegion)) {
|
||||
superRegion = Base->getSuperRegion();
|
||||
}
|
||||
assert(superRegion && !isa<MemSpaceRegion>(superRegion));
|
||||
/// Checks whether \p BaseClass is a valid virtual or direct non-virtual base
|
||||
/// class of the type of \p Super.
|
||||
static bool isValidBaseClass(const CXXRecordDecl *BaseClass,
|
||||
const TypedValueRegion *Super,
|
||||
bool IsVirtual) {
|
||||
const CXXRecordDecl *Class = Super->getValueType()->getAsCXXRecordDecl();
|
||||
if (!Class)
|
||||
return true;
|
||||
|
||||
if (IsVirtual)
|
||||
return Class->isVirtuallyDerivedFrom(BaseClass);
|
||||
|
||||
} else {
|
||||
// Non-virtual bases should always be direct bases.
|
||||
#ifndef NDEBUG
|
||||
bool FoundBase = false;
|
||||
for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
|
||||
E = Class->bases_end();
|
||||
I != E; ++I) {
|
||||
if (I->getType()->getAsCXXRecordDecl() == decl) {
|
||||
FoundBase = true;
|
||||
break;
|
||||
if (I->getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const CXXBaseObjectRegion *
|
||||
MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *RD,
|
||||
const MemRegion *Super,
|
||||
bool IsVirtual) {
|
||||
RD = RD->getCanonicalDecl();
|
||||
|
||||
if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(Super)) {
|
||||
assert(isValidBaseClass(RD, TVR, IsVirtual));
|
||||
|
||||
if (IsVirtual) {
|
||||
// Virtual base regions should not be layered, since the layout rules
|
||||
// are different.
|
||||
while (const CXXBaseObjectRegion *Base =
|
||||
dyn_cast<CXXBaseObjectRegion>(Super)) {
|
||||
Super = Base->getSuperRegion();
|
||||
}
|
||||
assert(Super && !isa<MemSpaceRegion>(Super));
|
||||
}
|
||||
}
|
||||
|
||||
assert(FoundBase && "Not a direct base class of this region");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return getSubRegion<CXXBaseObjectRegion>(decl, superRegion);
|
||||
return getSubRegion<CXXBaseObjectRegion>(RD, IsVirtual, Super);
|
||||
}
|
||||
|
||||
const CXXThisRegion*
|
||||
|
@ -1146,14 +1156,12 @@ RegionOffset MemRegion::getAsOffset() const {
|
|||
if (SymbolicOffsetBase)
|
||||
continue;
|
||||
|
||||
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Child);
|
||||
|
||||
CharUnits BaseOffset;
|
||||
const CXXRecordDecl *Base = BOR->getDecl();
|
||||
if (Child->isVirtuallyDerivedFrom(Base))
|
||||
BaseOffset = Layout.getVBaseClassOffset(Base);
|
||||
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Child);
|
||||
if (BOR->isVirtual())
|
||||
BaseOffset = Layout.getVBaseClassOffset(BOR->getDecl());
|
||||
else
|
||||
BaseOffset = Layout.getBaseClassOffset(Base);
|
||||
BaseOffset = Layout.getBaseClassOffset(BOR->getDecl());
|
||||
|
||||
// The base offset is in chars, not in bits.
|
||||
Offset += BaseOffset.getQuantity() * getContext().getCharWidth();
|
||||
|
|
|
@ -254,7 +254,7 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, const CastExpr *Cast) {
|
|||
for (CastExpr::path_const_iterator I = Cast->path_begin(),
|
||||
E = Cast->path_end();
|
||||
I != E; ++I) {
|
||||
Result = evalDerivedToBase(Result, (*I)->getType());
|
||||
Result = evalDerivedToBase(Result, (*I)->getType(), (*I)->isVirtual());
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
@ -264,12 +264,14 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, const CXXBasePath &Path) {
|
|||
SVal Result = Derived;
|
||||
for (CXXBasePath::const_iterator I = Path.begin(), E = Path.end();
|
||||
I != E; ++I) {
|
||||
Result = evalDerivedToBase(Result, I->Base->getType());
|
||||
Result = evalDerivedToBase(Result, I->Base->getType(),
|
||||
I->Base->isVirtual());
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType) {
|
||||
SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType,
|
||||
bool IsVirtual) {
|
||||
Optional<loc::MemRegionVal> DerivedRegVal =
|
||||
Derived.getAs<loc::MemRegionVal>();
|
||||
if (!DerivedRegVal)
|
||||
|
@ -281,7 +283,8 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType) {
|
|||
assert(BaseDecl && "not a C++ object?");
|
||||
|
||||
const MemRegion *BaseReg =
|
||||
MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion());
|
||||
MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion(),
|
||||
IsVirtual);
|
||||
|
||||
return loc::MemRegionVal(BaseReg);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue