[CFG] NFC: Refactor ConstructionContext into a finite set of cases.

ConstructionContext is moved into a separate translation unit and is separated
into multiple classes. The "old" "raw" ConstructionContext is renamed into
ConstructionContextLayer - which corresponds to the idea of building the context
gradually layer-by-layer, but it isn't easy to use in the clients. Once
CXXConstructExpr is reached, layers that we've gathered so far are transformed
into the actual, "new-style" "flat" ConstructionContext, which is put into the
CFGConstructor element and has no layers whatsoever (until it actually needs
them, eg. aggregate initialization). The new-style ConstructionContext is
instead presented as a variety of sub-classes that enumerate different ways of
constructing an object in C++. There are 5 of these supported for now,
which is around a half of what needs to be supported.

The layer-by-layer buildup process is still a little bit weird, but it hides
all the weirdness in one place, that sounds like a good thing.

Differential Revision: https://reviews.llvm.org/D43533

llvm-svn: 326238
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 1cf7063..727c304 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -29,6 +29,7 @@
 #include "clang/AST/StmtVisitor.h"
 #include "clang/AST/Type.h"
 #include "clang/Analysis/Support/BumpVector.h"
+#include "clang/Analysis/ConstructionContext.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/ExceptionSpecificationType.h"
 #include "clang/Basic/LLVM.h"
@@ -475,7 +476,7 @@
   // Information about the currently visited C++ object construction site.
   // This is set in the construction trigger and read when the constructor
   // itself is being visited.
-  llvm::DenseMap<CXXConstructExpr *, const ConstructionContext *>
+  llvm::DenseMap<CXXConstructExpr *, const ConstructionContextLayer *>
       ConstructionContextMap;
 
   bool badCFG = false;
@@ -652,18 +653,19 @@
     return Block;
   }
 
