summaryrefslogtreecommitdiffstats
path: root/clang/test
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2018-03-30 19:21:18 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2018-03-30 19:21:18 +0000
commit9d3a7d8b2badf05a52188e2874a1e53c1416e279 (patch)
tree692008944c764fdc963025a945d3253da3381820 /clang/test
parentdc97172b2fb7452bdd9e841e4b2d5049fbdd9275 (diff)
downloadbcm5719-llvm-9d3a7d8b2badf05a52188e2874a1e53c1416e279.tar.gz
bcm5719-llvm-9d3a7d8b2badf05a52188e2874a1e53c1416e279.zip
[CFG] [analyzer] Avoid modeling C++17 constructors that aren't fully supported.
Not enough work has been done so far to ensure correctness of construction contexts in the CFG when C++17 copy elision is in effect, so for now we should drop construction contexts in the CFG and in the analyzer when they seem different from what we support anyway. This includes initializations with conditional operators and return values across multiple stack frames. Differential Revision: https://reviews.llvm.org/D44854 llvm-svn: 328893
Diffstat (limited to 'clang/test')
-rw-r--r--clang/test/Analysis/cfg-rich-constructors.cpp7
-rw-r--r--clang/test/Analysis/cxx17-mandatory-elision.cpp58
-rw-r--r--clang/test/Analysis/temp-obj-dtors-cfg-output.cpp3
3 files changed, 66 insertions, 2 deletions
diff --git a/clang/test/Analysis/cfg-rich-constructors.cpp b/clang/test/Analysis/cfg-rich-constructors.cpp
index fe70e125ff3..51eca122292 100644
--- a/clang/test/Analysis/cfg-rich-constructors.cpp
+++ b/clang/test/Analysis/cfg-rich-constructors.cpp
@@ -108,6 +108,9 @@ void simpleVariableInitializedByValue() {
C c = C::get();
}
+// FIXME: Find construction contexts for both branches in C++17.
+// Note that once it gets detected, the test for the get() branch would not
+// fail, because FileCheck allows partial matches.
// CHECK: void simpleVariableWithTernaryOperator(bool coin)
// CHECK: [B1]
// CXX11-NEXT: 1: [B4.2] ? [B2.5] : [B3.6]
@@ -122,7 +125,7 @@ void simpleVariableInitializedByValue() {
// CXX11-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B2.4])
// CXX11-NEXT: 4: [B2.3]
// CXX11-NEXT: 5: [B2.4] (CXXConstructExpr, [B1.2], class C)
-// CXX17-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B1.2])
+// CXX17-NEXT: 3: [B2.2]()
// CHECK: [B3]
// CHECK-NEXT: 1: 0
// CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *)
@@ -130,7 +133,7 @@ void simpleVariableInitializedByValue() {
// CXX11-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
// CXX11-NEXT: 5: [B3.4]
// CXX11-NEXT: 6: [B3.5] (CXXConstructExpr, [B1.2], class C)
-// CXX17-NEXT: 3: [B3.2] (CXXConstructExpr, [B1.2], class C)
+// CXX17-NEXT: 3: [B3.2] (CXXConstructExpr, class C)
// CXX17-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
// CHECK: [B4]
// CHECK-NEXT: 1: coin
diff --git a/clang/test/Analysis/cxx17-mandatory-elision.cpp b/clang/test/Analysis/cxx17-mandatory-elision.cpp
new file mode 100644
index 00000000000..700888e47a9
--- /dev/null
+++ b/clang/test/Analysis/cxx17-mandatory-elision.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 -verify %s
+
+void clang_analyzer_eval(bool);
+
+template <typename T> struct AddressVector {
+ T *buf[10];
+ int len;
+
+ AddressVector() : len(0) {}
+
+ void push(T *t) {
+ buf[len] = t;
+ ++len;
+ }
+};
+
+class ClassWithoutDestructor {
+ AddressVector<ClassWithoutDestructor> &v;
+
+public:
+ ClassWithoutDestructor(AddressVector<ClassWithoutDestructor> &v) : v(v) {
+ v.push(this);
+ }
+
+ ClassWithoutDestructor(ClassWithoutDestructor &&c) : v(c.v) { v.push(this); }
+ ClassWithoutDestructor(const ClassWithoutDestructor &c) : v(c.v) {
+ v.push(this);
+ }
+};
+
+ClassWithoutDestructor make1(AddressVector<ClassWithoutDestructor> &v) {
+ return ClassWithoutDestructor(v);
+}
+ClassWithoutDestructor make2(AddressVector<ClassWithoutDestructor> &v) {
+ return make1(v);
+}
+ClassWithoutDestructor make3(AddressVector<ClassWithoutDestructor> &v) {
+ return make2(v);
+}
+
+void testMultipleReturns() {
+ AddressVector<ClassWithoutDestructor> v;
+ ClassWithoutDestructor c = make3(v);
+
+#if __cplusplus >= 201703L
+ // FIXME: Both should be TRUE.
+ clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(v.buf[0] == &c); // expected-warning{{FALSE}}
+#else
+ clang_analyzer_eval(v.len == 5); // expected-warning{{TRUE}}
+ clang_analyzer_eval(v.buf[0] != v.buf[1]); // expected-warning{{TRUE}}
+ clang_analyzer_eval(v.buf[1] != v.buf[2]); // expected-warning{{TRUE}}
+ clang_analyzer_eval(v.buf[2] != v.buf[3]); // expected-warning{{TRUE}}
+ clang_analyzer_eval(v.buf[3] != v.buf[4]); // expected-warning{{TRUE}}
+ clang_analyzer_eval(v.buf[4] == &c); // expected-warning{{TRUE}}
+#endif
+}
diff --git a/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp b/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp
index 62e5189f289..0b9397dd8ba 100644
--- a/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ b/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -218,6 +218,9 @@ C &&foo2();
// Don't try to figure out how to perform construction of the record here.
const C &bar1() { return foo1(); } // no-crash
C &&bar2() { return foo2(); } // no-crash
+const C &bar3(bool coin) {
+ return coin ? foo1() : foo1(); // no-crash
+}
} // end namespace pass_references_through
// CHECK: [B1 (ENTRY)]
OpenPOWER on IntegriCloud