MemRegionManager &MRMgr = StateMgr.getRegionManager();
StoreManager &StoreMgr = StateMgr.getStoreManager();
- // We need to be careful about treating a derived type's value as
- // bindings for a base type. Unless we're creating a temporary pointer region,
- // start by stripping and recording base casts.
- SmallVector<const CastExpr *, 4> Casts;
- const Expr *Inner = Ex->IgnoreParens();
- if (!Loc::isLocType(Result->getType())) {
- while (const CastExpr *CE = dyn_cast<CastExpr>(Inner)) {
- if (CE->getCastKind() == CK_DerivedToBase ||
- CE->getCastKind() == CK_UncheckedDerivedToBase)
- Casts.push_back(CE);
- else if (CE->getCastKind() != CK_NoOp)
- break;
+ // MaterializeTemporaryExpr may appear out of place, after a few field and
+ // base-class accesses have been made to the object, even though semantically
+ // it is the whole object that gets materialized and lifetime-extended.
+ //
+ // For example:
+ //
+ // `-MaterializeTemporaryExpr
+ // `-MemberExpr
+ // `-CXXTemporaryObjectExpr
+ //
+ // instead of the more natural
+ //
+ // `-MemberExpr
+ // `-MaterializeTemporaryExpr
+ // `-CXXTemporaryObjectExpr
+ //
+ // Use the usual methods for obtaining the expression of the base object,
+ // and record the adjustments that we need to make to obtain the sub-object
+ // that the whole expression 'Ex' refers to. This trick is usual,
+ // in the sense that CodeGen takes a similar route.
- Inner = CE->getSubExpr()->IgnoreParens();
- }
- }
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+
+ const Expr *Init = Ex->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
- // Create a temporary object region for the inner expression (which may have
- // a more derived type) and bind the value into it.
const TypedValueRegion *TR = nullptr;
if (const MaterializeTemporaryExpr *MT =
dyn_cast<MaterializeTemporaryExpr>(Result)) {
// If this object is bound to a reference with static storage duration, we
// put it in a different region to prevent "address leakage" warnings.
if (SD == SD_Static || SD == SD_Thread)
- TR = MRMgr.getCXXStaticTempObjectRegion(Inner);
+ TR = MRMgr.getCXXStaticTempObjectRegion(Init);
}
if (!TR)
- TR = MRMgr.getCXXTempObjectRegion(Inner, LC);
+ TR = MRMgr.getCXXTempObjectRegion(Init, LC);
SVal Reg = loc::MemRegionVal(TR);
+ // Make the necessary adjustments to obtain the sub-object.
+ for (auto I = Adjustments.rbegin(), E = Adjustments.rend(); I != E; ++I) {
+ const SubobjectAdjustment &Adj = *I;
+ switch (Adj.Kind) {
+ case SubobjectAdjustment::DerivedToBaseAdjustment:
+ Reg = StoreMgr.evalDerivedToBase(Reg, Adj.DerivedToBase.BasePath);
+ break;
+ case SubobjectAdjustment::FieldAdjustment:
+ Reg = StoreMgr.getLValueField(Adj.Field, Reg);
+ break;
+ case SubobjectAdjustment::MemberPointerAdjustment:
+ // FIXME: Unimplemented.
+ State->bindDefault(Reg, UnknownVal());
+ return State;
+ }
+ }
+
+ // Try to recover some path sensitivity in case we couldn't compute the value.
if (V.isUnknown())
V = getSValBuilder().conjureSymbolVal(Result, LC, TR->getValueType(),
currBldrCtx->blockCount());
+ // Bind the value of the expression to the sub-object region, and then bind
+ // the sub-object region to our expression.
State = State->bindLoc(Reg, V);
-
- // Re-apply the casts (from innermost to outermost) for type sanity.
- for (SmallVectorImpl<const CastExpr *>::reverse_iterator I = Casts.rbegin(),
- E = Casts.rend();
- I != E; ++I) {
- Reg = StoreMgr.evalDerivedToBase(Reg, *I);
- }
-
State = State->BindExpr(Result, LC, Reg);
return State;
}
SVal dest = state->getLValue(varDecl, Pred->getLocationContext());
const MemRegion *Region = dest.castAs<loc::MemRegionVal>().getRegion();
- if (const ReferenceType *refType = varType->getAs<ReferenceType>()) {
- varType = refType->getPointeeType();
- Region = state->getSVal(Region).getAsRegion();
+ if (varType->isReferenceType()) {
+ Region = state->getSVal(Region).getAsRegion()->getBaseRegion();
+ varType = cast<TypedValueRegion>(Region)->getValueType();
}
VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(), /*IsBase=*/ false,