Index: include/clang/Analysis/CFG.h =================================================================== --- include/clang/Analysis/CFG.h +++ include/clang/Analysis/CFG.h @@ -139,16 +139,10 @@ // necessary to express what memory is being initialized by // the construction. class ConstructionContext { - CXXConstructExpr *Constructor; - llvm::PointerUnion Trigger; - public: - ConstructionContext(CXXConstructExpr *Constructor, - Stmt *Trigger) - : Constructor(Constructor), Trigger(Trigger) {} + typedef llvm::PointerUnion TriggerTy; - ConstructionContext(CXXConstructExpr *Constructor, - CXXCtorInitializer *Trigger) + ConstructionContext(CXXConstructExpr *Constructor, TriggerTy Trigger) : Constructor(Constructor), Trigger(Trigger) {} const ConstructionContext *getPersistentCopy(BumpVectorContext &C) const { @@ -166,6 +160,10 @@ const CXXCtorInitializer *getTriggerInit() const { return Trigger.dyn_cast(); } + +private: + CXXConstructExpr *Constructor; + TriggerTy Trigger; }; /// CFGConstructor - Represents C++ constructor call. Maintains information Index: lib/Analysis/CFG.cpp =================================================================== --- lib/Analysis/CFG.cpp +++ lib/Analysis/CFG.cpp @@ -645,6 +645,11 @@ return Block; } + // Scan the child statement to find various constructors that might have been + // triggered by the given trigger. + void VisitForConstructionContext(ConstructionContext::TriggerTy Trigger, + Stmt *Child); + void autoCreateBlock() { if (!Block) Block = createBlock(); } CFGBlock *createBlock(bool add_successor = true); CFGBlock *createNoReturnBlock(); @@ -1129,6 +1134,16 @@ return nullptr; } +void CFGBuilder::VisitForConstructionContext( + ConstructionContext::TriggerTy Trigger, Stmt *Child) { + if (!Child) + return; + if (auto *Constructor = dyn_cast(Child)) + CurrentConstructionContext = ConstructionContext(Constructor, Trigger); + if (auto *Cleanups = dyn_cast(Child)) + VisitForConstructionContext(Trigger, Cleanups->getSubExpr()); +} + /// BuildCFG - Constructs a CFG from an AST (a Stmt*). The AST can represent an /// arbitrary statement. Examples include a single expression or a function /// body (compound statement). The ownership of the returned CFG is @@ -1256,8 +1271,7 @@ appendInitializer(Block, I); if (Init) { - if (CXXConstructExpr *CE = dyn_cast(Init)) - CurrentConstructionContext = {/*Constructor=*/CE, /*Trigger=*/I}; + VisitForConstructionContext(I, Init); if (HasTemporaries) { // For expression with temporaries go directly to subexpression to omit @@ -2343,8 +2357,7 @@ autoCreateBlock(); appendStmt(Block, DS); - if (auto *CE = dyn_cast_or_null(Init)) - CurrentConstructionContext = {/*Constructor=*/CE, /*Trigger=*/DS}; + VisitForConstructionContext(DS, Init); // Keep track of the last non-null block, as 'Block' can be nulled out // if the initializer expression is something like a 'while' in a @@ -3901,8 +3914,7 @@ autoCreateBlock(); appendStmt(Block, NE); - if (auto *CE = const_cast(NE->getConstructExpr())) - CurrentConstructionContext = {/*Constructor=*/CE, /*Trigger=*/NE}; + VisitForConstructionContext(NE, NE->getInitializer()); if (NE->getInitializer()) Block = Visit(NE->getInitializer()); Index: test/Analysis/temp-obj-dtors-cfg-output.cpp =================================================================== --- test/Analysis/temp-obj-dtors-cfg-output.cpp +++ test/Analysis/temp-obj-dtors-cfg-output.cpp @@ -492,7 +492,7 @@ // CHECK: 1: [B10.5] ? [B8.6] : [B9.15] // CHECK: 2: [B7.1] (ImplicitCastExpr, NoOp, const class A) // CHECK: 3: [B7.2] -// CHECK: 4: [B7.3] (CXXConstructExpr, class A) +// CHECK: 4: [B7.3] (CXXConstructExpr, [B7.5], class A) // CHECK: 5: A a = B() ? A() : A(B()); // CHECK: T: (Temp Dtor) [B9.2] // CHECK: Preds (2): B8 B9 @@ -625,7 +625,7 @@ // CHECK: 2: [B4.1] (BindTemporary) // CHECK: 3: [B4.2] (ImplicitCastExpr, NoOp, const struct C) // CHECK: 4: [B4.3] -// CHECK: 5: [B4.4] (CXXConstructExpr, struct C) +// CHECK: 5: [B4.4] (CXXConstructExpr, [B4.6], struct C) // CHECK: 6: C c = C(); // CHECK: 7: ~C() (Temporary object destructor) // CHECK: 8: c @@ -675,7 +675,7 @@ // CHECK: 1: D() (CXXConstructExpr, struct D) // CXX98: 2: [B3.1] (ImplicitCastExpr, NoOp, const struct D) // CXX98: 3: [B3.2] -// CXX98: 4: [B3.3] (CXXConstructExpr, struct D) +// CXX98: 4: [B3.3] (CXXConstructExpr, [B3.5], struct D) // CXX98: 5: D d = D(); // CXX98: 6: d // CXX98: 7: [B3.6].operator bool @@ -683,7 +683,7 @@ // CXX98: 9: [B3.8] (ImplicitCastExpr, UserDefinedConversion, _Bool) // CXX98: T: if [B3.9] // CXX11: 2: [B3.1] -// CXX11: 3: [B3.2] (CXXConstructExpr, struct D) +// CXX11: 3: [B3.2] (CXXConstructExpr, [B3.4], struct D) // CXX11: 4: D d = D(); // CXX11: 5: d // CXX11: 6: [B3.5].operator bool @@ -838,7 +838,7 @@ // CXX11: 1: [B7.3] ?: [B6.6] // CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A) // CHECK: 3: [B4.2] -// CHECK: 4: [B4.3] (CXXConstructExpr, class A) +// CHECK: 4: [B4.3] (CXXConstructExpr, [B4.5], class A) // CHECK: 5: A a = A() ?: A(); // CHECK: T: (Temp Dtor) [B6.2] // CHECK: Preds (2): B5 B6 @@ -993,7 +993,7 @@ // CHECK: 2: [B1.1] (BindTemporary) // CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A) // CHECK: 4: [B1.3] -// CHECK: 5: [B1.4] (CXXConstructExpr, class A) +// CHECK: 5: [B1.4] (CXXConstructExpr, [B1.6], class A) // CHECK: 6: A a = A(); // CHECK: 7: ~A() (Temporary object destructor) // CHECK: 8: int b; @@ -1033,7 +1033,7 @@ // CHECK: 4: [B1.3] (BindTemporary) // CHECK: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A) // CHECK: 6: [B1.5] -// CHECK: 7: [B1.6] (CXXConstructExpr, class A) +// CHECK: 7: [B1.6] (CXXConstructExpr, [B1.8], class A) // CHECK: 8: A a = A::make(); // CHECK: 9: ~A() (Temporary object destructor) // CHECK: 10: int b;