| // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s |
| // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s |
| |
| extern bool clang_analyzer_eval(bool); |
| |
| struct Trivial { |
| Trivial(int x) : value(x) {} |
| int value; |
| }; |
| |
| struct NonTrivial : public Trivial { |
| NonTrivial(int x) : Trivial(x) {} |
| ~NonTrivial(); |
| }; |
| |
| |
| Trivial getTrivial() { |
| return Trivial(42); // no-warning |
| } |
| |
| const Trivial &getTrivialRef() { |
| return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'Trivial' returned to caller}} |
| } |
| |
| |
| NonTrivial getNonTrivial() { |
| return NonTrivial(42); // no-warning |
| } |
| |
| const NonTrivial &getNonTrivialRef() { |
| return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}} |
| } |
| |
| namespace rdar13265460 { |
| struct TrivialSubclass : public Trivial { |
| TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {} |
| int anotherValue; |
| }; |
| |
| TrivialSubclass getTrivialSub() { |
| TrivialSubclass obj(1); |
| obj.value = 42; |
| obj.anotherValue = -42; |
| return obj; |
| } |
| |
| void testImmediate() { |
| TrivialSubclass obj = getTrivialSub(); |
| |
| clang_analyzer_eval(obj.value == 42); // expected-warning{{TRUE}} |
| clang_analyzer_eval(obj.anotherValue == -42); // expected-warning{{TRUE}} |
| |
| clang_analyzer_eval(getTrivialSub().value == 42); // expected-warning{{TRUE}} |
| clang_analyzer_eval(getTrivialSub().anotherValue == -42); // expected-warning{{TRUE}} |
| } |
| |
| void testMaterializeTemporaryExpr() { |
| const TrivialSubclass &ref = getTrivialSub(); |
| clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} |
| |
| const Trivial &baseRef = getTrivialSub(); |
| clang_analyzer_eval(baseRef.value == 42); // expected-warning{{TRUE}} |
| } |
| } |
| |
| namespace rdar13281951 { |
| struct Derived : public Trivial { |
| Derived(int value) : Trivial(value), value2(-value) {} |
| int value2; |
| }; |
| |
| void test() { |
| Derived obj(1); |
| obj.value = 42; |
| const Trivial * const &pointerRef = &obj; |
| clang_analyzer_eval(pointerRef->value == 42); // expected-warning{{TRUE}} |
| } |
| } |
| |
| namespace compound_literals { |
| struct POD { |
| int x, y; |
| }; |
| struct HasCtor { |
| HasCtor(int x, int y) : x(x), y(y) {} |
| int x, y; |
| }; |
| struct HasDtor { |
| int x, y; |
| ~HasDtor(); |
| }; |
| struct HasCtorDtor { |
| HasCtorDtor(int x, int y) : x(x), y(y) {} |
| ~HasCtorDtor(); |
| int x, y; |
| }; |
| |
| void test() { |
| clang_analyzer_eval(((POD){1, 42}).y == 42); // expected-warning{{TRUE}} |
| clang_analyzer_eval(((HasDtor){1, 42}).y == 42); // expected-warning{{TRUE}} |
| |
| #if __cplusplus >= 201103L |
| clang_analyzer_eval(((HasCtor){1, 42}).y == 42); // expected-warning{{TRUE}} |
| |
| // FIXME: should be TRUE, but we don't inline the constructors of |
| // temporaries because we can't model their destructors yet. |
| clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{UNKNOWN}} |
| #endif |
| } |
| } |
| |
| namespace destructors { |
| void testPR16664Crash() { |
| struct Dtor { |
| ~Dtor(); |
| }; |
| extern bool coin(); |
| extern bool check(const Dtor &); |
| |
| // Don't crash here. |
| if (coin() && (coin() || coin() || check(Dtor()))) { |
| Dtor(); |
| } |
| } |
| |
| void testConsistency(int i) { |
| struct NoReturnDtor { |
| ~NoReturnDtor() __attribute__((noreturn)); |
| }; |
| extern bool check(const NoReturnDtor &); |
| |
| if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) |
| clang_analyzer_eval(true); // expected-warning{{TRUE}} |
| |
| if (i != 5) |
| return; |
| if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) { |
| // FIXME: Should be no-warning, because the noreturn destructor should |
| // fire on all paths. |
| clang_analyzer_eval(true); // expected-warning{{TRUE}} |
| } |
| } |
| } |
| |
| void testStaticMaterializeTemporaryExpr() { |
| static const Trivial &ref = getTrivial(); |
| clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} |
| |
| static const Trivial &directRef = Trivial(42); |
| clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}} |
| |
| #if __has_feature(cxx_thread_local) |
| thread_local static const Trivial &threadRef = getTrivial(); |
| clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}} |
| |
| thread_local static const Trivial &threadDirectRef = Trivial(42); |
| clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}} |
| #endif |
| } |