[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:
Jordan Rose 2013-02-21 03:12:32 +00:00
parent e6a8cedd2c
commit 599f85ab85
6 changed files with 84 additions and 60 deletions

View File

@ -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);

View File

@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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));
}
/// 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);
for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
E = Class->bases_end();
I != E; ++I) {
if (I->getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass)
return true;
}
return false;
}
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));
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));
} 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;
}
}
assert(FoundBase && "Not a direct base class of this region");
#endif
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));
}
}
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();

View File

@ -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);
}