Index: include/clang/Analysis/CFG.h =================================================================== --- include/clang/Analysis/CFG.h +++ include/clang/Analysis/CFG.h @@ -193,6 +193,17 @@ return Trigger.dyn_cast(); } + const MaterializeTemporaryExpr *getMaterializedTemporary() const { + // TODO: Be more careful to ensure that there's only one MTE around. + for (const ConstructionContext *CC = this; CC; CC = CC->getParent()) { + if (const auto *MTE = dyn_cast_or_null( + CC->getTriggerStmt())) { + return MTE; + } + } + return nullptr; + } + bool isSameAsPartialContext(const ConstructionContext *Other) const { assert(Other); return (Trigger == Other->Trigger); @@ -248,6 +259,10 @@ return getConstructionContext()->getTriggerInit(); } + const MaterializeTemporaryExpr *getMaterializedTemporary() const { + return getConstructionContext()->getMaterializedTemporary(); + } + private: friend class CFGElement; Index: lib/Analysis/CFG.cpp =================================================================== --- lib/Analysis/CFG.cpp +++ lib/Analysis/CFG.cpp @@ -547,6 +547,8 @@ Stmt *Term, CFGBlock *TrueBlock, CFGBlock *FalseBlock); + CFGBlock *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE, + AddStmtChoice asc); CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc); CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S); CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S); @@ -1831,6 +1833,10 @@ case Stmt::LambdaExprClass: return VisitLambdaExpr(cast(S), asc); + case Stmt::MaterializeTemporaryExprClass: + return VisitMaterializeTemporaryExpr(cast(S), + asc); + case Stmt::MemberExprClass: return VisitMemberExpr(cast(S), asc); @@ -2966,6 +2972,16 @@ return EntryConditionBlock; } +CFGBlock * +CFGBuilder::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE, + AddStmtChoice asc) { + findConstructionContexts( + ConstructionContext::create(cfg->getBumpVectorContext(), MTE), + MTE->getTemporary()); + + return VisitStmt(MTE, asc); +} + CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) { if (asc.alwaysAdd(*this, M)) { autoCreateBlock(); @@ -4697,13 +4713,20 @@ } else if (const CXXConstructExpr *CCE = dyn_cast(S)) { OS << " (CXXConstructExpr, "; if (Optional CE = E.getAs()) { + // TODO: Refactor into ConstructionContext::print(). if (const Stmt *S = CE->getTriggerStmt()) - Helper.handledStmt((const_cast(S)), OS); + Helper.handledStmt(const_cast(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(S), OS); + OS << ", "; + } + } } OS << CCE->getType().getAsString() << ")"; } else if (const CastExpr *CE = dyn_cast(S)) { Index: test/Analysis/cfg-rich-constructors.cpp =================================================================== --- test/Analysis/cfg-rich-constructors.cpp +++ test/Analysis/cfg-rich-constructors.cpp @@ -133,11 +133,10 @@ C c = coin ? C::get() : C(0); } -// TODO: Should find construction target here. // CHECK: void referenceVariableWithConstructor() // CHECK: 1: 0 // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *) -// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, const class C) +// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], const class C) // CHECK-NEXT: 4: [B1.3] // CHECK-NEXT: 5: const C &c(0); void referenceVariableWithConstructor() { @@ -267,9 +266,8 @@ return {123, 456}; } -// TODO: Should find construction targets for the first constructor as well. // CHECK: C returnTemporary() -// CHECK: 1: C() (CXXConstructExpr, class C) +// CHECK: 1: C() (CXXConstructExpr, [B1.2], class C) // CHECK-NEXT: 2: [B1.1] // CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], class C) // CHECK-NEXT: 4: return [B1.3]; @@ -400,7 +398,7 @@ // CHECK: void referenceVariableWithConstructor() // CHECK: 1: 0 -// CHECK-NEXT: 2: [B1.1] (CXXConstructExpr, [B1.3], const class temporary_object_expr_with_dtors::D) +// CHECK-NEXT: 2: [B1.1] (CXXConstructExpr, [B1.3], [B1.4], const class temporary_object_expr_with_dtors::D) // CHECK-NEXT: 3: [B1.2] (BindTemporary) // CHECK-NEXT: 4: [B1.3] // CHECK-NEXT: 5: const temporary_object_expr_with_dtors::D &d(0); 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 @@ -714,7 +714,9 @@ // CHECK: Preds (1): B3 // CHECK: Succs (1): B0 // CHECK: [B3] -// CHECK: 1: D() (CXXConstructExpr, struct D) +// WARNINGS: 1: D() (CXXConstructExpr, struct D) +// CXX98-ANALYZER: 1: D() (CXXConstructExpr, struct D) +// CXX11-ANALYZER: 1: D() (CXXConstructExpr, [B3.2], struct D) // CXX98: 2: [B3.1] (ImplicitCastExpr, NoOp, const struct D) // CXX98: 3: [B3.2] // CXX98-WARNINGS: 4: [B3.3] (CXXConstructExpr, struct D) @@ -925,7 +927,8 @@ // CHECK: Succs (1): B4 // CHECK: [B7] // WARNINGS: 1: A() (CXXConstructExpr, class A) -// ANALYZER: 1: A() (CXXConstructExpr, [B7.2], class A) +// ANALYZER-CXX98: 1: A() (CXXConstructExpr, [B7.2], [B7.3], class A) +// ANALYZER-CXX11: 1: A() (CXXConstructExpr, [B7.2], class A) // CHECK: 2: [B7.1] (BindTemporary) // CXX98: 3: [B7.2].operator bool // CXX98: 4: [B7.2] @@ -992,7 +995,8 @@ // CHECK: 1: foo // CHECK: 2: [B7.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &)) // WARNINGS: 3: A() (CXXConstructExpr, class A) -// ANALYZER: 3: A() (CXXConstructExpr, [B7.4], class A) +// ANALYZER-CXX98: 3: A() (CXXConstructExpr, [B7.4], class A) +// ANALYZER-CXX11: 3: A() (CXXConstructExpr, class A) // CHECK: 4: [B7.3] (BindTemporary) // CXX98: 5: [B7.4].operator bool // CXX98: 6: [B7.4] @@ -1043,7 +1047,8 @@ // CHECK: Succs (1): B9 // CHECK: [B12] // WARNINGS: 1: A() (CXXConstructExpr, class A) -// ANALYZER: 1: A() (CXXConstructExpr, [B12.2], class A) +// ANALYZER-CXX98: 1: A() (CXXConstructExpr, [B12.2], [B12.3], class A) +// ANALYZER-CXX11: 1: A() (CXXConstructExpr, [B12.2], class A) // CHECK: 2: [B12.1] (BindTemporary) // CXX98: 3: [B12.2].operator bool // CXX98: 4: [B12.2] @@ -1199,7 +1204,8 @@ // CHECK: [B2 (NORETURN)] // CHECK: 1: int a; // WARNINGS: 2: NoReturn() (CXXConstructExpr, class NoReturn) -// ANALYZER: 2: NoReturn() (CXXConstructExpr, [B2.3], class NoReturn) +// ANALYZER-CXX98: 2: NoReturn() (CXXConstructExpr, [B2.3], [B2.4], class NoReturn) +// ANALYZER-CXX11: 2: NoReturn() (CXXConstructExpr, [B2.3], class NoReturn) // CHECK: 3: [B2.2] (BindTemporary) // CHECK: [[MEMBER:[45]]]: [B2.{{[34]}}].f // CHECK: {{[56]}}: [B2.[[MEMBER]]]()