xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- ExprEngineCXX.cpp - ExprEngine support for C++ -----------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file defines the C++ expression evaluation engine.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h"
140b57cec5SDimitry Andric #include "clang/AST/ParentMap.h"
15bdd1243dSDimitry Andric #include "clang/AST/StmtCXX.h"
16bdd1243dSDimitry Andric #include "clang/Analysis/ConstructionContext.h"
170b57cec5SDimitry Andric #include "clang/Basic/PrettyStackTrace.h"
180b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
190b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
200b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
21bdd1243dSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
22bdd1243dSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
2306c3fb27SDimitry Andric #include "llvm/ADT/STLExtras.h"
2406c3fb27SDimitry Andric #include "llvm/ADT/Sequence.h"
25bdd1243dSDimitry Andric #include <optional>
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric using namespace clang;
280b57cec5SDimitry Andric using namespace ento;
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
310b57cec5SDimitry Andric                                           ExplodedNode *Pred,
320b57cec5SDimitry Andric                                           ExplodedNodeSet &Dst) {
330b57cec5SDimitry Andric   StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
34480093f4SDimitry Andric   const Expr *tempExpr = ME->getSubExpr()->IgnoreParens();
350b57cec5SDimitry Andric   ProgramStateRef state = Pred->getState();
360b57cec5SDimitry Andric   const LocationContext *LCtx = Pred->getLocationContext();
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric   state = createTemporaryRegionIfNeeded(state, LCtx, tempExpr, ME);
390b57cec5SDimitry Andric   Bldr.generateNode(ME, Pred, state);
400b57cec5SDimitry Andric }
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric // FIXME: This is the sort of code that should eventually live in a Core
430b57cec5SDimitry Andric // checker rather than as a special case in ExprEngine.
440b57cec5SDimitry Andric void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
450b57cec5SDimitry Andric                                     const CallEvent &Call) {
460b57cec5SDimitry Andric   SVal ThisVal;
470b57cec5SDimitry Andric   bool AlwaysReturnsLValue;
480b57cec5SDimitry Andric   const CXXRecordDecl *ThisRD = nullptr;
490b57cec5SDimitry Andric   if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
500b57cec5SDimitry Andric     assert(Ctor->getDecl()->isTrivial());
510b57cec5SDimitry Andric     assert(Ctor->getDecl()->isCopyOrMoveConstructor());
520b57cec5SDimitry Andric     ThisVal = Ctor->getCXXThisVal();
530b57cec5SDimitry Andric     ThisRD = Ctor->getDecl()->getParent();
540b57cec5SDimitry Andric     AlwaysReturnsLValue = false;
550b57cec5SDimitry Andric   } else {
560b57cec5SDimitry Andric     assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial());
570b57cec5SDimitry Andric     assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() ==
580b57cec5SDimitry Andric            OO_Equal);
590b57cec5SDimitry Andric     ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal();
600b57cec5SDimitry Andric     ThisRD = cast<CXXMethodDecl>(Call.getDecl())->getParent();
610b57cec5SDimitry Andric     AlwaysReturnsLValue = true;
620b57cec5SDimitry Andric   }
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   const LocationContext *LCtx = Pred->getLocationContext();
6506c3fb27SDimitry Andric   const Expr *CallExpr = Call.getOriginExpr();
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   ExplodedNodeSet Dst;
680b57cec5SDimitry Andric   Bldr.takeNodes(Pred);
690b57cec5SDimitry Andric 
7006c3fb27SDimitry Andric   assert(ThisRD);
7106c3fb27SDimitry Andric   if (!ThisRD->isEmpty()) {
7206c3fb27SDimitry Andric     // Load the source value only for non-empty classes.
7306c3fb27SDimitry Andric     // Otherwise it'd retrieve an UnknownVal
7406c3fb27SDimitry Andric     // and bind it and RegionStore would think that the actual value
7506c3fb27SDimitry Andric     // in this region at this offset is unknown.
760b57cec5SDimitry Andric     SVal V = Call.getArgSVal(0);
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric     // If the value being copied is not unknown, load from its location to get
790b57cec5SDimitry Andric     // an aggregate rvalue.
80bdd1243dSDimitry Andric     if (std::optional<Loc> L = V.getAs<Loc>())
810b57cec5SDimitry Andric       V = Pred->getState()->getSVal(*L);
820b57cec5SDimitry Andric     else
830b57cec5SDimitry Andric       assert(V.isUnknownOrUndef());
840b57cec5SDimitry Andric     evalBind(Dst, CallExpr, Pred, ThisVal, V, true);
8506c3fb27SDimitry Andric   } else {
8606c3fb27SDimitry Andric     Dst.Add(Pred);
8706c3fb27SDimitry Andric   }
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   PostStmt PS(CallExpr, LCtx);
9006c3fb27SDimitry Andric   for (ExplodedNode *N : Dst) {
9106c3fb27SDimitry Andric     ProgramStateRef State = N->getState();
920b57cec5SDimitry Andric     if (AlwaysReturnsLValue)
930b57cec5SDimitry Andric       State = State->BindExpr(CallExpr, LCtx, ThisVal);
940b57cec5SDimitry Andric     else
950b57cec5SDimitry Andric       State = bindReturnValue(Call, LCtx, State);
9606c3fb27SDimitry Andric     Bldr.generateNode(PS, State, N);
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric 
100fcaf7f86SDimitry Andric SVal ExprEngine::makeElementRegion(ProgramStateRef State, SVal LValue,
101fcaf7f86SDimitry Andric                                    QualType &Ty, bool &IsArray, unsigned Idx) {
1020b57cec5SDimitry Andric   SValBuilder &SVB = State->getStateManager().getSValBuilder();
1030b57cec5SDimitry Andric   ASTContext &Ctx = SVB.getContext();
1040b57cec5SDimitry Andric 
105fcaf7f86SDimitry Andric   if (const ArrayType *AT = Ctx.getAsArrayType(Ty)) {
106fcaf7f86SDimitry Andric     while (AT) {
1070b57cec5SDimitry Andric       Ty = AT->getElementType();
108fcaf7f86SDimitry Andric       AT = dyn_cast<ArrayType>(AT->getElementType());
109fcaf7f86SDimitry Andric     }
110fcaf7f86SDimitry Andric     LValue = State->getLValue(Ty, SVB.makeArrayIndex(Idx), LValue);
1110b57cec5SDimitry Andric     IsArray = true;
1120b57cec5SDimitry Andric   }
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   return LValue;
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric 
117bdd1243dSDimitry Andric // In case when the prvalue is returned from the function (kind is one of
118bdd1243dSDimitry Andric // SimpleReturnedValueKind, CXX17ElidedCopyReturnedValueKind), then
119bdd1243dSDimitry Andric // it's materialization happens in context of the caller.
120bdd1243dSDimitry Andric // We pass BldrCtx explicitly, as currBldrCtx always refers to callee's context.
1215ffd83dbSDimitry Andric SVal ExprEngine::computeObjectUnderConstruction(
122bdd1243dSDimitry Andric     const Expr *E, ProgramStateRef State, const NodeBuilderContext *BldrCtx,
123bdd1243dSDimitry Andric     const LocationContext *LCtx, const ConstructionContext *CC,
124bdd1243dSDimitry Andric     EvalCallOptions &CallOpts, unsigned Idx) {
125bdd1243dSDimitry Andric 
1260b57cec5SDimitry Andric   SValBuilder &SVB = getSValBuilder();
1270b57cec5SDimitry Andric   MemRegionManager &MRMgr = SVB.getRegionManager();
1280b57cec5SDimitry Andric   ASTContext &ACtx = SVB.getContext();
1290b57cec5SDimitry Andric 
1305ffd83dbSDimitry Andric   // Compute the target region by exploring the construction context.
1310b57cec5SDimitry Andric   if (CC) {
1320b57cec5SDimitry Andric     switch (CC->getKind()) {
1330b57cec5SDimitry Andric     case ConstructionContext::CXX17ElidedCopyVariableKind:
1340b57cec5SDimitry Andric     case ConstructionContext::SimpleVariableKind: {
1350b57cec5SDimitry Andric       const auto *DSCC = cast<VariableConstructionContext>(CC);
1360b57cec5SDimitry Andric       const auto *DS = DSCC->getDeclStmt();
1370b57cec5SDimitry Andric       const auto *Var = cast<VarDecl>(DS->getSingleDecl());
1380b57cec5SDimitry Andric       QualType Ty = Var->getType();
139fcaf7f86SDimitry Andric       return makeElementRegion(State, State->getLValue(Var, LCtx), Ty,
140fcaf7f86SDimitry Andric                                CallOpts.IsArrayCtorOrDtor, Idx);
1410b57cec5SDimitry Andric     }
1420b57cec5SDimitry Andric     case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind:
1430b57cec5SDimitry Andric     case ConstructionContext::SimpleConstructorInitializerKind: {
1440b57cec5SDimitry Andric       const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
1450b57cec5SDimitry Andric       const auto *Init = ICC->getCXXCtorInitializer();
1460b57cec5SDimitry Andric       const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
1475ffd83dbSDimitry Andric       Loc ThisPtr = SVB.getCXXThis(CurCtor, LCtx->getStackFrame());
1480b57cec5SDimitry Andric       SVal ThisVal = State->getSVal(ThisPtr);
149e8d8bef9SDimitry Andric       if (Init->isBaseInitializer()) {
150e8d8bef9SDimitry Andric         const auto *ThisReg = cast<SubRegion>(ThisVal.getAsRegion());
151e8d8bef9SDimitry Andric         const CXXRecordDecl *BaseClass =
152e8d8bef9SDimitry Andric           Init->getBaseClass()->getAsCXXRecordDecl();
153e8d8bef9SDimitry Andric         const auto *BaseReg =
154e8d8bef9SDimitry Andric           MRMgr.getCXXBaseObjectRegion(BaseClass, ThisReg,
155e8d8bef9SDimitry Andric                                        Init->isBaseVirtual());
156e8d8bef9SDimitry Andric         return SVB.makeLoc(BaseReg);
157e8d8bef9SDimitry Andric       }
158e8d8bef9SDimitry Andric       if (Init->isDelegatingInitializer())
159e8d8bef9SDimitry Andric         return ThisVal;
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric       const ValueDecl *Field;
1620b57cec5SDimitry Andric       SVal FieldVal;
1630b57cec5SDimitry Andric       if (Init->isIndirectMemberInitializer()) {
1640b57cec5SDimitry Andric         Field = Init->getIndirectMember();
1650b57cec5SDimitry Andric         FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal);
1660b57cec5SDimitry Andric       } else {
1670b57cec5SDimitry Andric         Field = Init->getMember();
1680b57cec5SDimitry Andric         FieldVal = State->getLValue(Init->getMember(), ThisVal);
1690b57cec5SDimitry Andric       }
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric       QualType Ty = Field->getType();
172fcaf7f86SDimitry Andric       return makeElementRegion(State, FieldVal, Ty, CallOpts.IsArrayCtorOrDtor,
173fcaf7f86SDimitry Andric                                Idx);
1740b57cec5SDimitry Andric     }
1750b57cec5SDimitry Andric     case ConstructionContext::NewAllocatedObjectKind: {
1760b57cec5SDimitry Andric       if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
1770b57cec5SDimitry Andric         const auto *NECC = cast<NewAllocatedObjectConstructionContext>(CC);
1780b57cec5SDimitry Andric         const auto *NE = NECC->getCXXNewExpr();
1790b57cec5SDimitry Andric         SVal V = *getObjectUnderConstruction(State, NE, LCtx);
1800b57cec5SDimitry Andric         if (const SubRegion *MR =
1810b57cec5SDimitry Andric                 dyn_cast_or_null<SubRegion>(V.getAsRegion())) {
1820b57cec5SDimitry Andric           if (NE->isArray()) {
1830b57cec5SDimitry Andric             CallOpts.IsArrayCtorOrDtor = true;
184fcaf7f86SDimitry Andric 
185bdd1243dSDimitry Andric             auto Ty = NE->getType()->getPointeeType();
186bdd1243dSDimitry Andric             while (const auto *AT = getContext().getAsArrayType(Ty))
187bdd1243dSDimitry Andric               Ty = AT->getElementType();
188bdd1243dSDimitry Andric 
189bdd1243dSDimitry Andric             auto R = MRMgr.getElementRegion(Ty, svalBuilder.makeArrayIndex(Idx),
190bdd1243dSDimitry Andric                                             MR, SVB.getContext());
191fcaf7f86SDimitry Andric 
192fcaf7f86SDimitry Andric             return loc::MemRegionVal(R);
1930b57cec5SDimitry Andric           }
1945ffd83dbSDimitry Andric           return  V;
1950b57cec5SDimitry Andric         }
1960b57cec5SDimitry Andric         // TODO: Detect when the allocator returns a null pointer.
1970b57cec5SDimitry Andric         // Constructor shall not be called in this case.
1980b57cec5SDimitry Andric       }
1990b57cec5SDimitry Andric       break;
2000b57cec5SDimitry Andric     }
2010b57cec5SDimitry Andric     case ConstructionContext::SimpleReturnedValueKind:
2020b57cec5SDimitry Andric     case ConstructionContext::CXX17ElidedCopyReturnedValueKind: {
2030b57cec5SDimitry Andric       // The temporary is to be managed by the parent stack frame.
2040b57cec5SDimitry Andric       // So build it in the parent stack frame if we're not in the
2050b57cec5SDimitry Andric       // top frame of the analysis.
2060b57cec5SDimitry Andric       const StackFrameContext *SFC = LCtx->getStackFrame();
2070b57cec5SDimitry Andric       if (const LocationContext *CallerLCtx = SFC->getParent()) {
2080b57cec5SDimitry Andric         auto RTC = (*SFC->getCallSiteBlock())[SFC->getIndex()]
2090b57cec5SDimitry Andric                        .getAs<CFGCXXRecordTypedCall>();
2100b57cec5SDimitry Andric         if (!RTC) {
2110b57cec5SDimitry Andric           // We were unable to find the correct construction context for the
2120b57cec5SDimitry Andric           // call in the parent stack frame. This is equivalent to not being
2130b57cec5SDimitry Andric           // able to find construction context at all.
2140b57cec5SDimitry Andric           break;
2150b57cec5SDimitry Andric         }
2160b57cec5SDimitry Andric         if (isa<BlockInvocationContext>(CallerLCtx)) {
2170b57cec5SDimitry Andric           // Unwrap block invocation contexts. They're mostly part of
2180b57cec5SDimitry Andric           // the current stack frame.
2190b57cec5SDimitry Andric           CallerLCtx = CallerLCtx->getParent();
2200b57cec5SDimitry Andric           assert(!isa<BlockInvocationContext>(CallerLCtx));
2210b57cec5SDimitry Andric         }
222bdd1243dSDimitry Andric 
223bdd1243dSDimitry Andric         NodeBuilderContext CallerBldrCtx(getCoreEngine(),
224bdd1243dSDimitry Andric                                          SFC->getCallSiteBlock(), CallerLCtx);
2255ffd83dbSDimitry Andric         return computeObjectUnderConstruction(
226bdd1243dSDimitry Andric             cast<Expr>(SFC->getCallSite()), State, &CallerBldrCtx, CallerLCtx,
2270b57cec5SDimitry Andric             RTC->getConstructionContext(), CallOpts);
2280b57cec5SDimitry Andric       } else {
2290b57cec5SDimitry Andric         // We are on the top frame of the analysis. We do not know where is the
2300b57cec5SDimitry Andric         // object returned to. Conjure a symbolic region for the return value.
2310b57cec5SDimitry Andric         // TODO: We probably need a new MemRegion kind to represent the storage
232*0fca6ea1SDimitry Andric         // of that SymbolicRegion, so that we could produce a fancy symbol
2330b57cec5SDimitry Andric         // instead of an anonymous conjured symbol.
2340b57cec5SDimitry Andric         // TODO: Do we need to track the region to avoid having it dead
2350b57cec5SDimitry Andric         // too early? It does die too early, at least in C++17, but because
2360b57cec5SDimitry Andric         // putting anything into a SymbolicRegion causes an immediate escape,
2370b57cec5SDimitry Andric         // it doesn't cause any leak false positives.
2380b57cec5SDimitry Andric         const auto *RCC = cast<ReturnedValueConstructionContext>(CC);
2390b57cec5SDimitry Andric         // Make sure that this doesn't coincide with any other symbol
2400b57cec5SDimitry Andric         // conjured for the returned expression.
2410b57cec5SDimitry Andric         static const int TopLevelSymRegionTag = 0;
2420b57cec5SDimitry Andric         const Expr *RetE = RCC->getReturnStmt()->getRetValue();
2430b57cec5SDimitry Andric         assert(RetE && "Void returns should not have a construction context");
2440b57cec5SDimitry Andric         QualType ReturnTy = RetE->getType();
2450b57cec5SDimitry Andric         QualType RegionTy = ACtx.getPointerType(ReturnTy);
2465ffd83dbSDimitry Andric         return SVB.conjureSymbolVal(&TopLevelSymRegionTag, RetE, SFC, RegionTy,
2475ffd83dbSDimitry Andric                                     currBldrCtx->blockCount());
2480b57cec5SDimitry Andric       }
2490b57cec5SDimitry Andric       llvm_unreachable("Unhandled return value construction context!");
2500b57cec5SDimitry Andric     }
2510b57cec5SDimitry Andric     case ConstructionContext::ElidedTemporaryObjectKind: {
2520b57cec5SDimitry Andric       assert(AMgr.getAnalyzerOptions().ShouldElideConstructors);
2530b57cec5SDimitry Andric       const auto *TCC = cast<ElidedTemporaryObjectConstructionContext>(CC);
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric       // Support pre-C++17 copy elision. We'll have the elidable copy
2560b57cec5SDimitry Andric       // constructor in the AST and in the CFG, but we'll skip it
2570b57cec5SDimitry Andric       // and construct directly into the final object. This call
2580b57cec5SDimitry Andric       // also sets the CallOpts flags for us.
2590b57cec5SDimitry Andric       // If the elided copy/move constructor is not supported, there's still
2600b57cec5SDimitry Andric       // benefit in trying to model the non-elided constructor.
2610b57cec5SDimitry Andric       // Stash our state before trying to elide, as it'll get overwritten.
2620b57cec5SDimitry Andric       ProgramStateRef PreElideState = State;
2630b57cec5SDimitry Andric       EvalCallOptions PreElideCallOpts = CallOpts;
2640b57cec5SDimitry Andric 
2655ffd83dbSDimitry Andric       SVal V = computeObjectUnderConstruction(
266bdd1243dSDimitry Andric           TCC->getConstructorAfterElision(), State, BldrCtx, LCtx,
2675ffd83dbSDimitry Andric           TCC->getConstructionContextAfterElision(), CallOpts);
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric       // FIXME: This definition of "copy elision has not failed" is unreliable.
2700b57cec5SDimitry Andric       // It doesn't indicate that the constructor will actually be inlined
2715ffd83dbSDimitry Andric       // later; this is still up to evalCall() to decide.
2725ffd83dbSDimitry Andric       if (!CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion)
2735ffd83dbSDimitry Andric         return V;
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric       // Copy elision failed. Revert the changes and proceed as if we have
2760b57cec5SDimitry Andric       // a simple temporary.
2770b57cec5SDimitry Andric       CallOpts = PreElideCallOpts;
2785ffd83dbSDimitry Andric       CallOpts.IsElidableCtorThatHasNotBeenElided = true;
279bdd1243dSDimitry Andric       [[fallthrough]];
2800b57cec5SDimitry Andric     }
2810b57cec5SDimitry Andric     case ConstructionContext::SimpleTemporaryObjectKind: {
2820b57cec5SDimitry Andric       const auto *TCC = cast<TemporaryObjectConstructionContext>(CC);
2830b57cec5SDimitry Andric       const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr();
2840b57cec5SDimitry Andric 
2855ffd83dbSDimitry Andric       CallOpts.IsTemporaryCtorOrDtor = true;
2860b57cec5SDimitry Andric       if (MTE) {
2870b57cec5SDimitry Andric         if (const ValueDecl *VD = MTE->getExtendingDecl()) {
28806c3fb27SDimitry Andric           StorageDuration SD = MTE->getStorageDuration();
28906c3fb27SDimitry Andric           assert(SD != SD_FullExpression);
2900b57cec5SDimitry Andric           if (!VD->getType()->isReferenceType()) {
2910b57cec5SDimitry Andric             // We're lifetime-extended by a surrounding aggregate.
2920b57cec5SDimitry Andric             // Automatic destructors aren't quite working in this case
2930b57cec5SDimitry Andric             // on the CFG side. We should warn the caller about that.
2940b57cec5SDimitry Andric             // FIXME: Is there a better way to retrieve this information from
2950b57cec5SDimitry Andric             // the MaterializeTemporaryExpr?
2960b57cec5SDimitry Andric             CallOpts.IsTemporaryLifetimeExtendedViaAggregate = true;
2970b57cec5SDimitry Andric           }
2980b57cec5SDimitry Andric 
29906c3fb27SDimitry Andric           if (SD == SD_Static || SD == SD_Thread)
30006c3fb27SDimitry Andric             return loc::MemRegionVal(
30106c3fb27SDimitry Andric                 MRMgr.getCXXStaticLifetimeExtendedObjectRegion(E, VD));
30206c3fb27SDimitry Andric 
30306c3fb27SDimitry Andric           return loc::MemRegionVal(
30406c3fb27SDimitry Andric               MRMgr.getCXXLifetimeExtendedObjectRegion(E, VD, LCtx));
30506c3fb27SDimitry Andric         }
30606c3fb27SDimitry Andric         assert(MTE->getStorageDuration() == SD_FullExpression);
3070b57cec5SDimitry Andric       }
3080b57cec5SDimitry Andric 
3095ffd83dbSDimitry Andric       return loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx));
3100b57cec5SDimitry Andric     }
311972a253aSDimitry Andric     case ConstructionContext::LambdaCaptureKind: {
312972a253aSDimitry Andric       CallOpts.IsTemporaryCtorOrDtor = true;
313972a253aSDimitry Andric 
314972a253aSDimitry Andric       const auto *LCC = cast<LambdaCaptureConstructionContext>(CC);
315972a253aSDimitry Andric 
316972a253aSDimitry Andric       SVal Base = loc::MemRegionVal(
317972a253aSDimitry Andric           MRMgr.getCXXTempObjectRegion(LCC->getInitializer(), LCtx));
318972a253aSDimitry Andric 
319972a253aSDimitry Andric       const auto *CE = dyn_cast_or_null<CXXConstructExpr>(E);
320972a253aSDimitry Andric       if (getIndexOfElementToConstruct(State, CE, LCtx)) {
321972a253aSDimitry Andric         CallOpts.IsArrayCtorOrDtor = true;
322972a253aSDimitry Andric         Base = State->getLValue(E->getType(), svalBuilder.makeArrayIndex(Idx),
323972a253aSDimitry Andric                                 Base);
324972a253aSDimitry Andric       }
325972a253aSDimitry Andric 
326972a253aSDimitry Andric       return Base;
327972a253aSDimitry Andric     }
3280b57cec5SDimitry Andric     case ConstructionContext::ArgumentKind: {
3290b57cec5SDimitry Andric       // Arguments are technically temporaries.
3300b57cec5SDimitry Andric       CallOpts.IsTemporaryCtorOrDtor = true;
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric       const auto *ACC = cast<ArgumentConstructionContext>(CC);
3330b57cec5SDimitry Andric       const Expr *E = ACC->getCallLikeExpr();
3340b57cec5SDimitry Andric       unsigned Idx = ACC->getIndex();
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric       CallEventManager &CEMgr = getStateManager().getCallEventManager();
337bdd1243dSDimitry Andric       auto getArgLoc = [&](CallEventRef<> Caller) -> std::optional<SVal> {
338a7dea167SDimitry Andric         const LocationContext *FutureSFC =
339bdd1243dSDimitry Andric             Caller->getCalleeStackFrame(BldrCtx->blockCount());
3400b57cec5SDimitry Andric         // Return early if we are unable to reliably foresee
3410b57cec5SDimitry Andric         // the future stack frame.
3420b57cec5SDimitry Andric         if (!FutureSFC)
343bdd1243dSDimitry Andric           return std::nullopt;
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric         // This should be equivalent to Caller->getDecl() for now, but
3460b57cec5SDimitry Andric         // FutureSFC->getDecl() is likely to support better stuff (like
3470b57cec5SDimitry Andric         // virtual functions) earlier.
3480b57cec5SDimitry Andric         const Decl *CalleeD = FutureSFC->getDecl();
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric         // FIXME: Support for variadic arguments is not implemented here yet.
3510b57cec5SDimitry Andric         if (CallEvent::isVariadic(CalleeD))
352bdd1243dSDimitry Andric           return std::nullopt;
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric         // Operator arguments do not correspond to operator parameters
3550b57cec5SDimitry Andric         // because this-argument is implemented as a normal argument in
3560b57cec5SDimitry Andric         // operator call expressions but not in operator declarations.
3575ffd83dbSDimitry Andric         const TypedValueRegion *TVR = Caller->getParameterLocation(
358bdd1243dSDimitry Andric             *Caller->getAdjustedParameterIndex(Idx), BldrCtx->blockCount());
3595ffd83dbSDimitry Andric         if (!TVR)
360bdd1243dSDimitry Andric           return std::nullopt;
3610b57cec5SDimitry Andric 
3625ffd83dbSDimitry Andric         return loc::MemRegionVal(TVR);
3630b57cec5SDimitry Andric       };
3640b57cec5SDimitry Andric 
3650b57cec5SDimitry Andric       if (const auto *CE = dyn_cast<CallExpr>(E)) {
36606c3fb27SDimitry Andric         CallEventRef<> Caller =
36706c3fb27SDimitry Andric             CEMgr.getSimpleCall(CE, State, LCtx, getCFGElementRef());
368bdd1243dSDimitry Andric         if (std::optional<SVal> V = getArgLoc(Caller))
3695ffd83dbSDimitry Andric           return *V;
3700b57cec5SDimitry Andric         else
3710b57cec5SDimitry Andric           break;
3720b57cec5SDimitry Andric       } else if (const auto *CCE = dyn_cast<CXXConstructExpr>(E)) {
3730b57cec5SDimitry Andric         // Don't bother figuring out the target region for the future
3740b57cec5SDimitry Andric         // constructor because we won't need it.
37506c3fb27SDimitry Andric         CallEventRef<> Caller = CEMgr.getCXXConstructorCall(
37606c3fb27SDimitry Andric             CCE, /*Target=*/nullptr, State, LCtx, getCFGElementRef());
377bdd1243dSDimitry Andric         if (std::optional<SVal> V = getArgLoc(Caller))
3785ffd83dbSDimitry Andric           return *V;
3790b57cec5SDimitry Andric         else
3800b57cec5SDimitry Andric           break;
3810b57cec5SDimitry Andric       } else if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) {
38206c3fb27SDimitry Andric         CallEventRef<> Caller =
38306c3fb27SDimitry Andric             CEMgr.getObjCMethodCall(ME, State, LCtx, getCFGElementRef());
384bdd1243dSDimitry Andric         if (std::optional<SVal> V = getArgLoc(Caller))
3855ffd83dbSDimitry Andric           return *V;
3860b57cec5SDimitry Andric         else
3870b57cec5SDimitry Andric           break;
3885ffd83dbSDimitry Andric       }
3895ffd83dbSDimitry Andric     }
3905ffd83dbSDimitry Andric     } // switch (CC->getKind())
3910b57cec5SDimitry Andric   }
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric   // If we couldn't find an existing region to construct into, assume we're
3940b57cec5SDimitry Andric   // constructing a temporary. Notify the caller of our failure.
3950b57cec5SDimitry Andric   CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
3965ffd83dbSDimitry Andric   return loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx));
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric 
3995ffd83dbSDimitry Andric ProgramStateRef ExprEngine::updateObjectsUnderConstruction(
4005ffd83dbSDimitry Andric     SVal V, const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
4015ffd83dbSDimitry Andric     const ConstructionContext *CC, const EvalCallOptions &CallOpts) {
4025ffd83dbSDimitry Andric   if (CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion) {
4035ffd83dbSDimitry Andric     // Sounds like we failed to find the target region and therefore
4045ffd83dbSDimitry Andric     // copy elision failed. There's nothing we can do about it here.
4055ffd83dbSDimitry Andric     return State;
4065ffd83dbSDimitry Andric   }
4075ffd83dbSDimitry Andric 
4085ffd83dbSDimitry Andric   // See if we're constructing an existing region by looking at the
4095ffd83dbSDimitry Andric   // current construction context.
4105ffd83dbSDimitry Andric   assert(CC && "Computed target region without construction context?");
4115ffd83dbSDimitry Andric   switch (CC->getKind()) {
4125ffd83dbSDimitry Andric   case ConstructionContext::CXX17ElidedCopyVariableKind:
4135ffd83dbSDimitry Andric   case ConstructionContext::SimpleVariableKind: {
4145ffd83dbSDimitry Andric     const auto *DSCC = cast<VariableConstructionContext>(CC);
4155ffd83dbSDimitry Andric     return addObjectUnderConstruction(State, DSCC->getDeclStmt(), LCtx, V);
4165ffd83dbSDimitry Andric     }
4175ffd83dbSDimitry Andric     case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind:
4185ffd83dbSDimitry Andric     case ConstructionContext::SimpleConstructorInitializerKind: {
4195ffd83dbSDimitry Andric       const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
420e8d8bef9SDimitry Andric       const auto *Init = ICC->getCXXCtorInitializer();
421e8d8bef9SDimitry Andric       // Base and delegating initializers handled above
422e8d8bef9SDimitry Andric       assert(Init->isAnyMemberInitializer() &&
423e8d8bef9SDimitry Andric              "Base and delegating initializers should have been handled by"
424e8d8bef9SDimitry Andric              "computeObjectUnderConstruction()");
425e8d8bef9SDimitry Andric       return addObjectUnderConstruction(State, Init, LCtx, V);
4265ffd83dbSDimitry Andric     }
4275ffd83dbSDimitry Andric     case ConstructionContext::NewAllocatedObjectKind: {
4285ffd83dbSDimitry Andric       return State;
4295ffd83dbSDimitry Andric     }
4305ffd83dbSDimitry Andric     case ConstructionContext::SimpleReturnedValueKind:
4315ffd83dbSDimitry Andric     case ConstructionContext::CXX17ElidedCopyReturnedValueKind: {
4325ffd83dbSDimitry Andric       const StackFrameContext *SFC = LCtx->getStackFrame();
4335ffd83dbSDimitry Andric       const LocationContext *CallerLCtx = SFC->getParent();
4345ffd83dbSDimitry Andric       if (!CallerLCtx) {
4355ffd83dbSDimitry Andric         // No extra work is necessary in top frame.
4365ffd83dbSDimitry Andric         return State;
4375ffd83dbSDimitry Andric       }
4385ffd83dbSDimitry Andric 
4395ffd83dbSDimitry Andric       auto RTC = (*SFC->getCallSiteBlock())[SFC->getIndex()]
4405ffd83dbSDimitry Andric                      .getAs<CFGCXXRecordTypedCall>();
4415ffd83dbSDimitry Andric       assert(RTC && "Could not have had a target region without it");
4425ffd83dbSDimitry Andric       if (isa<BlockInvocationContext>(CallerLCtx)) {
4435ffd83dbSDimitry Andric         // Unwrap block invocation contexts. They're mostly part of
4445ffd83dbSDimitry Andric         // the current stack frame.
4455ffd83dbSDimitry Andric         CallerLCtx = CallerLCtx->getParent();
4465ffd83dbSDimitry Andric         assert(!isa<BlockInvocationContext>(CallerLCtx));
4475ffd83dbSDimitry Andric       }
4485ffd83dbSDimitry Andric 
4495ffd83dbSDimitry Andric       return updateObjectsUnderConstruction(V,
4505ffd83dbSDimitry Andric           cast<Expr>(SFC->getCallSite()), State, CallerLCtx,
4515ffd83dbSDimitry Andric           RTC->getConstructionContext(), CallOpts);
4525ffd83dbSDimitry Andric     }
4535ffd83dbSDimitry Andric     case ConstructionContext::ElidedTemporaryObjectKind: {
4545ffd83dbSDimitry Andric       assert(AMgr.getAnalyzerOptions().ShouldElideConstructors);
4555ffd83dbSDimitry Andric       if (!CallOpts.IsElidableCtorThatHasNotBeenElided) {
4565ffd83dbSDimitry Andric         const auto *TCC = cast<ElidedTemporaryObjectConstructionContext>(CC);
4575ffd83dbSDimitry Andric         State = updateObjectsUnderConstruction(
4585ffd83dbSDimitry Andric             V, TCC->getConstructorAfterElision(), State, LCtx,
4595ffd83dbSDimitry Andric             TCC->getConstructionContextAfterElision(), CallOpts);
4605ffd83dbSDimitry Andric 
4615ffd83dbSDimitry Andric         // Remember that we've elided the constructor.
4625ffd83dbSDimitry Andric         State = addObjectUnderConstruction(
4635ffd83dbSDimitry Andric             State, TCC->getConstructorAfterElision(), LCtx, V);
4645ffd83dbSDimitry Andric 
4655ffd83dbSDimitry Andric         // Remember that we've elided the destructor.
4665ffd83dbSDimitry Andric         if (const auto *BTE = TCC->getCXXBindTemporaryExpr())
4675ffd83dbSDimitry Andric           State = elideDestructor(State, BTE, LCtx);
4685ffd83dbSDimitry Andric 
4695ffd83dbSDimitry Andric         // Instead of materialization, shamelessly return
4705ffd83dbSDimitry Andric         // the final object destination.
4715ffd83dbSDimitry Andric         if (const auto *MTE = TCC->getMaterializedTemporaryExpr())
4725ffd83dbSDimitry Andric           State = addObjectUnderConstruction(State, MTE, LCtx, V);
4735ffd83dbSDimitry Andric 
4745ffd83dbSDimitry Andric         return State;
4755ffd83dbSDimitry Andric       }
4765ffd83dbSDimitry Andric       // If we decided not to elide the constructor, proceed as if
4775ffd83dbSDimitry Andric       // it's a simple temporary.
478bdd1243dSDimitry Andric       [[fallthrough]];
4795ffd83dbSDimitry Andric     }
4805ffd83dbSDimitry Andric     case ConstructionContext::SimpleTemporaryObjectKind: {
4815ffd83dbSDimitry Andric       const auto *TCC = cast<TemporaryObjectConstructionContext>(CC);
4825ffd83dbSDimitry Andric       if (const auto *BTE = TCC->getCXXBindTemporaryExpr())
4835ffd83dbSDimitry Andric         State = addObjectUnderConstruction(State, BTE, LCtx, V);
4845ffd83dbSDimitry Andric 
4855ffd83dbSDimitry Andric       if (const auto *MTE = TCC->getMaterializedTemporaryExpr())
4865ffd83dbSDimitry Andric         State = addObjectUnderConstruction(State, MTE, LCtx, V);
4875ffd83dbSDimitry Andric 
4885ffd83dbSDimitry Andric       return State;
4895ffd83dbSDimitry Andric     }
490972a253aSDimitry Andric     case ConstructionContext::LambdaCaptureKind: {
491972a253aSDimitry Andric       const auto *LCC = cast<LambdaCaptureConstructionContext>(CC);
492972a253aSDimitry Andric 
493972a253aSDimitry Andric       // If we capture and array, we want to store the super region, not a
494972a253aSDimitry Andric       // sub-region.
495972a253aSDimitry Andric       if (const auto *EL = dyn_cast_or_null<ElementRegion>(V.getAsRegion()))
496972a253aSDimitry Andric         V = loc::MemRegionVal(EL->getSuperRegion());
497972a253aSDimitry Andric 
498972a253aSDimitry Andric       return addObjectUnderConstruction(
499972a253aSDimitry Andric           State, {LCC->getLambdaExpr(), LCC->getIndex()}, LCtx, V);
500972a253aSDimitry Andric     }
5015ffd83dbSDimitry Andric     case ConstructionContext::ArgumentKind: {
5025ffd83dbSDimitry Andric       const auto *ACC = cast<ArgumentConstructionContext>(CC);
5035ffd83dbSDimitry Andric       if (const auto *BTE = ACC->getCXXBindTemporaryExpr())
5045ffd83dbSDimitry Andric         State = addObjectUnderConstruction(State, BTE, LCtx, V);
5055ffd83dbSDimitry Andric 
5065ffd83dbSDimitry Andric       return addObjectUnderConstruction(
5075ffd83dbSDimitry Andric           State, {ACC->getCallLikeExpr(), ACC->getIndex()}, LCtx, V);
5085ffd83dbSDimitry Andric     }
5095ffd83dbSDimitry Andric   }
5105ffd83dbSDimitry Andric   llvm_unreachable("Unhandled construction context!");
5115ffd83dbSDimitry Andric }
5125ffd83dbSDimitry Andric 
513972a253aSDimitry Andric static ProgramStateRef
514972a253aSDimitry Andric bindRequiredArrayElementToEnvironment(ProgramStateRef State,
515972a253aSDimitry Andric                                       const ArrayInitLoopExpr *AILE,
516972a253aSDimitry Andric                                       const LocationContext *LCtx, SVal Idx) {
517972a253aSDimitry Andric   // The ctor in this case is guaranteed to be a copy ctor, otherwise we hit a
518972a253aSDimitry Andric   // compile time error.
519972a253aSDimitry Andric   //
520972a253aSDimitry Andric   //  -ArrayInitLoopExpr                <-- we're here
521972a253aSDimitry Andric   //   |-OpaqueValueExpr
522972a253aSDimitry Andric   //   | `-DeclRefExpr                  <-- match this
523972a253aSDimitry Andric   //   `-CXXConstructExpr
524972a253aSDimitry Andric   //     `-ImplicitCastExpr
525972a253aSDimitry Andric   //       `-ArraySubscriptExpr
526972a253aSDimitry Andric   //         |-ImplicitCastExpr
527972a253aSDimitry Andric   //         | `-OpaqueValueExpr
528972a253aSDimitry Andric   //         |   `-DeclRefExpr
529972a253aSDimitry Andric   //         `-ArrayInitIndexExpr
530972a253aSDimitry Andric   //
531972a253aSDimitry Andric   // The resulting expression might look like the one below in an implicit
532972a253aSDimitry Andric   // copy/move ctor.
533972a253aSDimitry Andric   //
534972a253aSDimitry Andric   //   ArrayInitLoopExpr                <-- we're here
535972a253aSDimitry Andric   //   |-OpaqueValueExpr
536972a253aSDimitry Andric   //   | `-MemberExpr                   <-- match this
537972a253aSDimitry Andric   //   |  (`-CXXStaticCastExpr)         <-- move ctor only
538972a253aSDimitry Andric   //   |     `-DeclRefExpr
539972a253aSDimitry Andric   //   `-CXXConstructExpr
540972a253aSDimitry Andric   //     `-ArraySubscriptExpr
541972a253aSDimitry Andric   //       |-ImplicitCastExpr
542972a253aSDimitry Andric   //       | `-OpaqueValueExpr
543972a253aSDimitry Andric   //       |   `-MemberExpr
544972a253aSDimitry Andric   //       |     `-DeclRefExpr
545972a253aSDimitry Andric   //       `-ArrayInitIndexExpr
546972a253aSDimitry Andric   //
547bdd1243dSDimitry Andric   // The resulting expression for a multidimensional array.
548bdd1243dSDimitry Andric   // ArrayInitLoopExpr                  <-- we're here
549bdd1243dSDimitry Andric   // |-OpaqueValueExpr
550bdd1243dSDimitry Andric   // | `-DeclRefExpr                    <-- match this
551bdd1243dSDimitry Andric   // `-ArrayInitLoopExpr
552bdd1243dSDimitry Andric   //   |-OpaqueValueExpr
553bdd1243dSDimitry Andric   //   | `-ArraySubscriptExpr
554bdd1243dSDimitry Andric   //   |   |-ImplicitCastExpr
555bdd1243dSDimitry Andric   //   |   | `-OpaqueValueExpr
556bdd1243dSDimitry Andric   //   |   |   `-DeclRefExpr
557bdd1243dSDimitry Andric   //   |   `-ArrayInitIndexExpr
558bdd1243dSDimitry Andric   //   `-CXXConstructExpr             <-- extract this
559bdd1243dSDimitry Andric   //     ` ...
560bdd1243dSDimitry Andric 
561bdd1243dSDimitry Andric   const auto *OVESrc = AILE->getCommonExpr()->getSourceExpr();
562bdd1243dSDimitry Andric 
563972a253aSDimitry Andric   // HACK: There is no way we can put the index of the array element into the
564972a253aSDimitry Andric   // CFG unless we unroll the loop, so we manually select and bind the required
565972a253aSDimitry Andric   // parameter to the environment.
566bdd1243dSDimitry Andric   const auto *CE =
567bdd1243dSDimitry Andric       cast<CXXConstructExpr>(extractElementInitializerFromNestedAILE(AILE));
568972a253aSDimitry Andric 
569972a253aSDimitry Andric   SVal Base = UnknownVal();
570972a253aSDimitry Andric   if (const auto *ME = dyn_cast<MemberExpr>(OVESrc))
571972a253aSDimitry Andric     Base = State->getSVal(ME, LCtx);
572bdd1243dSDimitry Andric   else if (const auto *DRE = dyn_cast<DeclRefExpr>(OVESrc))
573972a253aSDimitry Andric     Base = State->getLValue(cast<VarDecl>(DRE->getDecl()), LCtx);
574972a253aSDimitry Andric   else
575972a253aSDimitry Andric     llvm_unreachable("ArrayInitLoopExpr contains unexpected source expression");
576972a253aSDimitry Andric 
577972a253aSDimitry Andric   SVal NthElem = State->getLValue(CE->getType(), Idx, Base);
578972a253aSDimitry Andric 
579972a253aSDimitry Andric   return State->BindExpr(CE->getArg(0), LCtx, NthElem);
580972a253aSDimitry Andric }
581972a253aSDimitry Andric 
5825ffd83dbSDimitry Andric void ExprEngine::handleConstructor(const Expr *E,
5830b57cec5SDimitry Andric                                    ExplodedNode *Pred,
5840b57cec5SDimitry Andric                                    ExplodedNodeSet &destNodes) {
5855ffd83dbSDimitry Andric   const auto *CE = dyn_cast<CXXConstructExpr>(E);
5865ffd83dbSDimitry Andric   const auto *CIE = dyn_cast<CXXInheritedCtorInitExpr>(E);
5875ffd83dbSDimitry Andric   assert(CE || CIE);
5885ffd83dbSDimitry Andric 
5890b57cec5SDimitry Andric   const LocationContext *LCtx = Pred->getLocationContext();
5900b57cec5SDimitry Andric   ProgramStateRef State = Pred->getState();
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric   SVal Target = UnknownVal();
5930b57cec5SDimitry Andric 
5945ffd83dbSDimitry Andric   if (CE) {
595bdd1243dSDimitry Andric     if (std::optional<SVal> ElidedTarget =
5960b57cec5SDimitry Andric             getObjectUnderConstruction(State, CE, LCtx)) {
597bdd1243dSDimitry Andric         // We've previously modeled an elidable constructor by pretending that
598bdd1243dSDimitry Andric         // it in fact constructs into the correct target. This constructor can
5995ffd83dbSDimitry Andric         // therefore be skipped.
6000b57cec5SDimitry Andric         Target = *ElidedTarget;
6010b57cec5SDimitry Andric         StmtNodeBuilder Bldr(Pred, destNodes, *currBldrCtx);
6020b57cec5SDimitry Andric         State = finishObjectConstruction(State, CE, LCtx);
6030b57cec5SDimitry Andric         if (auto L = Target.getAs<Loc>())
6040b57cec5SDimitry Andric           State = State->BindExpr(CE, LCtx, State->getSVal(*L, CE->getType()));
6050b57cec5SDimitry Andric         Bldr.generateNode(CE, Pred, State);
6060b57cec5SDimitry Andric         return;
6070b57cec5SDimitry Andric     }
6085ffd83dbSDimitry Andric   }
6090b57cec5SDimitry Andric 
6100b57cec5SDimitry Andric   EvalCallOptions CallOpts;
6110b57cec5SDimitry Andric   auto C = getCurrentCFGElement().getAs<CFGConstructor>();
6120b57cec5SDimitry Andric   assert(C || getCurrentCFGElement().getAs<CFGStmt>());
6130b57cec5SDimitry Andric   const ConstructionContext *CC = C ? C->getConstructionContext() : nullptr;
6140b57cec5SDimitry Andric 
6155f757f3fSDimitry Andric   const CXXConstructionKind CK =
6165ffd83dbSDimitry Andric       CE ? CE->getConstructionKind() : CIE->getConstructionKind();
6175ffd83dbSDimitry Andric   switch (CK) {
6185f757f3fSDimitry Andric   case CXXConstructionKind::Complete: {
6195ffd83dbSDimitry Andric     // Inherited constructors are always base class constructors.
6205ffd83dbSDimitry Andric     assert(CE && !CIE && "A complete constructor is inherited?!");
6215ffd83dbSDimitry Andric 
622972a253aSDimitry Andric     // If the ctor is part of an ArrayInitLoopExpr, we want to handle it
623972a253aSDimitry Andric     // differently.
624972a253aSDimitry Andric     auto *AILE = CC ? CC->getArrayInitLoop() : nullptr;
625972a253aSDimitry Andric 
626fcaf7f86SDimitry Andric     unsigned Idx = 0;
627972a253aSDimitry Andric     if (CE->getType()->isArrayType() || AILE) {
628bdd1243dSDimitry Andric 
629bdd1243dSDimitry Andric       auto isZeroSizeArray = [&] {
630bdd1243dSDimitry Andric         uint64_t Size = 1;
631bdd1243dSDimitry Andric 
632bdd1243dSDimitry Andric         if (const auto *CAT = dyn_cast<ConstantArrayType>(CE->getType()))
633bdd1243dSDimitry Andric           Size = getContext().getConstantArrayElementCount(CAT);
634bdd1243dSDimitry Andric         else if (AILE)
635bdd1243dSDimitry Andric           Size = getContext().getArrayInitLoopExprElementCount(AILE);
636bdd1243dSDimitry Andric 
637bdd1243dSDimitry Andric         return Size == 0;
638bdd1243dSDimitry Andric       };
639bdd1243dSDimitry Andric 
640bdd1243dSDimitry Andric       // No element construction will happen in a 0 size array.
641bdd1243dSDimitry Andric       if (isZeroSizeArray()) {
642bdd1243dSDimitry Andric         StmtNodeBuilder Bldr(Pred, destNodes, *currBldrCtx);
643bdd1243dSDimitry Andric         static SimpleProgramPointTag T{"ExprEngine",
644bdd1243dSDimitry Andric                                        "Skipping 0 size array construction"};
645bdd1243dSDimitry Andric         Bldr.generateNode(CE, Pred, State, &T);
646bdd1243dSDimitry Andric         return;
647bdd1243dSDimitry Andric       }
648bdd1243dSDimitry Andric 
649fcaf7f86SDimitry Andric       Idx = getIndexOfElementToConstruct(State, CE, LCtx).value_or(0u);
650fcaf7f86SDimitry Andric       State = setIndexOfElementToConstruct(State, CE, LCtx, Idx + 1);
651fcaf7f86SDimitry Andric     }
652fcaf7f86SDimitry Andric 
653972a253aSDimitry Andric     if (AILE) {
654972a253aSDimitry Andric       // Only set this once even though we loop through it multiple times.
655972a253aSDimitry Andric       if (!getPendingInitLoop(State, CE, LCtx))
656bdd1243dSDimitry Andric         State = setPendingInitLoop(
657bdd1243dSDimitry Andric             State, CE, LCtx,
658bdd1243dSDimitry Andric             getContext().getArrayInitLoopExprElementCount(AILE));
659972a253aSDimitry Andric 
660972a253aSDimitry Andric       State = bindRequiredArrayElementToEnvironment(
661972a253aSDimitry Andric           State, AILE, LCtx, svalBuilder.makeArrayIndex(Idx));
662972a253aSDimitry Andric     }
663972a253aSDimitry Andric 
6645ffd83dbSDimitry Andric     // The target region is found from construction context.
665bdd1243dSDimitry Andric     std::tie(State, Target) = handleConstructionContext(
666bdd1243dSDimitry Andric         CE, State, currBldrCtx, LCtx, CC, CallOpts, Idx);
6670b57cec5SDimitry Andric     break;
6680b57cec5SDimitry Andric   }
6695f757f3fSDimitry Andric   case CXXConstructionKind::VirtualBase: {
6700b57cec5SDimitry Andric     // Make sure we are not calling virtual base class initializers twice.
6710b57cec5SDimitry Andric     // Only the most-derived object should initialize virtual base classes.
6720b57cec5SDimitry Andric     const auto *OuterCtor = dyn_cast_or_null<CXXConstructExpr>(
6730b57cec5SDimitry Andric         LCtx->getStackFrame()->getCallSite());
6740b57cec5SDimitry Andric     assert(
6750b57cec5SDimitry Andric         (!OuterCtor ||
6765f757f3fSDimitry Andric          OuterCtor->getConstructionKind() == CXXConstructionKind::Complete ||
6775f757f3fSDimitry Andric          OuterCtor->getConstructionKind() == CXXConstructionKind::Delegating) &&
6780b57cec5SDimitry Andric         ("This virtual base should have already been initialized by "
6790b57cec5SDimitry Andric          "the most derived class!"));
6800b57cec5SDimitry Andric     (void)OuterCtor;
681bdd1243dSDimitry Andric     [[fallthrough]];
6820b57cec5SDimitry Andric   }
6835f757f3fSDimitry Andric   case CXXConstructionKind::NonVirtualBase:
6840b57cec5SDimitry Andric     // In C++17, classes with non-virtual bases may be aggregates, so they would
6850b57cec5SDimitry Andric     // be initialized as aggregates without a constructor call, so we may have
6860b57cec5SDimitry Andric     // a base class constructed directly into an initializer list without
6870b57cec5SDimitry Andric     // having the derived-class constructor call on the previous stack frame.
6880b57cec5SDimitry Andric     // Initializer lists may be nested into more initializer lists that
6890b57cec5SDimitry Andric     // correspond to surrounding aggregate initializations.
6900b57cec5SDimitry Andric     // FIXME: For now this code essentially bails out. We need to find the
6910b57cec5SDimitry Andric     // correct target region and set it.
6920b57cec5SDimitry Andric     // FIXME: Instead of relying on the ParentMap, we should have the
6930b57cec5SDimitry Andric     // trigger-statement (InitListExpr in this case) passed down from CFG or
6940b57cec5SDimitry Andric     // otherwise always available during construction.
695349cc55cSDimitry Andric     if (isa_and_nonnull<InitListExpr>(LCtx->getParentMap().getParent(E))) {
6960b57cec5SDimitry Andric       MemRegionManager &MRMgr = getSValBuilder().getRegionManager();
6975ffd83dbSDimitry Andric       Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx));
6980b57cec5SDimitry Andric       CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
6990b57cec5SDimitry Andric       break;
7000b57cec5SDimitry Andric     }
701bdd1243dSDimitry Andric     [[fallthrough]];
7025f757f3fSDimitry Andric   case CXXConstructionKind::Delegating: {
7030b57cec5SDimitry Andric     const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
7040b57cec5SDimitry Andric     Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor,
7050b57cec5SDimitry Andric                                               LCtx->getStackFrame());
7060b57cec5SDimitry Andric     SVal ThisVal = State->getSVal(ThisPtr);
7070b57cec5SDimitry Andric 
7085f757f3fSDimitry Andric     if (CK == CXXConstructionKind::Delegating) {
7090b57cec5SDimitry Andric       Target = ThisVal;
7100b57cec5SDimitry Andric     } else {
7110b57cec5SDimitry Andric       // Cast to the base type.
7125f757f3fSDimitry Andric       bool IsVirtual = (CK == CXXConstructionKind::VirtualBase);
7135ffd83dbSDimitry Andric       SVal BaseVal =
7145ffd83dbSDimitry Andric           getStoreManager().evalDerivedToBase(ThisVal, E->getType(), IsVirtual);
7150b57cec5SDimitry Andric       Target = BaseVal;
7160b57cec5SDimitry Andric     }
7170b57cec5SDimitry Andric     break;
7180b57cec5SDimitry Andric   }
7190b57cec5SDimitry Andric   }
7200b57cec5SDimitry Andric 
7210b57cec5SDimitry Andric   if (State != Pred->getState()) {
7220b57cec5SDimitry Andric     static SimpleProgramPointTag T("ExprEngine",
7230b57cec5SDimitry Andric                                    "Prepare for object construction");
7240b57cec5SDimitry Andric     ExplodedNodeSet DstPrepare;
7250b57cec5SDimitry Andric     StmtNodeBuilder BldrPrepare(Pred, DstPrepare, *currBldrCtx);
7265ffd83dbSDimitry Andric     BldrPrepare.generateNode(E, Pred, State, &T, ProgramPoint::PreStmtKind);
7270b57cec5SDimitry Andric     assert(DstPrepare.size() <= 1);
7280b57cec5SDimitry Andric     if (DstPrepare.size() == 0)
7290b57cec5SDimitry Andric       return;
7300b57cec5SDimitry Andric     Pred = *BldrPrepare.begin();
7310b57cec5SDimitry Andric   }
7320b57cec5SDimitry Andric 
7335ffd83dbSDimitry Andric   const MemRegion *TargetRegion = Target.getAsRegion();
7340b57cec5SDimitry Andric   CallEventManager &CEMgr = getStateManager().getCallEventManager();
7355ffd83dbSDimitry Andric   CallEventRef<> Call =
7365ffd83dbSDimitry Andric       CIE ? (CallEventRef<>)CEMgr.getCXXInheritedConstructorCall(
73706c3fb27SDimitry Andric                 CIE, TargetRegion, State, LCtx, getCFGElementRef())
7385ffd83dbSDimitry Andric           : (CallEventRef<>)CEMgr.getCXXConstructorCall(
73906c3fb27SDimitry Andric                 CE, TargetRegion, State, LCtx, getCFGElementRef());
7400b57cec5SDimitry Andric 
7410b57cec5SDimitry Andric   ExplodedNodeSet DstPreVisit;
7425ffd83dbSDimitry Andric   getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, E, *this);
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric   ExplodedNodeSet PreInitialized;
7455ffd83dbSDimitry Andric   if (CE) {
7465ffd83dbSDimitry Andric     // FIXME: Is it possible and/or useful to do this before PreStmt?
7470b57cec5SDimitry Andric     StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx);
74806c3fb27SDimitry Andric     for (ExplodedNode *N : DstPreVisit) {
74906c3fb27SDimitry Andric       ProgramStateRef State = N->getState();
7500b57cec5SDimitry Andric       if (CE->requiresZeroInitialization()) {
7510b57cec5SDimitry Andric         // FIXME: Once we properly handle constructors in new-expressions, we'll
7520b57cec5SDimitry Andric         // need to invalidate the region before setting a default value, to make
7530b57cec5SDimitry Andric         // sure there aren't any lingering bindings around. This probably needs
7540b57cec5SDimitry Andric         // to happen regardless of whether or not the object is zero-initialized
7550b57cec5SDimitry Andric         // to handle random fields of a placement-initialized object picking up
7560b57cec5SDimitry Andric         // old bindings. We might only want to do it when we need to, though.
7570b57cec5SDimitry Andric         // FIXME: This isn't actually correct for arrays -- we need to zero-
7580b57cec5SDimitry Andric         // initialize the entire array, not just the first element -- but our
7590b57cec5SDimitry Andric         // handling of arrays everywhere else is weak as well, so this shouldn't
7600b57cec5SDimitry Andric         // actually make things worse. Placement new makes this tricky as well,
7610b57cec5SDimitry Andric         // since it's then possible to be initializing one part of a multi-
7620b57cec5SDimitry Andric         // dimensional array.
7630b57cec5SDimitry Andric         State = State->bindDefaultZero(Target, LCtx);
7640b57cec5SDimitry Andric       }
7650b57cec5SDimitry Andric 
76606c3fb27SDimitry Andric       Bldr.generateNode(CE, N, State, /*tag=*/nullptr,
7670b57cec5SDimitry Andric                         ProgramPoint::PreStmtKind);
7680b57cec5SDimitry Andric     }
7695ffd83dbSDimitry Andric   } else {
7705ffd83dbSDimitry Andric     PreInitialized = DstPreVisit;
7710b57cec5SDimitry Andric   }
7720b57cec5SDimitry Andric 
7730b57cec5SDimitry Andric   ExplodedNodeSet DstPreCall;
7740b57cec5SDimitry Andric   getCheckerManager().runCheckersForPreCall(DstPreCall, PreInitialized,
7750b57cec5SDimitry Andric                                             *Call, *this);
7760b57cec5SDimitry Andric 
7770b57cec5SDimitry Andric   ExplodedNodeSet DstEvaluated;
7780b57cec5SDimitry Andric 
7795ffd83dbSDimitry Andric   if (CE && CE->getConstructor()->isTrivial() &&
7800b57cec5SDimitry Andric       CE->getConstructor()->isCopyOrMoveConstructor() &&
7810b57cec5SDimitry Andric       !CallOpts.IsArrayCtorOrDtor) {
782e8d8bef9SDimitry Andric     StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx);
7830b57cec5SDimitry Andric     // FIXME: Handle other kinds of trivial constructors as well.
78406c3fb27SDimitry Andric     for (ExplodedNode *N : DstPreCall)
78506c3fb27SDimitry Andric       performTrivialCopy(Bldr, N, *Call);
7860b57cec5SDimitry Andric 
7870b57cec5SDimitry Andric   } else {
78806c3fb27SDimitry Andric     for (ExplodedNode *N : DstPreCall)
78906c3fb27SDimitry Andric       getCheckerManager().runCheckersForEvalCall(DstEvaluated, N, *Call, *this,
7905ffd83dbSDimitry Andric                                                  CallOpts);
7910b57cec5SDimitry Andric   }
7920b57cec5SDimitry Andric 
7930b57cec5SDimitry Andric   // If the CFG was constructed without elements for temporary destructors
7940b57cec5SDimitry Andric   // and the just-called constructor created a temporary object then
7950b57cec5SDimitry Andric   // stop exploration if the temporary object has a noreturn constructor.
7960b57cec5SDimitry Andric   // This can lose coverage because the destructor, if it were present
7970b57cec5SDimitry Andric   // in the CFG, would be called at the end of the full expression or
7980b57cec5SDimitry Andric   // later (for life-time extended temporaries) -- but avoids infeasible
7990b57cec5SDimitry Andric   // paths when no-return temporary destructors are used for assertions.
800e8d8bef9SDimitry Andric   ExplodedNodeSet DstEvaluatedPostProcessed;
801e8d8bef9SDimitry Andric   StmtNodeBuilder Bldr(DstEvaluated, DstEvaluatedPostProcessed, *currBldrCtx);
8020b57cec5SDimitry Andric   const AnalysisDeclContext *ADC = LCtx->getAnalysisDeclContext();
8030b57cec5SDimitry Andric   if (!ADC->getCFGBuildOptions().AddTemporaryDtors) {
80406c3fb27SDimitry Andric     if (llvm::isa_and_nonnull<CXXTempObjectRegion,
80506c3fb27SDimitry Andric                               CXXLifetimeExtendedObjectRegion>(TargetRegion) &&
8065ffd83dbSDimitry Andric         cast<CXXConstructorDecl>(Call->getDecl())
8075ffd83dbSDimitry Andric             ->getParent()
8085ffd83dbSDimitry Andric             ->isAnyDestructorNoReturn()) {
8090b57cec5SDimitry Andric 
8100b57cec5SDimitry Andric       // If we've inlined the constructor, then DstEvaluated would be empty.
8110b57cec5SDimitry Andric       // In this case we still want a sink, which could be implemented
8120b57cec5SDimitry Andric       // in processCallExit. But we don't have that implemented at the moment,
8130b57cec5SDimitry Andric       // so if you hit this assertion, see if you can avoid inlining
8140b57cec5SDimitry Andric       // the respective constructor when analyzer-config cfg-temporary-dtors
8150b57cec5SDimitry Andric       // is set to false.
8160b57cec5SDimitry Andric       // Otherwise there's nothing wrong with inlining such constructor.
8170b57cec5SDimitry Andric       assert(!DstEvaluated.empty() &&
8180b57cec5SDimitry Andric              "We should not have inlined this constructor!");
8190b57cec5SDimitry Andric 
8200b57cec5SDimitry Andric       for (ExplodedNode *N : DstEvaluated) {
8215ffd83dbSDimitry Andric         Bldr.generateSink(E, N, N->getState());
8220b57cec5SDimitry Andric       }
8230b57cec5SDimitry Andric 
8240b57cec5SDimitry Andric       // There is no need to run the PostCall and PostStmt checker
8250b57cec5SDimitry Andric       // callbacks because we just generated sinks on all nodes in th
8260b57cec5SDimitry Andric       // frontier.
8270b57cec5SDimitry Andric       return;
8280b57cec5SDimitry Andric     }
8290b57cec5SDimitry Andric   }
8300b57cec5SDimitry Andric 
8310b57cec5SDimitry Andric   ExplodedNodeSet DstPostArgumentCleanup;
832e8d8bef9SDimitry Andric   for (ExplodedNode *I : DstEvaluatedPostProcessed)
8330b57cec5SDimitry Andric     finishArgumentConstruction(DstPostArgumentCleanup, I, *Call);
8340b57cec5SDimitry Andric 
8350b57cec5SDimitry Andric   // If there were other constructors called for object-type arguments
8360b57cec5SDimitry Andric   // of this constructor, clean them up.
8370b57cec5SDimitry Andric   ExplodedNodeSet DstPostCall;
8380b57cec5SDimitry Andric   getCheckerManager().runCheckersForPostCall(DstPostCall,
8390b57cec5SDimitry Andric                                              DstPostArgumentCleanup,
8400b57cec5SDimitry Andric                                              *Call, *this);
8415ffd83dbSDimitry Andric   getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, E, *this);
8425ffd83dbSDimitry Andric }
8435ffd83dbSDimitry Andric 
8445ffd83dbSDimitry Andric void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
8455ffd83dbSDimitry Andric                                        ExplodedNode *Pred,
8465ffd83dbSDimitry Andric                                        ExplodedNodeSet &Dst) {
8475ffd83dbSDimitry Andric   handleConstructor(CE, Pred, Dst);
8485ffd83dbSDimitry Andric }
8495ffd83dbSDimitry Andric 
8505ffd83dbSDimitry Andric void ExprEngine::VisitCXXInheritedCtorInitExpr(
8515ffd83dbSDimitry Andric     const CXXInheritedCtorInitExpr *CE, ExplodedNode *Pred,
8525ffd83dbSDimitry Andric     ExplodedNodeSet &Dst) {
8535ffd83dbSDimitry Andric   handleConstructor(CE, Pred, Dst);
8540b57cec5SDimitry Andric }
8550b57cec5SDimitry Andric 
8560b57cec5SDimitry Andric void ExprEngine::VisitCXXDestructor(QualType ObjectType,
8570b57cec5SDimitry Andric                                     const MemRegion *Dest,
8580b57cec5SDimitry Andric                                     const Stmt *S,
8590b57cec5SDimitry Andric                                     bool IsBaseDtor,
8600b57cec5SDimitry Andric                                     ExplodedNode *Pred,
8610b57cec5SDimitry Andric                                     ExplodedNodeSet &Dst,
862a7dea167SDimitry Andric                                     EvalCallOptions &CallOpts) {
8630b57cec5SDimitry Andric   assert(S && "A destructor without a trigger!");
8640b57cec5SDimitry Andric   const LocationContext *LCtx = Pred->getLocationContext();
8650b57cec5SDimitry Andric   ProgramStateRef State = Pred->getState();
8660b57cec5SDimitry Andric 
8670b57cec5SDimitry Andric   const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl();
8680b57cec5SDimitry Andric   assert(RecordDecl && "Only CXXRecordDecls should have destructors");
8690b57cec5SDimitry Andric   const CXXDestructorDecl *DtorDecl = RecordDecl->getDestructor();
8700b57cec5SDimitry Andric   // FIXME: There should always be a Decl, otherwise the destructor call
8710b57cec5SDimitry Andric   // shouldn't have been added to the CFG in the first place.
8720b57cec5SDimitry Andric   if (!DtorDecl) {
8730b57cec5SDimitry Andric     // Skip the invalid destructor. We cannot simply return because
8740b57cec5SDimitry Andric     // it would interrupt the analysis instead.
8750b57cec5SDimitry Andric     static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor");
8760b57cec5SDimitry Andric     // FIXME: PostImplicitCall with a null decl may crash elsewhere anyway.
87706c3fb27SDimitry Andric     PostImplicitCall PP(/*Decl=*/nullptr, S->getEndLoc(), LCtx,
87806c3fb27SDimitry Andric                         getCFGElementRef(), &T);
8790b57cec5SDimitry Andric     NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
8800b57cec5SDimitry Andric     Bldr.generateNode(PP, Pred->getState(), Pred);
8810b57cec5SDimitry Andric     return;
8820b57cec5SDimitry Andric   }
8830b57cec5SDimitry Andric 
884a7dea167SDimitry Andric   if (!Dest) {
885a7dea167SDimitry Andric     // We're trying to destroy something that is not a region. This may happen
886a7dea167SDimitry Andric     // for a variety of reasons (unknown target region, concrete integer instead
887a7dea167SDimitry Andric     // of target region, etc.). The current code makes an attempt to recover.
888a7dea167SDimitry Andric     // FIXME: We probably don't really need to recover when we're dealing
889a7dea167SDimitry Andric     // with concrete integers specifically.
890a7dea167SDimitry Andric     CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
891a7dea167SDimitry Andric     if (const Expr *E = dyn_cast_or_null<Expr>(S)) {
892a7dea167SDimitry Andric       Dest = MRMgr.getCXXTempObjectRegion(E, Pred->getLocationContext());
893a7dea167SDimitry Andric     } else {
894a7dea167SDimitry Andric       static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor");
895a7dea167SDimitry Andric       NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
896a7dea167SDimitry Andric       Bldr.generateSink(Pred->getLocation().withTag(&T),
897a7dea167SDimitry Andric                         Pred->getState(), Pred);
898a7dea167SDimitry Andric       return;
899a7dea167SDimitry Andric     }
900a7dea167SDimitry Andric   }
901a7dea167SDimitry Andric 
9020b57cec5SDimitry Andric   CallEventManager &CEMgr = getStateManager().getCallEventManager();
90306c3fb27SDimitry Andric   CallEventRef<CXXDestructorCall> Call = CEMgr.getCXXDestructorCall(
90406c3fb27SDimitry Andric       DtorDecl, S, Dest, IsBaseDtor, State, LCtx, getCFGElementRef());
9050b57cec5SDimitry Andric 
9060b57cec5SDimitry Andric   PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
9070b57cec5SDimitry Andric                                 Call->getSourceRange().getBegin(),
9080b57cec5SDimitry Andric                                 "Error evaluating destructor");
9090b57cec5SDimitry Andric 
9100b57cec5SDimitry Andric   ExplodedNodeSet DstPreCall;
9110b57cec5SDimitry Andric   getCheckerManager().runCheckersForPreCall(DstPreCall, Pred,
9120b57cec5SDimitry Andric                                             *Call, *this);
9130b57cec5SDimitry Andric 
9140b57cec5SDimitry Andric   ExplodedNodeSet DstInvalidated;
9150b57cec5SDimitry Andric   StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
91606c3fb27SDimitry Andric   for (ExplodedNode *N : DstPreCall)
91706c3fb27SDimitry Andric     defaultEvalCall(Bldr, N, *Call, CallOpts);
9180b57cec5SDimitry Andric 
9190b57cec5SDimitry Andric   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
9200b57cec5SDimitry Andric                                              *Call, *this);
9210b57cec5SDimitry Andric }
9220b57cec5SDimitry Andric 
9230b57cec5SDimitry Andric void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
9240b57cec5SDimitry Andric                                           ExplodedNode *Pred,
9250b57cec5SDimitry Andric                                           ExplodedNodeSet &Dst) {
9260b57cec5SDimitry Andric   ProgramStateRef State = Pred->getState();
9270b57cec5SDimitry Andric   const LocationContext *LCtx = Pred->getLocationContext();
9280b57cec5SDimitry Andric   PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
9290b57cec5SDimitry Andric                                 CNE->getBeginLoc(),
9300b57cec5SDimitry Andric                                 "Error evaluating New Allocator Call");
9310b57cec5SDimitry Andric   CallEventManager &CEMgr = getStateManager().getCallEventManager();
9320b57cec5SDimitry Andric   CallEventRef<CXXAllocatorCall> Call =
93306c3fb27SDimitry Andric       CEMgr.getCXXAllocatorCall(CNE, State, LCtx, getCFGElementRef());
9340b57cec5SDimitry Andric 
9350b57cec5SDimitry Andric   ExplodedNodeSet DstPreCall;
9360b57cec5SDimitry Andric   getCheckerManager().runCheckersForPreCall(DstPreCall, Pred,
9370b57cec5SDimitry Andric                                             *Call, *this);
9380b57cec5SDimitry Andric 
9390b57cec5SDimitry Andric   ExplodedNodeSet DstPostCall;
9400b57cec5SDimitry Andric   StmtNodeBuilder CallBldr(DstPreCall, DstPostCall, *currBldrCtx);
9415ffd83dbSDimitry Andric   for (ExplodedNode *I : DstPreCall) {
9420b57cec5SDimitry Andric     // FIXME: Provide evalCall for checkers?
9430b57cec5SDimitry Andric     defaultEvalCall(CallBldr, I, *Call);
9440b57cec5SDimitry Andric   }
9450b57cec5SDimitry Andric   // If the call is inlined, DstPostCall will be empty and we bail out now.
9460b57cec5SDimitry Andric 
9470b57cec5SDimitry Andric   // Store return value of operator new() for future use, until the actual
9480b57cec5SDimitry Andric   // CXXNewExpr gets processed.
9490b57cec5SDimitry Andric   ExplodedNodeSet DstPostValue;
9500b57cec5SDimitry Andric   StmtNodeBuilder ValueBldr(DstPostCall, DstPostValue, *currBldrCtx);
9515ffd83dbSDimitry Andric   for (ExplodedNode *I : DstPostCall) {
9520b57cec5SDimitry Andric     // FIXME: Because CNE serves as the "call site" for the allocator (due to
9530b57cec5SDimitry Andric     // lack of a better expression in the AST), the conjured return value symbol
9540b57cec5SDimitry Andric     // is going to be of the same type (C++ object pointer type). Technically
9550b57cec5SDimitry Andric     // this is not correct because the operator new's prototype always says that
9560b57cec5SDimitry Andric     // it returns a 'void *'. So we should change the type of the symbol,
9570b57cec5SDimitry Andric     // and then evaluate the cast over the symbolic pointer from 'void *' to
9580b57cec5SDimitry Andric     // the object pointer type. But without changing the symbol's type it
9590b57cec5SDimitry Andric     // is breaking too much to evaluate the no-op symbolic cast over it, so we
9600b57cec5SDimitry Andric     // skip it for now.
9610b57cec5SDimitry Andric     ProgramStateRef State = I->getState();
9620b57cec5SDimitry Andric     SVal RetVal = State->getSVal(CNE, LCtx);
963bdd1243dSDimitry Andric     // [basic.stc.dynamic.allocation] (on the return value of an allocation
964bdd1243dSDimitry Andric     // function):
965bdd1243dSDimitry Andric     // "The order, contiguity, and initial value of storage allocated by
966bdd1243dSDimitry Andric     // successive calls to an allocation function are unspecified."
967bdd1243dSDimitry Andric     State = State->bindDefaultInitial(RetVal, UndefinedVal{}, LCtx);
9680b57cec5SDimitry Andric 
9690b57cec5SDimitry Andric     // If this allocation function is not declared as non-throwing, failures
9700b57cec5SDimitry Andric     // /must/ be signalled by exceptions, and thus the return value will never
9710b57cec5SDimitry Andric     // be NULL. -fno-exceptions does not influence this semantics.
9720b57cec5SDimitry Andric     // FIXME: GCC has a -fcheck-new option, which forces it to consider the case
9730b57cec5SDimitry Andric     // where new can return NULL. If we end up supporting that option, we can
9740b57cec5SDimitry Andric     // consider adding a check for it here.
9750b57cec5SDimitry Andric     // C++11 [basic.stc.dynamic.allocation]p3.
9760b57cec5SDimitry Andric     if (const FunctionDecl *FD = CNE->getOperatorNew()) {
9770b57cec5SDimitry Andric       QualType Ty = FD->getType();
9780b57cec5SDimitry Andric       if (const auto *ProtoType = Ty->getAs<FunctionProtoType>())
9790b57cec5SDimitry Andric         if (!ProtoType->isNothrow())
9800b57cec5SDimitry Andric           State = State->assume(RetVal.castAs<DefinedOrUnknownSVal>(), true);
9810b57cec5SDimitry Andric     }
9820b57cec5SDimitry Andric 
9830b57cec5SDimitry Andric     ValueBldr.generateNode(
9840b57cec5SDimitry Andric         CNE, I, addObjectUnderConstruction(State, CNE, LCtx, RetVal));
9850b57cec5SDimitry Andric   }
9860b57cec5SDimitry Andric 
9870b57cec5SDimitry Andric   ExplodedNodeSet DstPostPostCallCallback;
9880b57cec5SDimitry Andric   getCheckerManager().runCheckersForPostCall(DstPostPostCallCallback,
9890b57cec5SDimitry Andric                                              DstPostValue, *Call, *this);
9905ffd83dbSDimitry Andric   for (ExplodedNode *I : DstPostPostCallCallback) {
9915ffd83dbSDimitry Andric     getCheckerManager().runCheckersForNewAllocator(*Call, Dst, I, *this);
9920b57cec5SDimitry Andric   }
9930b57cec5SDimitry Andric }
9940b57cec5SDimitry Andric 
9950b57cec5SDimitry Andric void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
9960b57cec5SDimitry Andric                                    ExplodedNodeSet &Dst) {
9970b57cec5SDimitry Andric   // FIXME: Much of this should eventually migrate to CXXAllocatorCall.
9980b57cec5SDimitry Andric   // Also, we need to decide how allocators actually work -- they're not
9990b57cec5SDimitry Andric   // really part of the CXXNewExpr because they happen BEFORE the
10000b57cec5SDimitry Andric   // CXXConstructExpr subexpression. See PR12014 for some discussion.
10010b57cec5SDimitry Andric 
10020b57cec5SDimitry Andric   unsigned blockCount = currBldrCtx->blockCount();
10030b57cec5SDimitry Andric   const LocationContext *LCtx = Pred->getLocationContext();
10040b57cec5SDimitry Andric   SVal symVal = UnknownVal();
10050b57cec5SDimitry Andric   FunctionDecl *FD = CNE->getOperatorNew();
10060b57cec5SDimitry Andric 
10070b57cec5SDimitry Andric   bool IsStandardGlobalOpNewFunction =
10080b57cec5SDimitry Andric       FD->isReplaceableGlobalAllocationFunction();
10090b57cec5SDimitry Andric 
10100b57cec5SDimitry Andric   ProgramStateRef State = Pred->getState();
10110b57cec5SDimitry Andric 
10120b57cec5SDimitry Andric   // Retrieve the stored operator new() return value.
10130b57cec5SDimitry Andric   if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
10140b57cec5SDimitry Andric     symVal = *getObjectUnderConstruction(State, CNE, LCtx);
10150b57cec5SDimitry Andric     State = finishObjectConstruction(State, CNE, LCtx);
10160b57cec5SDimitry Andric   }
10170b57cec5SDimitry Andric 
10180b57cec5SDimitry Andric   // We assume all standard global 'operator new' functions allocate memory in
10190b57cec5SDimitry Andric   // heap. We realize this is an approximation that might not correctly model
10200b57cec5SDimitry Andric   // a custom global allocator.
10210b57cec5SDimitry Andric   if (symVal.isUnknown()) {
10220b57cec5SDimitry Andric     if (IsStandardGlobalOpNewFunction)
10230b57cec5SDimitry Andric       symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount);
10240b57cec5SDimitry Andric     else
10250b57cec5SDimitry Andric       symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(),
10260b57cec5SDimitry Andric                                             blockCount);
10270b57cec5SDimitry Andric   }
10280b57cec5SDimitry Andric 
10290b57cec5SDimitry Andric   CallEventManager &CEMgr = getStateManager().getCallEventManager();
10300b57cec5SDimitry Andric   CallEventRef<CXXAllocatorCall> Call =
103106c3fb27SDimitry Andric       CEMgr.getCXXAllocatorCall(CNE, State, LCtx, getCFGElementRef());
10320b57cec5SDimitry Andric 
10330b57cec5SDimitry Andric   if (!AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
10340b57cec5SDimitry Andric     // Invalidate placement args.
10350b57cec5SDimitry Andric     // FIXME: Once we figure out how we want allocators to work,
1036a7dea167SDimitry Andric     // we should be using the usual pre-/(default-)eval-/post-call checkers
1037a7dea167SDimitry Andric     // here.
10380b57cec5SDimitry Andric     State = Call->invalidateRegions(blockCount);
10390b57cec5SDimitry Andric     if (!State)
10400b57cec5SDimitry Andric       return;
10410b57cec5SDimitry Andric 
10420b57cec5SDimitry Andric     // If this allocation function is not declared as non-throwing, failures
10430b57cec5SDimitry Andric     // /must/ be signalled by exceptions, and thus the return value will never
10440b57cec5SDimitry Andric     // be NULL. -fno-exceptions does not influence this semantics.
10450b57cec5SDimitry Andric     // FIXME: GCC has a -fcheck-new option, which forces it to consider the case
10460b57cec5SDimitry Andric     // where new can return NULL. If we end up supporting that option, we can
10470b57cec5SDimitry Andric     // consider adding a check for it here.
10480b57cec5SDimitry Andric     // C++11 [basic.stc.dynamic.allocation]p3.
104981ad6265SDimitry Andric     if (const auto *ProtoType = FD->getType()->getAs<FunctionProtoType>())
10500b57cec5SDimitry Andric       if (!ProtoType->isNothrow())
10510b57cec5SDimitry Andric         if (auto dSymVal = symVal.getAs<DefinedOrUnknownSVal>())
10520b57cec5SDimitry Andric           State = State->assume(*dSymVal, true);
10530b57cec5SDimitry Andric   }
10540b57cec5SDimitry Andric 
10550b57cec5SDimitry Andric   StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
10560b57cec5SDimitry Andric 
10570b57cec5SDimitry Andric   SVal Result = symVal;
10580b57cec5SDimitry Andric 
10590b57cec5SDimitry Andric   if (CNE->isArray()) {
1060fcaf7f86SDimitry Andric 
1061a7dea167SDimitry Andric     if (const auto *NewReg = cast_or_null<SubRegion>(symVal.getAsRegion())) {
1062fcaf7f86SDimitry Andric       // If each element is initialized by their default constructor, the field
1063fcaf7f86SDimitry Andric       // values are properly placed inside the required region, however if an
1064fcaf7f86SDimitry Andric       // initializer list is used, this doesn't happen automatically.
1065fcaf7f86SDimitry Andric       auto *Init = CNE->getInitializer();
1066972a253aSDimitry Andric       bool isInitList = isa_and_nonnull<InitListExpr>(Init);
1067fcaf7f86SDimitry Andric 
1068fcaf7f86SDimitry Andric       QualType ObjTy =
1069fcaf7f86SDimitry Andric           isInitList ? Init->getType() : CNE->getType()->getPointeeType();
10700b57cec5SDimitry Andric       const ElementRegion *EleReg =
1071fcaf7f86SDimitry Andric           MRMgr.getElementRegion(ObjTy, svalBuilder.makeArrayIndex(0), NewReg,
1072fcaf7f86SDimitry Andric                                  svalBuilder.getContext());
10730b57cec5SDimitry Andric       Result = loc::MemRegionVal(EleReg);
1074fcaf7f86SDimitry Andric 
1075fcaf7f86SDimitry Andric       // If the array is list initialized, we bind the initializer list to the
1076fcaf7f86SDimitry Andric       // memory region here, otherwise we would lose it.
1077fcaf7f86SDimitry Andric       if (isInitList) {
1078fcaf7f86SDimitry Andric         Bldr.takeNodes(Pred);
1079fcaf7f86SDimitry Andric         Pred = Bldr.generateNode(CNE, Pred, State);
1080fcaf7f86SDimitry Andric 
1081fcaf7f86SDimitry Andric         SVal V = State->getSVal(Init, LCtx);
1082fcaf7f86SDimitry Andric         ExplodedNodeSet evaluated;
1083fcaf7f86SDimitry Andric         evalBind(evaluated, CNE, Pred, Result, V, true);
1084fcaf7f86SDimitry Andric 
1085fcaf7f86SDimitry Andric         Bldr.takeNodes(Pred);
1086fcaf7f86SDimitry Andric         Bldr.addNodes(evaluated);
1087fcaf7f86SDimitry Andric 
1088fcaf7f86SDimitry Andric         Pred = *evaluated.begin();
1089fcaf7f86SDimitry Andric         State = Pred->getState();
10900b57cec5SDimitry Andric       }
1091fcaf7f86SDimitry Andric     }
1092fcaf7f86SDimitry Andric 
10930b57cec5SDimitry Andric     State = State->BindExpr(CNE, Pred->getLocationContext(), Result);
10940b57cec5SDimitry Andric     Bldr.generateNode(CNE, Pred, State);
10950b57cec5SDimitry Andric     return;
10960b57cec5SDimitry Andric   }
10970b57cec5SDimitry Andric 
10980b57cec5SDimitry Andric   // FIXME: Once we have proper support for CXXConstructExprs inside
10990b57cec5SDimitry Andric   // CXXNewExpr, we need to make sure that the constructed object is not
11000b57cec5SDimitry Andric   // immediately invalidated here. (The placement call should happen before
11010b57cec5SDimitry Andric   // the constructor call anyway.)
110281ad6265SDimitry Andric   if (FD->isReservedGlobalPlacementOperator()) {
11030b57cec5SDimitry Andric     // Non-array placement new should always return the placement location.
11040b57cec5SDimitry Andric     SVal PlacementLoc = State->getSVal(CNE->getPlacementArg(0), LCtx);
11050b57cec5SDimitry Andric     Result = svalBuilder.evalCast(PlacementLoc, CNE->getType(),
11060b57cec5SDimitry Andric                                   CNE->getPlacementArg(0)->getType());
11070b57cec5SDimitry Andric   }
11080b57cec5SDimitry Andric 
11090b57cec5SDimitry Andric   // Bind the address of the object, then check to see if we cached out.
11100b57cec5SDimitry Andric   State = State->BindExpr(CNE, LCtx, Result);
11110b57cec5SDimitry Andric   ExplodedNode *NewN = Bldr.generateNode(CNE, Pred, State);
11120b57cec5SDimitry Andric   if (!NewN)
11130b57cec5SDimitry Andric     return;
11140b57cec5SDimitry Andric 
11150b57cec5SDimitry Andric   // If the type is not a record, we won't have a CXXConstructExpr as an
11160b57cec5SDimitry Andric   // initializer. Copy the value over.
11170b57cec5SDimitry Andric   if (const Expr *Init = CNE->getInitializer()) {
11180b57cec5SDimitry Andric     if (!isa<CXXConstructExpr>(Init)) {
11190b57cec5SDimitry Andric       assert(Bldr.getResults().size() == 1);
11200b57cec5SDimitry Andric       Bldr.takeNodes(NewN);
11210b57cec5SDimitry Andric       evalBind(Dst, CNE, NewN, Result, State->getSVal(Init, LCtx),
11220b57cec5SDimitry Andric                /*FirstInit=*/IsStandardGlobalOpNewFunction);
11230b57cec5SDimitry Andric     }
11240b57cec5SDimitry Andric   }
11250b57cec5SDimitry Andric }
11260b57cec5SDimitry Andric 
11270b57cec5SDimitry Andric void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
11280b57cec5SDimitry Andric                                     ExplodedNode *Pred, ExplodedNodeSet &Dst) {
11295ffd83dbSDimitry Andric 
11305ffd83dbSDimitry Andric   CallEventManager &CEMgr = getStateManager().getCallEventManager();
11315ffd83dbSDimitry Andric   CallEventRef<CXXDeallocatorCall> Call = CEMgr.getCXXDeallocatorCall(
113206c3fb27SDimitry Andric       CDE, Pred->getState(), Pred->getLocationContext(), getCFGElementRef());
11335ffd83dbSDimitry Andric 
11345ffd83dbSDimitry Andric   ExplodedNodeSet DstPreCall;
11355ffd83dbSDimitry Andric   getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, *Call, *this);
113681ad6265SDimitry Andric   ExplodedNodeSet DstPostCall;
11375ffd83dbSDimitry Andric 
113881ad6265SDimitry Andric   if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
113981ad6265SDimitry Andric     StmtNodeBuilder Bldr(DstPreCall, DstPostCall, *currBldrCtx);
114081ad6265SDimitry Andric     for (ExplodedNode *I : DstPreCall) {
114181ad6265SDimitry Andric       defaultEvalCall(Bldr, I, *Call);
114281ad6265SDimitry Andric     }
114381ad6265SDimitry Andric   } else {
114481ad6265SDimitry Andric     DstPostCall = DstPreCall;
114581ad6265SDimitry Andric   }
114681ad6265SDimitry Andric   getCheckerManager().runCheckersForPostCall(Dst, DstPostCall, *Call, *this);
11470b57cec5SDimitry Andric }
11480b57cec5SDimitry Andric 
11495ffd83dbSDimitry Andric void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred,
11500b57cec5SDimitry Andric                                    ExplodedNodeSet &Dst) {
11510b57cec5SDimitry Andric   const VarDecl *VD = CS->getExceptionDecl();
11520b57cec5SDimitry Andric   if (!VD) {
11530b57cec5SDimitry Andric     Dst.Add(Pred);
11540b57cec5SDimitry Andric     return;
11550b57cec5SDimitry Andric   }
11560b57cec5SDimitry Andric 
11570b57cec5SDimitry Andric   const LocationContext *LCtx = Pred->getLocationContext();
11580b57cec5SDimitry Andric   SVal V = svalBuilder.conjureSymbolVal(CS, LCtx, VD->getType(),
11590b57cec5SDimitry Andric                                         currBldrCtx->blockCount());
11600b57cec5SDimitry Andric   ProgramStateRef state = Pred->getState();
11610b57cec5SDimitry Andric   state = state->bindLoc(state->getLValue(VD, LCtx), V, LCtx);
11620b57cec5SDimitry Andric 
11630b57cec5SDimitry Andric   StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
11640b57cec5SDimitry Andric   Bldr.generateNode(CS, Pred, state);
11650b57cec5SDimitry Andric }
11660b57cec5SDimitry Andric 
11670b57cec5SDimitry Andric void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
11680b57cec5SDimitry Andric                                     ExplodedNodeSet &Dst) {
11690b57cec5SDimitry Andric   StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
11700b57cec5SDimitry Andric 
11710b57cec5SDimitry Andric   // Get the this object region from StoreManager.
11720b57cec5SDimitry Andric   const LocationContext *LCtx = Pred->getLocationContext();
11730b57cec5SDimitry Andric   const MemRegion *R =
11740b57cec5SDimitry Andric     svalBuilder.getRegionManager().getCXXThisRegion(
11750b57cec5SDimitry Andric                                   getContext().getCanonicalType(TE->getType()),
11760b57cec5SDimitry Andric                                                     LCtx);
11770b57cec5SDimitry Andric 
11780b57cec5SDimitry Andric   ProgramStateRef state = Pred->getState();
11790b57cec5SDimitry Andric   SVal V = state->getSVal(loc::MemRegionVal(R));
11800b57cec5SDimitry Andric   Bldr.generateNode(TE, Pred, state->BindExpr(TE, LCtx, V));
11810b57cec5SDimitry Andric }
11820b57cec5SDimitry Andric 
11830b57cec5SDimitry Andric void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
11840b57cec5SDimitry Andric                                  ExplodedNodeSet &Dst) {
11850b57cec5SDimitry Andric   const LocationContext *LocCtxt = Pred->getLocationContext();
11860b57cec5SDimitry Andric 
11870b57cec5SDimitry Andric   // Get the region of the lambda itself.
11880b57cec5SDimitry Andric   const MemRegion *R = svalBuilder.getRegionManager().getCXXTempObjectRegion(
11890b57cec5SDimitry Andric       LE, LocCtxt);
11900b57cec5SDimitry Andric   SVal V = loc::MemRegionVal(R);
11910b57cec5SDimitry Andric 
11920b57cec5SDimitry Andric   ProgramStateRef State = Pred->getState();
11930b57cec5SDimitry Andric 
11940b57cec5SDimitry Andric   // If we created a new MemRegion for the lambda, we should explicitly bind
11950b57cec5SDimitry Andric   // the captures.
119606c3fb27SDimitry Andric   for (auto const [Idx, FieldForCapture, InitExpr] :
119706c3fb27SDimitry Andric        llvm::zip(llvm::seq<unsigned>(0, -1), LE->getLambdaClass()->fields(),
119806c3fb27SDimitry Andric                  LE->capture_inits())) {
11990b57cec5SDimitry Andric     SVal FieldLoc = State->getLValue(FieldForCapture, V);
12000b57cec5SDimitry Andric 
12010b57cec5SDimitry Andric     SVal InitVal;
12020b57cec5SDimitry Andric     if (!FieldForCapture->hasCapturedVLAType()) {
12030b57cec5SDimitry Andric       assert(InitExpr && "Capture missing initialization expression");
1204972a253aSDimitry Andric 
1205bdd1243dSDimitry Andric       // Capturing a 0 length array is a no-op, so we ignore it to get a more
1206bdd1243dSDimitry Andric       // accurate analysis. If it's not ignored, it would set the default
1207bdd1243dSDimitry Andric       // binding of the lambda to 'Unknown', which can lead to falsely detecting
1208bdd1243dSDimitry Andric       // 'Uninitialized' values as 'Unknown' and not reporting a warning.
1209bdd1243dSDimitry Andric       const auto FTy = FieldForCapture->getType();
1210bdd1243dSDimitry Andric       if (FTy->isConstantArrayType() &&
1211bdd1243dSDimitry Andric           getContext().getConstantArrayElementCount(
1212bdd1243dSDimitry Andric               getContext().getAsConstantArrayType(FTy)) == 0)
1213bdd1243dSDimitry Andric         continue;
1214bdd1243dSDimitry Andric 
1215bdd1243dSDimitry Andric       // With C++17 copy elision the InitExpr can be anything, so instead of
1216bdd1243dSDimitry Andric       // pattern matching all cases, we simple check if the current field is
1217bdd1243dSDimitry Andric       // under construction or not, regardless what it's InitExpr is.
1218bdd1243dSDimitry Andric       if (const auto OUC =
1219bdd1243dSDimitry Andric               getObjectUnderConstruction(State, {LE, Idx}, LocCtxt)) {
1220bdd1243dSDimitry Andric         InitVal = State->getSVal(OUC->getAsRegion());
1221972a253aSDimitry Andric 
1222972a253aSDimitry Andric         State = finishObjectConstruction(State, {LE, Idx}, LocCtxt);
1223972a253aSDimitry Andric       } else
12240b57cec5SDimitry Andric         InitVal = State->getSVal(InitExpr, LocCtxt);
1225972a253aSDimitry Andric 
12260b57cec5SDimitry Andric     } else {
1227972a253aSDimitry Andric 
1228972a253aSDimitry Andric       assert(!getObjectUnderConstruction(State, {LE, Idx}, LocCtxt) &&
1229972a253aSDimitry Andric              "VLA capture by value is a compile time error!");
1230972a253aSDimitry Andric 
12310b57cec5SDimitry Andric       // The field stores the length of a captured variable-length array.
12320b57cec5SDimitry Andric       // These captures don't have initialization expressions; instead we
12330b57cec5SDimitry Andric       // get the length from the VLAType size expression.
12340b57cec5SDimitry Andric       Expr *SizeExpr = FieldForCapture->getCapturedVLAType()->getSizeExpr();
12350b57cec5SDimitry Andric       InitVal = State->getSVal(SizeExpr, LocCtxt);
12360b57cec5SDimitry Andric     }
12370b57cec5SDimitry Andric 
12380b57cec5SDimitry Andric     State = State->bindLoc(FieldLoc, InitVal, LocCtxt);
12390b57cec5SDimitry Andric   }
12400b57cec5SDimitry Andric 
12410b57cec5SDimitry Andric   // Decay the Loc into an RValue, because there might be a
12420b57cec5SDimitry Andric   // MaterializeTemporaryExpr node above this one which expects the bound value
12430b57cec5SDimitry Andric   // to be an RValue.
12440b57cec5SDimitry Andric   SVal LambdaRVal = State->getSVal(R);
12450b57cec5SDimitry Andric 
12460b57cec5SDimitry Andric   ExplodedNodeSet Tmp;
12470b57cec5SDimitry Andric   StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
12480b57cec5SDimitry Andric   // FIXME: is this the right program point kind?
12490b57cec5SDimitry Andric   Bldr.generateNode(LE, Pred,
12500b57cec5SDimitry Andric                     State->BindExpr(LE, LocCtxt, LambdaRVal),
12510b57cec5SDimitry Andric                     nullptr, ProgramPoint::PostLValueKind);
12520b57cec5SDimitry Andric 
12530b57cec5SDimitry Andric   // FIXME: Move all post/pre visits to ::Visit().
12540b57cec5SDimitry Andric   getCheckerManager().runCheckersForPostStmt(Dst, Tmp, LE, *this);
12550b57cec5SDimitry Andric }
1256