r324798 - [CFG] Provide construction contexts when constructors have cleanups.
Artem Dergachev via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 9 18:46:14 PST 2018
Author: dergachev
Date: Fri Feb 9 18:46:14 2018
New Revision: 324798
URL: http://llvm.org/viewvc/llvm-project?rev=324798&view=rev
Log:
[CFG] Provide construction contexts when constructors have cleanups.
Now that we make it possible to query the CFG constructor element to find
information about the construction site, possible cleanup work represented by
ExprWithCleanups should not prevent us from providing this information.
This allows us to have a correct construction context for variables initialized
"by value" via elidable copy-constructors, such as 'i' in
iterator i = vector.begin();
Differential Revision: https://reviews.llvm.org/D42719
Modified:
cfe/trunk/lib/Analysis/CFG.cpp
cfe/trunk/test/Analysis/cfg-rich-constructors.cpp
cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp
Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=324798&r1=324797&r2=324798&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Fri Feb 9 18:46:14 2018
@@ -1158,6 +1158,8 @@ void CFGBuilder::EnterConstructionContex
assert(CurrentConstructionContext.isNull() &&
"Already within a construction context!");
CurrentConstructionContext = ConstructionContext(Trigger);
+ } else if (auto *Cleanups = dyn_cast<ExprWithCleanups>(Child)) {
+ EnterConstructionContextIfNecessary(Trigger, Cleanups->getSubExpr());
}
}
Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=324798&r1=324797&r2=324798&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original)
+++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Fri Feb 9 18:46:14 2018
@@ -92,18 +92,45 @@ void simpleVariableWithOperatorNewInBrac
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 @@ void referenceVariableWithInitializer()
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 @@ public:
// 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
Modified: cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp?rev=324798&r1=324797&r2=324798&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp (original)
+++ cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp Fri Feb 9 18:46:14 2018
@@ -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 @@ int testConsistencyNestedNormalReturn(bo
// 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 @@ int testConsistencyNestedNormalReturn(bo
// 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 @@ int testConsistencyNestedNormalReturn(bo
// 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 @@ int testConsistencyNestedNormalReturn(bo
// 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 @@ int testConsistencyNestedNormalReturn(bo
// 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 @@ int testConsistencyNestedNormalReturn(bo
// 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 @@ int testConsistencyNestedNormalReturn(bo
// 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;
More information about the cfe-commits
mailing list