Index: cfe/trunk/lib/Analysis/CFG.cpp =================================================================== --- cfe/trunk/lib/Analysis/CFG.cpp +++ cfe/trunk/lib/Analysis/CFG.cpp @@ -1158,6 +1158,8 @@ assert(CurrentConstructionContext.isNull() && "Already within a construction context!"); CurrentConstructionContext = ConstructionContext(Trigger); + } else if (auto *Cleanups = dyn_cast(Child)) { + EnterConstructionContextIfNecessary(Trigger, Cleanups->getSubExpr()); } } Index: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp =================================================================== --- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp +++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp @@ -92,18 +92,45 @@ C c{new C()}; } -// TODO: Should find construction target here. // CHECK: void simpleVariableInitializedByValue() // CHECK: 1: C::get // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) // CHECK-NEXT: 3: [B1.2]() // CHECK-NEXT: 4: [B1.3] -// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, class C) +// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], class C) // CHECK-NEXT: 6: C c = C::get(); void simpleVariableInitializedByValue() { C c = C::get(); } +// TODO: Should find construction target for the three temporaries as well. +// CHECK: void simpleVariableWithTernaryOperator(bool coin) +// CHECK: [B1] +// CHECK-NEXT: 1: [B4.2] ? [B2.5] : [B3.6] +// CHECK-NEXT: 2: [B1.1] +// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], class C) +// CHECK-NEXT: 4: C c = coin ? C::get() : C(0); +// CHECK: [B2] +// CHECK-NEXT: 1: C::get +// CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) +// CHECK-NEXT: 3: [B2.2]() +// CHECK-NEXT: 4: [B2.3] +// CHECK-NEXT: 5: [B2.4] (CXXConstructExpr, class C) +// CHECK: [B3] +// CHECK-NEXT: 1: 0 +// CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *) +// CHECK-NEXT: 3: [B3.2] (CXXConstructExpr, class C) +// CHECK-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) +// CHECK-NEXT: 5: [B3.4] +// CHECK-NEXT: 6: [B3.5] (CXXConstructExpr, class C) +// CHECK: [B4] +// CHECK-NEXT: 1: coin +// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: [B4.2] ? ... : ... +void simpleVariableWithTernaryOperator(bool coin) { + C c = coin ? C::get() : C(0); +} + // TODO: Should find construction target here. // CHECK: void referenceVariableWithConstructor() // CHECK: 1: 0 @@ -125,6 +152,34 @@ const C &c = C(); } +// TODO: Should find construction targets here. +// CHECK: void referenceVariableWithTernaryOperator(bool coin) +// CHECK: [B1] +// CHECK-NEXT: 1: [B4.2] ? [B2.5] : [B3.6] +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NoOp, const class C) +// CHECK-NEXT: 3: [B1.2] +// CHECK-NEXT: 4: const C &c = coin ? C::get() : C(0); +// CHECK: [B2] +// CHECK-NEXT: 1: C::get +// CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) +// CHECK-NEXT: 3: [B2.2]() +// CHECK-NEXT: 4: [B2.3] +// CHECK-NEXT: 5: [B2.4] (CXXConstructExpr, class C) +// CHECK: [B3] +// CHECK-NEXT: 1: 0 +// CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *) +// CHECK-NEXT: 3: [B3.2] (CXXConstructExpr, class C) +// CHECK-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) +// CHECK-NEXT: 5: [B3.4] +// CHECK-NEXT: 6: [B3.5] (CXXConstructExpr, class C) +// CHECK: [B4] +// CHECK-NEXT: 1: coin +// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: [B4.2] ? ... : ... +void referenceVariableWithTernaryOperator(bool coin) { + const C &c = coin ? C::get() : C(0); +} + } // end namespace decl_stmt namespace ctor_initializers { @@ -148,6 +203,24 @@ // CHECK: 1: (CXXConstructExpr, D() (Delegating initializer), class ctor_initializers::D) // CHECK-NEXT: 2: D([B1.1]) (Delegating initializer) D(int): D() {} + +// CHECK: D(double) +// CHECK: 1: C::get +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) +// CHECK-NEXT: 3: [B1.2]() +// CHECK-NEXT: 4: [B1.3] +// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, C([B1.4]) (Base initializer), class C) +// CHECK-NEXT: 6: C([B1.5]) (Base initializer) +// CHECK-NEXT: 7: CFGNewAllocator(C *) +// CHECK-NEXT: 8: C::get +// CHECK-NEXT: 9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) +// CHECK-NEXT: 10: [B1.9]() +// CHECK-NEXT: 11: [B1.10] +// CHECK-NEXT: 12: [B1.11] (CXXConstructExpr, [B1.13], class C) +// CHECK-NEXT: 13: new C([B1.12]) +// CHECK-NEXT: 14: [B1.13] (CXXConstructExpr, c1([B1.13]) (Member initializer), class C) +// CHECK-NEXT: 15: c1([B1.14]) (Member initializer) + D(double): C(C::get()), c1(new C(C::get())) {} }; } // end namespace ctor_initializers Index: cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp =================================================================== --- cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp +++ cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp @@ -1,8 +1,23 @@ // RUN: rm -f %t -// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=true -std=c++98 %s > %t 2>&1 -// RUN: FileCheck --input-file=%t -check-prefix=CXX98 -check-prefix=CHECK %s -// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=true -std=c++11 %s > %t 2>&1 -// RUN: FileCheck --input-file=%t -check-prefix=CXX11 -check-prefix=CHECK %s +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=true,cfg-rich-constructors=false -std=c++98 %s > %t 2>&1 +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX98,WARNINGS,CXX98-WARNINGS %s +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=true,cfg-rich-constructors=false -std=c++11 %s > %t 2>&1 +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX11,WARNINGS,CXX11-WARNINGS %s +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=true,cfg-rich-constructors=true -std=c++98 %s > %t 2>&1 +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX98,ANALYZER,CXX98-ANALYZER %s +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=true,cfg-rich-constructors=true -std=c++11 %s > %t 2>&1 +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX11,ANALYZER,CXX11-ANALYZER %s + +// This file tests how we construct two different flavors of the Clang CFG - +// the CFG used by the Sema analysis-based warnings and the CFG used by the +// static analyzer. The difference in the behavior is checked via FileCheck +// prefixes (WARNINGS and ANALYZER respectively). When introducing new analyzer +// flags, no new run lines should be added - just these flags would go to the +// respective line depending on where is it turned on and where is it turned +// off. Feel free to add tests that test only one of the CFG flavors if you're +// not sure how the other flavor is supposed to work in your case. + +// Additionally, different C++ standards are checked. class A { public: @@ -492,7 +507,8 @@ // 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) +// WARNINGS: 4: [B7.3] (CXXConstructExpr, class A) +// ANALYZER: 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 +641,8 @@ // 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) +// WARNINGS: 5: [B4.4] (CXXConstructExpr, struct C) +// ANALYZER: 5: [B4.4] (CXXConstructExpr, [B4.6], struct C) // CHECK: 6: C c = C(); // CHECK: 7: ~C() (Temporary object destructor) // CHECK: 8: c @@ -675,7 +692,8 @@ // 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-WARNINGS: 4: [B3.3] (CXXConstructExpr, struct D) +// CXX98-ANALYZER: 4: [B3.3] (CXXConstructExpr, [B3.5], struct D) // CXX98: 5: D d = D(); // CXX98: 6: d // CXX98: 7: [B3.6].operator bool @@ -683,7 +701,8 @@ // CXX98: 9: [B3.8] (ImplicitCastExpr, UserDefinedConversion, _Bool) // CXX98: T: if [B3.9] // CXX11: 2: [B3.1] -// CXX11: 3: [B3.2] (CXXConstructExpr, struct D) +// CXX11-WARNINGS: 3: [B3.2] (CXXConstructExpr, struct D) +// CXX11-ANALYZER: 3: [B3.2] (CXXConstructExpr, [B3.4], struct D) // CXX11: 4: D d = D(); // CXX11: 5: d // CXX11: 6: [B3.5].operator bool @@ -838,7 +857,8 @@ // 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) +// WARNINGS: 4: [B4.3] (CXXConstructExpr, class A) +// ANALYZER: 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 +1013,8 @@ // 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) +// WARNINGS: 5: [B1.4] (CXXConstructExpr, class A) +// ANALYZER: 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 +1054,8 @@ // 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) +// WARNINGS: 7: [B1.6] (CXXConstructExpr, class A) +// ANALYZER: 7: [B1.6] (CXXConstructExpr, [B1.8], class A) // CHECK: 8: A a = A::make(); // CHECK: 9: ~A() (Temporary object destructor) // CHECK: 10: int b;