temporaries.cpp revision 95ab9e306f4deefeabd89ea61987f4a8d67e0890
1// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s 2// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s 3// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -analyzer-config cfg-temporary-dtors=true %s -DTEMPORARY_DTORS 4 5extern bool clang_analyzer_eval(bool); 6 7struct Trivial { 8 Trivial(int x) : value(x) {} 9 int value; 10}; 11 12struct NonTrivial : public Trivial { 13 NonTrivial(int x) : Trivial(x) {} 14 ~NonTrivial(); 15}; 16 17 18Trivial getTrivial() { 19 return Trivial(42); // no-warning 20} 21 22const Trivial &getTrivialRef() { 23 return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'Trivial' returned to caller}} 24} 25 26 27NonTrivial getNonTrivial() { 28 return NonTrivial(42); // no-warning 29} 30 31const NonTrivial &getNonTrivialRef() { 32 return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}} 33} 34 35namespace rdar13265460 { 36 struct TrivialSubclass : public Trivial { 37 TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {} 38 int anotherValue; 39 }; 40 41 TrivialSubclass getTrivialSub() { 42 TrivialSubclass obj(1); 43 obj.value = 42; 44 obj.anotherValue = -42; 45 return obj; 46 } 47 48 void testImmediate() { 49 TrivialSubclass obj = getTrivialSub(); 50 51 clang_analyzer_eval(obj.value == 42); // expected-warning{{TRUE}} 52 clang_analyzer_eval(obj.anotherValue == -42); // expected-warning{{TRUE}} 53 54 clang_analyzer_eval(getTrivialSub().value == 42); // expected-warning{{TRUE}} 55 clang_analyzer_eval(getTrivialSub().anotherValue == -42); // expected-warning{{TRUE}} 56 } 57 58 void testMaterializeTemporaryExpr() { 59 const TrivialSubclass &ref = getTrivialSub(); 60 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} 61 62 const Trivial &baseRef = getTrivialSub(); 63 clang_analyzer_eval(baseRef.value == 42); // expected-warning{{TRUE}} 64 } 65} 66 67namespace rdar13281951 { 68 struct Derived : public Trivial { 69 Derived(int value) : Trivial(value), value2(-value) {} 70 int value2; 71 }; 72 73 void test() { 74 Derived obj(1); 75 obj.value = 42; 76 const Trivial * const &pointerRef = &obj; 77 clang_analyzer_eval(pointerRef->value == 42); // expected-warning{{TRUE}} 78 } 79} 80 81namespace compound_literals { 82 struct POD { 83 int x, y; 84 }; 85 struct HasCtor { 86 HasCtor(int x, int y) : x(x), y(y) {} 87 int x, y; 88 }; 89 struct HasDtor { 90 int x, y; 91 ~HasDtor(); 92 }; 93 struct HasCtorDtor { 94 HasCtorDtor(int x, int y) : x(x), y(y) {} 95 ~HasCtorDtor(); 96 int x, y; 97 }; 98 99 void test() { 100 clang_analyzer_eval(((POD){1, 42}).y == 42); // expected-warning{{TRUE}} 101 clang_analyzer_eval(((HasDtor){1, 42}).y == 42); // expected-warning{{TRUE}} 102 103#if __cplusplus >= 201103L 104 clang_analyzer_eval(((HasCtor){1, 42}).y == 42); // expected-warning{{TRUE}} 105 106 // FIXME: should be TRUE, but we don't inline the constructors of 107 // temporaries because we can't model their destructors yet. 108 clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{UNKNOWN}} 109#endif 110 } 111} 112 113namespace destructors { 114 void testPR16664Crash() { 115 struct Dtor { 116 ~Dtor(); 117 }; 118 extern bool coin(); 119 extern bool check(const Dtor &); 120 121 // Don't crash here. 122 if (coin() && (coin() || coin() || check(Dtor()))) { 123 Dtor(); 124 } 125 } 126 127#ifdef TEMPORARY_DTORS 128 struct NoReturnDtor { 129 ~NoReturnDtor() __attribute__((noreturn)); 130 }; 131 132 void noReturnTemp(int *x) { 133 if (! x) NoReturnDtor(); 134 *x = 47; // no warning 135 } 136 137 void noReturnInline(int **x) { 138 NoReturnDtor(); 139 } 140 141 void callNoReturn() { 142 int *x; 143 noReturnInline(&x); 144 *x = 47; // no warning 145 } 146 147 extern bool check(const NoReturnDtor &); 148 149 void testConsistencyIf(int i) { 150 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 151 clang_analyzer_eval(true); // expected-warning{{TRUE}} 152 153 if (i != 5) 154 return; 155 if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) { 156 clang_analyzer_eval(true); // no warning, unreachable code 157 } 158 } 159 160 void testConsistencyTernary(int i) { 161 (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0; 162 163 clang_analyzer_eval(true); // expected-warning{{TRUE}} 164 165 if (i != 5) 166 return; 167 168 (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0; 169 170 clang_analyzer_eval(true); // no warning, unreachable code 171 } 172 173 void testConsistencyNested(int i) { 174 extern bool compute(bool); 175 176 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 177 clang_analyzer_eval(true); // expected-warning{{TRUE}} 178 179 if (i != 5) 180 return; 181 182 if (compute(i == 5 && 183 (i == 4 || compute(true) || 184 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || 185 i != 4) { 186 clang_analyzer_eval(true); // expected-warning{{TRUE}} 187 } 188 189 if (compute(i == 5 && 190 (i == 4 || i == 4 || 191 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || 192 i != 4) { 193 clang_analyzer_eval(true); // no warning, unreachable code 194 } 195 } 196#endif // TEMPORARY_DTORS 197} 198 199void testStaticMaterializeTemporaryExpr() { 200 static const Trivial &ref = getTrivial(); 201 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} 202 203 static const Trivial &directRef = Trivial(42); 204 clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}} 205 206#if __has_feature(cxx_thread_local) 207 thread_local static const Trivial &threadRef = getTrivial(); 208 clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}} 209 210 thread_local static const Trivial &threadDirectRef = Trivial(42); 211 clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}} 212#endif 213} 214 215namespace PR16629 { 216 struct A { 217 explicit A(int* p_) : p(p_) {} 218 int* p; 219 }; 220 221 extern void escape(const A*[]); 222 extern void check(int); 223 224 void callEscape(const A& a) { 225 const A* args[] = { &a }; 226 escape(args); 227 } 228 229 void testNoWarning() { 230 int x; 231 callEscape(A(&x)); 232 check(x); // Analyzer used to give a "x is uninitialized warning" here 233 } 234 235 void set(const A*a[]) { 236 *a[0]->p = 47; 237 } 238 239 void callSet(const A& a) { 240 const A* args[] = { &a }; 241 set(args); 242 } 243 244 void testConsistency() { 245 int x; 246 callSet(A(&x)); 247 clang_analyzer_eval(x == 47); // expected-warning{{TRUE}} 248 } 249} 250