-  // Remember to apply \p CC when constructing the CFG element for \p CE.
-  void consumeConstructionContext(const ConstructionContext *CC,
+  // Remember to apply the construction context based on the current \p Layer
+  // when constructing the CFG element for \p CE.
+  void consumeConstructionContext(const ConstructionContextLayer *Layer,
                                   CXXConstructExpr *CE);
 
-  // Scan the child statement \p Child to find the constructor that might
-  // have been directly triggered by the current node, \p Trigger. If such
-  // constructor has been found, set current construction context to point
-  // to the trigger statement. The construction context will be unset once
-  // it is consumed when the CFG building procedure processes the
-  // construct-expression and adds the respective CFGConstructor element.
-  void findConstructionContexts(const ConstructionContext *ContextSoFar,
+  // Scan \p Child statement to find constructors in it, while keeping in mind
+  // that its parent statement is providing a partial construction context
+  // described by \p Layer. If a constructor is found, it would be assigned
+  // the context based on the layer. If an additional construction context layer
+  // is found, the function recurses into that.
+  void findConstructionContexts(const ConstructionContextLayer *Layer,
                                 Stmt *Child);
+
   // Unset the construction context after consuming it. This is done immediately
   // after adding the CFGConstructor element, so there's no need to
   // do this manually in every Visit... function.
@@ -710,7 +712,11 @@
 
   void appendConstructor(CFGBlock *B, CXXConstructExpr *CE) {
     if (BuildOpts.AddRichCXXConstructors) {
-      if (const ConstructionContext *CC = ConstructionContextMap.lookup(CE)) {
+      if (const ConstructionContextLayer *Layer =
+              ConstructionContextMap.lookup(CE)) {
+        const ConstructionContext *CC =
+            ConstructionContext::createFromLayers(cfg->getBumpVectorContext(),
+                                                  Layer);
         B->appendConstructor(CE, CC, cfg->getBumpVectorContext());
         cleanupConstructionContext(CE);
         return;
@@ -1155,20 +1161,21 @@
   return nullptr;
 }
 
-void CFGBuilder::consumeConstructionContext(const ConstructionContext *CC, CXXConstructExpr *CE) {
-  if (const ConstructionContext *PreviousContext =
+void CFGBuilder::consumeConstructionContext(
+    const ConstructionContextLayer *Layer, CXXConstructExpr *CE) {
+  if (const ConstructionContextLayer *PreviouslyStoredLayer =
           ConstructionContextMap.lookup(CE)) {
     // We might have visited this child when we were finding construction
     // contexts within its parents.
-    assert(PreviousContext->isStrictlyMoreSpecificThan(CC) &&
+    assert(PreviouslyStoredLayer->isStrictlyMoreSpecificThan(Layer) &&
            "Already within a different construction context!");
   } else {
-    ConstructionContextMap[CE] = CC;
+    ConstructionContextMap[CE] = Layer;
   }
 }
 
 void CFGBuilder::findConstructionContexts(
-    const ConstructionContext *ContextSoFar, Stmt *Child) {
+    const ConstructionContextLayer *Layer, Stmt *Child) {
   if (!BuildOpts.AddRichCXXConstructors)
     return;
 
@@ -1178,36 +1185,36 @@
   switch(Child->getStmtClass()) {
   case Stmt::CXXConstructExprClass:
   case Stmt::CXXTemporaryObjectExprClass: {
-    consumeConstructionContext(ContextSoFar, cast<CXXConstructExpr>(Child));
+    consumeConstructionContext(Layer, cast<CXXConstructExpr>(Child));
     break;
   }
   case Stmt::ExprWithCleanupsClass: {
     auto *Cleanups = cast<ExprWithCleanups>(Child);
-    findConstructionContexts(ContextSoFar, Cleanups->getSubExpr());
+    findConstructionContexts(Layer, Cleanups->getSubExpr());
     break;
   }
   case Stmt::CXXFunctionalCastExprClass: {
     auto *Cast = cast<CXXFunctionalCastExpr>(Child);
-    findConstructionContexts(ContextSoFar, Cast->getSubExpr());
+    findConstructionContexts(Layer, Cast->getSubExpr());
     break;
   }
   case Stmt::ImplicitCastExprClass: {
     auto *Cast = cast<ImplicitCastExpr>(Child);
-    findConstructionContexts(ContextSoFar, Cast->getSubExpr());
+    findConstructionContexts(Layer, Cast->getSubExpr());
     break;
   }
   case Stmt::CXXBindTemporaryExprClass: {
     auto *BTE = cast<CXXBindTemporaryExpr>(Child);
     findConstructionContexts(
-        ConstructionContext::create(cfg->getBumpVectorContext(), BTE,
-                                    ContextSoFar),
+        ConstructionContextLayer::create(cfg->getBumpVectorContext(),
+                                         BTE, Layer),
         BTE->getSubExpr());
     break;
   }
   case Stmt::ConditionalOperatorClass: {
     auto *CO = cast<ConditionalOperator>(Child);
-    findConstructionContexts(ContextSoFar, CO->getLHS());
-    findConstructionContexts(ContextSoFar, CO->getRHS());
+    findConstructionContexts(Layer, CO->getLHS());
+    findConstructionContexts(Layer, CO->getRHS());
     break;
   }
   default:
@@ -1356,7 +1363,7 @@
 
   if (Init) {
     findConstructionContexts(
-        ConstructionContext::create(cfg->getBumpVectorContext(), I),
+        ConstructionContextLayer::create(cfg->getBumpVectorContext(), I),
         Init);
 
     if (HasTemporaries) {
@@ -2448,7 +2455,7 @@
   appendStmt(Block, DS);
 
   findConstructionContexts(
-      ConstructionContext::create(cfg->getBumpVectorContext(), DS),
+      ConstructionContextLayer::create(cfg->getBumpVectorContext(), DS),
       Init);
 
   // Keep track of the last non-null block, as 'Block' can be nulled out
@@ -2642,7 +2649,7 @@
   addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), R);
 
   findConstructionContexts(
-      ConstructionContext::create(cfg->getBumpVectorContext(), R),
+      ConstructionContextLayer::create(cfg->getBumpVectorContext(), R),
       R->getRetValue());
 
   // If the one of the destructors does not return, we already have the Exit
@@ -3015,7 +3022,7 @@
 CFGBuilder::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
                                           AddStmtChoice asc) {
   findConstructionContexts(
-      ConstructionContext::create(cfg->getBumpVectorContext(), MTE),
+      ConstructionContextLayer::create(cfg->getBumpVectorContext(), MTE),
       MTE->getTemporary());
 
   return VisitStmt(MTE, asc);
@@ -4002,7 +4009,7 @@
     appendStmt(Block, E);
 
     findConstructionContexts(
-        ConstructionContext::create(cfg->getBumpVectorContext(), E),
+        ConstructionContextLayer::create(cfg->getBumpVectorContext(), E),
         E->getSubExpr());
 
     // We do not want to propagate the AlwaysAdd property.
@@ -4025,7 +4032,7 @@
   appendStmt(Block, NE);
 
   findConstructionContexts(
-      ConstructionContext::create(cfg->getBumpVectorContext(), NE),
+      ConstructionContextLayer::create(cfg->getBumpVectorContext(), NE),
       const_cast<CXXConstructExpr *>(NE->getConstructExpr()));
 
   if (NE->getInitializer())
@@ -4752,19 +4759,44 @@
     } else if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(S)) {
       OS << " (CXXConstructExpr, ";
       if (Optional<CFGConstructor> CE = E.getAs<CFGConstructor>()) {
-        // TODO: Refactor into ConstructionContext::print().
-        if (const Stmt *S = CE->getTriggerStmt())
-          Helper.handledStmt(const_cast<Stmt *>(S), OS);
-        else if (const CXXCtorInitializer *I = CE->getTriggerInit())
-          print_initializer(OS, Helper, I);
-        else
-          llvm_unreachable("Unexpected trigger kind!");
-        OS << ", ";
-        if (const Stmt *S = CE->getMaterializedTemporary()) {
-          if (S != CE->getTriggerStmt()) {
-            Helper.handledStmt(const_cast<Stmt *>(S), OS);
-            OS << ", ";
-          }
+        const ConstructionContext *CC = CE->getConstructionContext();
+        const Stmt *S1 = nullptr, *S2 = nullptr;
+        switch (CC->getKind()) {
+        case ConstructionContext::ConstructorInitializerKind: {
+          const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
+          print_initializer(OS, Helper, ICC->getCXXCtorInitializer());
+          OS << ", ";
+          break;
+        }
+        case ConstructionContext::SimpleVariableKind: {
+          const auto *DSCC = cast<SimpleVariableConstructionContext>(CC);
+          S1 = DSCC->getDeclStmt();
+          break;
+        }
+        case ConstructionContext::NewAllocatedObjectKind: {
+          const auto *NECC = cast<NewAllocatedObjectConstructionContext>(CC);
+          S1 = NECC->getCXXNewExpr();
+          break;
+        }
+        case ConstructionContext::ReturnedValueKind: {
+          const auto *RSCC = cast<ReturnedValueConstructionContext>(CC);
+          S1 = RSCC->getReturnStmt();
+          break;
+        }
+        case ConstructionContext::TemporaryObjectKind: {
+          const auto *TOCC = cast<TemporaryObjectConstructionContext>(CC);
+          S1 = TOCC->getCXXBindTemporaryExpr();
+          S2 = TOCC->getMaterializedTemporaryExpr();
+          break;
+        }
+        }
+        if (S1) {
+          Helper.handledStmt(const_cast<Stmt *>(S1), OS);
+          OS << ", ";
+        }
+        if (S2) {
+          Helper.handledStmt(const_cast<Stmt *>(S2), OS);
+          OS << ", ";
         }
       }
       OS << CCE->getType().getAsString() << ")";
diff --git a/clang/lib/Analysis/CMakeLists.txt b/clang/lib/Analysis/CMakeLists.txt
index fdc9e6c..432067d 100644
--- a/clang/lib/Analysis/CMakeLists.txt
+++ b/clang/lib/Analysis/CMakeLists.txt
@@ -11,6 +11,7 @@
   CallGraph.cpp
   CloneDetection.cpp
   CocoaConventions.cpp
+  ConstructionContext.cpp
   Consumed.cpp
   CodeInjector.cpp
   Dominators.cpp
diff --git a/clang/lib/Analysis/ConstructionContext.cpp b/clang/lib/Analysis/ConstructionContext.cpp
new file mode 100644
index 0000000..aea329b
--- /dev/null
+++ b/clang/lib/Analysis/ConstructionContext.cpp
@@ -0,0 +1,92 @@
+//===- ConstructionContext.cpp - CFG constructor information --------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ConstructionContext class and its sub-classes,
+// which represent various different ways of constructing C++ objects
+// with the additional information the users may want to know about
+// the constructor.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/ConstructionContext.h"
+
+using namespace clang;
+
+const ConstructionContextLayer *
+ConstructionContextLayer::create(BumpVectorContext &C, TriggerTy Trigger,
+                                 const ConstructionContextLayer *Parent) {
+  ConstructionContextLayer *CC =
+      C.getAllocator().Allocate<ConstructionContextLayer>();
+  return new (CC) ConstructionContextLayer(Trigger, Parent);
+}
+
+bool ConstructionContextLayer::isStrictlyMoreSpecificThan(
+    const ConstructionContextLayer *Other) const {
+  const ConstructionContextLayer *Self = this;
+  while (true) {
+    if (!Other)
+      return Self;
+    if (!Self || !Self->isSameLayer(Other))
+      return false;
+    Self = Self->getParent();
+    Other = Other->getParent();
+  }
+  llvm_unreachable("The above loop can only be terminated via return!");
+}
+
+const ConstructionContext *ConstructionContext::createFromLayers(
+    BumpVectorContext &C, const ConstructionContextLayer *TopLayer) {
+  // Before this point all we've had was a stockpile of arbitrary layers.
+  // Now validate that it is shaped as one of the finite amount of expected
+  // patterns.
+  if (const Stmt *S = TopLayer->getTriggerStmt()) {
+    if (const auto *DS = dyn_cast<DeclStmt>(S)) {
+      assert(TopLayer->isLast());
+      auto *CC =
+          C.getAllocator().Allocate<SimpleVariableConstructionContext>();
+      return new (CC) SimpleVariableConstructionContext(DS);
+    } else if (const auto *NE = dyn_cast<CXXNewExpr>(S)) {
+      assert(TopLayer->isLast());
+      auto *CC =
+          C.getAllocator().Allocate<NewAllocatedObjectConstructionContext>();
+      return new (CC) NewAllocatedObjectConstructionContext(NE);
+    } else if (const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(S)) {
+      const MaterializeTemporaryExpr *MTE = nullptr;
+      assert(BTE->getType().getCanonicalType()
+                ->getAsCXXRecordDecl()->hasNonTrivialDestructor());
+      // For temporaries with destructors, there may or may not be
+      // lifetime extension on the parent layer.
+      if (const ConstructionContextLayer *ParentLayer = TopLayer->getParent()) {
+        assert(ParentLayer->isLast());
+        MTE = cast<MaterializeTemporaryExpr>(ParentLayer->getTriggerStmt());
+      }
+      auto *CC =
+          C.getAllocator().Allocate<TemporaryObjectConstructionContext>();
+      return new (CC) TemporaryObjectConstructionContext(BTE, MTE);
+    } else if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(S)) {
+      assert(MTE->getType().getCanonicalType()
+                ->getAsCXXRecordDecl()->hasTrivialDestructor());
+      assert(TopLayer->isLast());
+      auto *CC =
+          C.getAllocator().Allocate<TemporaryObjectConstructionContext>();
+      return new (CC) TemporaryObjectConstructionContext(nullptr, MTE);
+    } else if (const auto *RS = dyn_cast<ReturnStmt>(S)) {
+      assert(TopLayer->isLast());
+      auto *CC =
+          C.getAllocator().Allocate<ReturnedValueConstructionContext>();
+      return new (CC) ReturnedValueConstructionContext(RS);
+    }
+  } else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) {
+    assert(TopLayer->isLast());
+    auto *CC =
+        C.getAllocator().Allocate<ConstructorInitializerConstructionContext>();
+    return new (CC) ConstructorInitializerConstructionContext(I);
+  }
+  llvm_unreachable("Unexpected construction context!");
+}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 2c1e858..14b4569 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/Analysis/ConstructionContext.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/ParentMap.h"
@@ -111,47 +112,20 @@
   // See if we're constructing an existing region by looking at the
   // current construction context.
   if (CC) {
-    if (const Stmt *TriggerStmt = CC->getTriggerStmt()) {
-      if (const CXXNewExpr *CNE = dyn_cast<CXXNewExpr>(TriggerStmt)) {
-        if (AMgr.getAnalyzerOptions().mayInlineCXXAllocator()) {
-          // TODO: Detect when the allocator returns a null pointer.
-          // Constructor shall not be called in this case.
-          if (const SubRegion *MR = dyn_cast_or_null<SubRegion>(
-                  getCXXNewAllocatorValue(State, CNE, LCtx).getAsRegion())) {
-            if (CNE->isArray()) {
-              // TODO: In fact, we need to call the constructor for every
-              // allocated element, not just the first one!
-              CallOpts.IsArrayCtorOrDtor = true;
-              return getStoreManager().GetElementZeroRegion(
-                  MR, CNE->getType()->getPointeeType());
-            }
-            return MR;
-          }
-        }
-      } else if (auto *DS = dyn_cast<DeclStmt>(TriggerStmt)) {
-        const auto *Var = cast<VarDecl>(DS->getSingleDecl());
-        SVal LValue = State->getLValue(Var, LCtx);
-        QualType Ty = Var->getType();
-        LValue = makeZeroElementRegion(State, LValue, Ty,
-                                       CallOpts.IsArrayCtorOrDtor);
-        return LValue.getAsRegion();
-      } else if (isa<ReturnStmt>(TriggerStmt)) {
-        // TODO: We should construct into a CXXBindTemporaryExpr or a
-        // MaterializeTemporaryExpr around the call-expression on the previous
-        // stack frame. Currently we re-bind the temporary to the correct region
-        // later, but that's not semantically correct. This of course does not
-        // apply when we're in the top frame. But if we are in an inlined
-        // function, we should be able to take the call-site CFG element,
-        // and it should contain (but right now it wouldn't) some sort of
-        // construction context that'd give us the right temporary expression.
-        CallOpts.IsTemporaryCtorOrDtor = true;
-        return MRMgr.getCXXTempObjectRegion(CE, LCtx);
-      } else if (isa<CXXBindTemporaryExpr>(TriggerStmt)) {
-        CallOpts.IsTemporaryCtorOrDtor = true;
-        return MRMgr.getCXXTempObjectRegion(CE, LCtx);
-      }
-      // TODO: Consider other directly initialized elements.
-    } else if (const CXXCtorInitializer *Init = CC->getTriggerInit()) {
+    switch (CC->getKind()) {
+    case ConstructionContext::SimpleVariableKind: {
+      const auto *DSCC = cast<SimpleVariableConstructionContext>(CC);
+      const auto *DS = DSCC->getDeclStmt();
+      const auto *Var = cast<VarDecl>(DS->getSingleDecl());
+      SVal LValue = State->getLValue(Var, LCtx);
+      QualType Ty = Var->getType();
+      LValue =
+          makeZeroElementRegion(State, LValue, Ty, CallOpts.IsArrayCtorOrDtor);
+      return LValue.getAsRegion();
+    }
+    case ConstructionContext::ConstructorInitializerKind: {
+      const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
+      const auto *Init = ICC->getCXXCtorInitializer();
       assert(Init->isAnyMemberInitializer());
       const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
       Loc ThisPtr =
@@ -173,10 +147,45 @@
                                        CallOpts.IsArrayCtorOrDtor);
       return FieldVal.getAsRegion();
     }
-
-    // FIXME: This will eventually need to handle new-expressions as well.
-    // Don't forget to update the pre-constructor initialization code in
-    // ExprEngine::VisitCXXConstructExpr.
+    case ConstructionContext::NewAllocatedObjectKind: {
+      if (AMgr.getAnalyzerOptions().mayInlineCXXAllocator()) {
+        const auto *NECC = cast<NewAllocatedObjectConstructionContext>(CC);
+        const auto *NE = NECC->getCXXNewExpr();
+        // TODO: Detect when the allocator returns a null pointer.
+        // Constructor shall not be called in this case.
+        if (const SubRegion *MR = dyn_cast_or_null<SubRegion>(
+                getCXXNewAllocatorValue(State, NE, LCtx).getAsRegion())) {
+          if (NE->isArray()) {
+            // TODO: In fact, we need to call the constructor for every
+            // allocated element, not just the first one!
+            CallOpts.IsArrayCtorOrDtor = true;
+            return getStoreManager().GetElementZeroRegion(
+                MR, NE->getType()->getPointeeType());
+          }
+          return MR;
+        }
+      }
+      break;
+    }
+    case ConstructionContext::TemporaryObjectKind: {
+      // TODO: Support temporaries lifetime-extended via static references.
+      // They'd need a getCXXStaticTempObjectRegion().
+      CallOpts.IsTemporaryCtorOrDtor = true;
+      return MRMgr.getCXXTempObjectRegion(CE, LCtx);
+    }
+    case ConstructionContext::ReturnedValueKind: {
+      // TODO: We should construct into a CXXBindTemporaryExpr or a
+      // MaterializeTemporaryExpr around the call-expression on the previous
+      // stack frame. Currently we re-bind the temporary to the correct region
+      // later, but that's not semantically correct. This of course does not
+      // apply when we're in the top frame. But if we are in an inlined
+      // function, we should be able to take the call-site CFG element,
+      // and it should contain (but right now it wouldn't) some sort of
+      // construction context that'd give us the right temporary expression.
+      CallOpts.IsTemporaryCtorOrDtor = true;
+      return MRMgr.getCXXTempObjectRegion(CE, LCtx);
+    }
+    }
   }
   // If we couldn't find an existing region to construct into, assume we're
   // constructing a temporary. Notify the caller of our failure.
@@ -227,6 +236,7 @@
 
   EvalCallOptions CallOpts;
   auto C = getCurrentCFGElement().getAs<CFGConstructor>();
+  assert(C || getCurrentCFGElement().getAs<CFGStmt>());
   const ConstructionContext *CC = C ? C->getConstructionContext() : nullptr;
 
   const CXXBindTemporaryExpr *BTE = nullptr;
@@ -235,15 +245,27 @@
   switch (CE->getConstructionKind()) {
   case CXXConstructExpr::CK_Complete: {
     Target = getRegionForConstructedObject(CE, Pred, CC, CallOpts);
-    if (CC && AMgr.getAnalyzerOptions().includeTemporaryDtorsInCFG() &&
-        !CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion &&
-        CallOpts.IsTemporaryCtorOrDtor) {
-      MTE = CC->getMaterializedTemporary();
-      if (!MTE || MTE->getStorageDuration() == SD_FullExpression) {
-        // If the temporary is lifetime-extended, don't save the BTE,
-        // because we don't need a temporary destructor, but an automatic
-        // destructor. The cast may fail because it may as well be a ReturnStmt.
-        BTE = dyn_cast<CXXBindTemporaryExpr>(CC->getTriggerStmt());
+
+    // In case of temporary object construction, extract data necessary for
+    // destruction and lifetime extension.
+    if (const auto *TCC =
+            dyn_cast_or_null<TemporaryObjectConstructionContext>(CC)) {
+      assert(CallOpts.IsTemporaryCtorOrDtor);
+      assert(!CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion);
+      if (AMgr.getAnalyzerOptions().includeTemporaryDtorsInCFG()) {
+        BTE = TCC->getCXXBindTemporaryExpr();
+        MTE = TCC->getMaterializedTemporaryExpr();
+        if (!BTE) {
+          // FIXME: lifetime extension for temporaries without destructors
+          // is not implemented yet.
+          MTE = nullptr;
+        }
+        if (MTE && MTE->getStorageDuration() != SD_FullExpression) {
+          // If the temporary is lifetime-extended, don't save the BTE,
+          // because we don't need a temporary destructor, but an automatic
+          // destructor.
+          BTE = nullptr;
+        }
       }
     }
     break;
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 0a41205..4838a8f 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -16,6 +16,7 @@
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/ConstructionContext.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "llvm/ADT/SmallSet.h"
@@ -635,10 +636,11 @@
 
     const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr();
 
-    auto CC = getCurrentCFGElement().getAs<CFGConstructor>();
-    const Stmt *ParentExpr = CC ? CC->getTriggerStmt() : nullptr;
+    auto CCE = getCurrentCFGElement().getAs<CFGConstructor>();
+    const ConstructionContext *CC = CCE ? CCE->getConstructionContext()
+                                        : nullptr;
 
-    if (ParentExpr && isa<CXXNewExpr>(ParentExpr) &&
+    if (CC && isa<NewAllocatedObjectConstructionContext>(CC) &&
         !Opts.mayInlineCXXAllocator())
       return CIP_DisallowedOnce;