summaryrefslogtreecommitdiff
path: root/test/Analysis/temporaries.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/Analysis/temporaries.cpp')
-rw-r--r--test/Analysis/temporaries.cpp280
1 files changed, 270 insertions, 10 deletions
diff --git a/test/Analysis/temporaries.cpp b/test/Analysis/temporaries.cpp
index e760d7ea283ad..6191abfb4d2ea 100644
--- a/test/Analysis/temporaries.cpp
+++ b/test/Analysis/temporaries.cpp
@@ -1,15 +1,31 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -verify -w -std=c++03 %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -verify -w -std=c++11 %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true %s -std=c++11
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus,debug.ExprInspection -DTEMPORARY_DTORS -w -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true %s -std=c++17
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=core,cplusplus\
+// RUN: -analyzer-checker debug.ExprInspection -Wno-non-pod-varargs\
+// RUN: -analyzer-config eagerly-assume=false -verify %s\
+// RUN: -std=c++03 -analyzer-config cfg-temporary-dtors=false
+
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=core,cplusplus\
+// RUN: -analyzer-checker debug.ExprInspection -Wno-non-pod-varargs\
+// RUN: -analyzer-config eagerly-assume=false -verify %s\
+// RUN: -std=c++11 -analyzer-config cfg-temporary-dtors=false
+
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=core,cplusplus\
+// RUN: -analyzer-checker debug.ExprInspection -Wno-non-pod-varargs\
+// RUN: -analyzer-config eagerly-assume=false -verify %s\
+// RUN: -std=c++11 -analyzer-config cfg-temporary-dtors=true\
+// RUN: -DTEMPORARY_DTORS
+
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=core,cplusplus\
+// RUN: -analyzer-checker debug.ExprInspection -Wno-non-pod-varargs\
+// RUN: -analyzer-config eagerly-assume=false -verify %s\
+// RUN: -std=c++17 -analyzer-config cfg-temporary-dtors=true\
+// RUN: -DTEMPORARY_DTORS
-// Note: The C++17 run-line doesn't -verify yet - it is a no-crash test.
extern bool clang_analyzer_eval(bool);
extern bool clang_analyzer_warnIfReached();
void clang_analyzer_checkInlined(bool);
-#include "Inputs/system-header-simulator-cxx.h";
+#include "Inputs/system-header-simulator-cxx.h"
struct Trivial {
Trivial(int x) : value(x) {}
@@ -450,7 +466,16 @@ namespace destructors {
}
#if __cplusplus >= 201103L
- CtorWithNoReturnDtor returnNoReturnDtor() {
+ struct CtorWithNoReturnDtor2 {
+ CtorWithNoReturnDtor2() = default;
+
+ CtorWithNoReturnDtor2(int x) {
+ clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+ }
+
+ ~CtorWithNoReturnDtor2() __attribute__((noreturn));
+ };
+ CtorWithNoReturnDtor2 returnNoReturnDtor() {
return {1}; // no-crash
}
#endif
@@ -805,7 +830,12 @@ void test_ternary_temporary_with_copy(int coin) {
// On each branch the variable is constructed directly.
if (coin) {
clang_analyzer_eval(x == 1); // expected-warning{{TRUE}}
+#if __cplusplus < 201703L
clang_analyzer_eval(y == 1); // expected-warning{{TRUE}}
+#else
+ // FIXME: Destructor called twice in C++17?
+ clang_analyzer_eval(y == 2); // expected-warning{{TRUE}}
+#endif
clang_analyzer_eval(z == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(w == 0); // expected-warning{{TRUE}}
@@ -813,7 +843,12 @@ void test_ternary_temporary_with_copy(int coin) {
clang_analyzer_eval(x == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(y == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(z == 1); // expected-warning{{TRUE}}
+#if __cplusplus < 201703L
clang_analyzer_eval(w == 1); // expected-warning{{TRUE}}
+#else
+ // FIXME: Destructor called twice in C++17?
+ clang_analyzer_eval(w == 2); // expected-warning{{TRUE}}
+#endif
}
}
} // namespace test_match_constructors_and_destructors
@@ -865,9 +900,12 @@ class C {
public:
~C() {
glob = 1;
+ // FIXME: Why is destructor not inlined in C++17
clang_analyzer_checkInlined(true);
#ifdef TEMPORARY_DTORS
- // expected-warning@-2{{TRUE}}
+#if __cplusplus < 201703L
+ // expected-warning@-3{{TRUE}}
+#endif
#endif
}
};
@@ -886,11 +924,16 @@ void test(int coin) {
// temporaries returned from functions, so we took the wrong branch.
coin && is(get()); // no-crash
if (coin) {
+ // FIXME: Why is destructor not inlined in C++17
clang_analyzer_eval(glob);
#ifdef TEMPORARY_DTORS
- // expected-warning@-2{{TRUE}}
+#if __cplusplus < 201703L
+ // expected-warning@-3{{TRUE}}
+#else
+ // expected-warning@-5{{UNKNOWN}}
+#endif
#else
- // expected-warning@-4{{UNKNOWN}}
+ // expected-warning@-8{{UNKNOWN}}
#endif
} else {
// The destructor is not called on this branch.
@@ -962,6 +1005,92 @@ C &&bar2() { return foo2(); } // no-crash
} // end namespace pass_references_through
+namespace arguments {
+int glob;
+
+struct S {
+ int x;
+ S(int x): x(x) {}
+ S(const S &s) : x(s.x) {}
+ ~S() {}
+
+ S &operator+(S s) {
+ glob = s.x;
+ x += s.x;
+ return *this;
+ }
+};
+
+class C {
+public:
+ virtual void bar3(S s) {}
+};
+
+class D: public C {
+public:
+ D() {}
+ virtual void bar3(S s) override { glob = s.x; }
+};
+
+void bar1(S s) {
+ glob = s.x;
+}
+
+// Record-typed calls are a different CFGStmt, let's see if we handle that
+// as well.
+S bar2(S s) {
+ glob = s.x;
+ return S(3);
+}
+
+void bar5(int, ...);
+
+void foo(void (*bar4)(S)) {
+ bar1(S(1));
+ clang_analyzer_eval(glob == 1);
+#ifdef TEMPORARY_DTORS
+ // expected-warning@-2{{TRUE}}
+#else
+ // expected-warning@-4{{UNKNOWN}}
+#endif
+
+ bar2(S(2));
+ // FIXME: Why are we losing information in C++17?
+ clang_analyzer_eval(glob == 2);
+#ifdef TEMPORARY_DTORS
+#if __cplusplus < 201703L
+ // expected-warning@-3{{TRUE}}
+#else
+ // expected-warning@-5{{UNKNOWN}}
+#endif
+#else
+ // expected-warning@-8{{UNKNOWN}}
+#endif
+
+ C *c = new D();
+ c->bar3(S(3));
+ // FIXME: Should be TRUE.
+ clang_analyzer_eval(glob == 3); // expected-warning{{UNKNOWN}}
+ delete c;
+
+ // What if we've no idea what we're calling?
+ bar4(S(4)); // no-crash
+
+ S(5) + S(6);
+ clang_analyzer_eval(glob == 6);
+#ifdef TEMPORARY_DTORS
+ // expected-warning@-2{{TRUE}}
+#else
+ // expected-warning@-4{{UNKNOWN}}
+#endif
+
+ // Variadic functions. This will __builtin_trap() because you cannot pass
+ // an object as a variadic argument.
+ bar5(7, S(7)); // no-crash
+ clang_analyzer_warnIfReached(); // no-warning
+}
+} // namespace arguments
+
namespace ctor_argument {
// Stripped down unique_ptr<int>
struct IntPtr {
@@ -986,3 +1115,134 @@ void bar() {
*i = 99; // no-warning
}
} // namespace ctor_argument
+
+namespace operator_implicit_argument {
+struct S {
+ bool x;
+ S(bool x): x(x) {}
+ operator bool() const { return x; }
+};
+
+void foo() {
+ if (S(false)) {
+ clang_analyzer_warnIfReached(); // no-warning
+ }
+ if (S(true)) {
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ }
+}
+} // namespace operator_implicit_argument
+
+
+#if __cplusplus >= 201103L
+namespace argument_lazy_bindings {
+int glob;
+
+struct S {
+ int x, y, z;
+};
+
+struct T {
+ S s;
+ int w;
+ T(int w): s{5, 6, 7}, w(w) {}
+};
+
+void foo(T t) {
+ t.s = {1, 2, 3};
+ glob = t.w;
+}
+
+void bar() {
+ foo(T(4));
+ clang_analyzer_eval(glob == 4); // expected-warning{{TRUE}}
+}
+} // namespace argument_lazy_bindings
+#endif
+
+namespace operator_argument_cleanup {
+struct S {
+ S();
+};
+
+class C {
+public:
+ void operator=(S);
+};
+
+void foo() {
+ C c;
+ c = S(); // no-crash
+}
+} // namespace operator_argument_cleanup
+
+namespace argument_decl_lookup {
+class C {};
+int foo(C);
+int bar(C c) { foo(c); }
+int foo(C c) {}
+} // namespace argument_decl_lookup
+
+namespace argument_virtual_decl_lookup {
+class C {};
+
+struct T {
+ virtual void foo(C);
+};
+
+void run() {
+ T *t;
+ t->foo(C()); // no-crash // expected-warning{{Called C++ object pointer is uninitialized}}
+}
+
+// This is after run() because the test is about picking the correct decl
+// for the parameter region, which should belong to the correct function decl,
+// and the non-definition decl should be found by direct lookup.
+void T::foo(C) {}
+} // namespace argument_virtual_decl_lookup
+
+namespace union_indirect_field_crash {
+union U {
+ struct {
+ int x;
+ };
+};
+
+template <typename T> class C {
+public:
+ void foo() const {
+ (void)(true ? U().x : 0);
+ }
+};
+
+void test() {
+ C<int> c;
+ c.foo();
+}
+} // namespace union_indirect_field_crash
+
+namespace return_from_top_frame {
+struct S {
+ int *p;
+ S() { p = new int; }
+ S(S &&s) : p(s.p) { s.p = 0; }
+ ~S(); // Presumably releases 'p'.
+};
+
+S foo() {
+ S s;
+ return s;
+}
+
+S bar1() {
+ return foo(); // no-warning
+}
+
+S bar2() {
+ return S();
+}
+
+S bar3(int coin) {
+ return coin ? S() : foo(); // no-warning
+}
+} // namespace return_from_top_frame