diff options
Diffstat (limited to 'test/Analysis/temporaries.cpp')
-rw-r--r-- | test/Analysis/temporaries.cpp | 280 |
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 |