diff options
| author | Artem Dergachev <artem.dergachev@gmail.com> | 2018-03-30 19:21:18 +0000 |
|---|---|---|
| committer | Artem Dergachev <artem.dergachev@gmail.com> | 2018-03-30 19:21:18 +0000 |
| commit | 9d3a7d8b2badf05a52188e2874a1e53c1416e279 (patch) | |
| tree | 692008944c764fdc963025a945d3253da3381820 /clang/test | |
| parent | dc97172b2fb7452bdd9e841e4b2d5049fbdd9275 (diff) | |
| download | bcm5719-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.cpp | 7 | ||||
| -rw-r--r-- | clang/test/Analysis/cxx17-mandatory-elision.cpp | 58 | ||||
| -rw-r--r-- | clang/test/Analysis/temp-obj-dtors-cfg-output.cpp | 3 |
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)] |

