temporaries.cpp revision 651f13cea278ec967336033dd032faef0e9fc2ec
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 -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s 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 testPR16664andPR18159Crash() { 115 struct Dtor { 116 ~Dtor(); 117 }; 118 extern bool coin(); 119 extern bool check(const Dtor &); 120 121#ifndef TEMPORARY_DTORS 122 // FIXME: Don't assert here when tmp dtors are enabled. 123 // PR16664 and PR18159 124 if (coin() && (coin() || coin() || check(Dtor()))) { 125 Dtor(); 126 } 127#endif 128 } 129 130#ifdef TEMPORARY_DTORS 131 struct NoReturnDtor { 132 ~NoReturnDtor() __attribute__((noreturn)); 133 }; 134 135 void noReturnTemp(int *x) { 136 if (! x) NoReturnDtor(); 137 *x = 47; // no warning 138 } 139 140 void noReturnInline(int **x) { 141 NoReturnDtor(); 142 } 143 144 void callNoReturn() { 145 int *x; 146 noReturnInline(&x); 147 *x = 47; // no warning 148 } 149 150 extern bool check(const NoReturnDtor &); 151 152 void testConsistencyIf(int i) { 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/* 174 // PR16664 and PR18159 175 FIXME: Don't assert here. 176 void testConsistencyNested(int i) { 177 extern bool compute(bool); 178 179 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 180 clang_analyzer_eval(true); // expected TRUE 181 182 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 183 clang_analyzer_eval(true); // expected TRUE 184 185 if (i != 5) 186 return; 187 188 if (compute(i == 5 && 189 (i == 4 || compute(true) || 190 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || 191 i != 4) { 192 clang_analyzer_eval(true); // expected TRUE 193 } 194 195 FIXME: This shouldn't cause a warning. 196 if (compute(i == 5 && 197 (i == 4 || i == 4 || 198 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || 199 i != 4) { 200 clang_analyzer_eval(true); // no warning, unreachable code 201 } 202 }*/ 203 204 // PR16664 and PR18159 205 void testConsistencyNestedSimple(bool value) { 206 if (value) { 207 if (!value || check(NoReturnDtor())) { 208 clang_analyzer_eval(true); // no warning, unreachable code 209 } 210 } 211 } 212 213 // PR16664 and PR18159 214 void testConsistencyNestedComplex(bool value) { 215 if (value) { 216 if (!value || !value || check(NoReturnDtor())) { 217 // FIXME: This shouldn't cause a warning. 218 clang_analyzer_eval(true); // expected-warning{{TRUE}} 219 } 220 } 221 } 222 223 // PR16664 and PR18159 224 void testConsistencyNestedWarning(bool value) { 225 if (value) { 226 if (!value || value || check(NoReturnDtor())) { 227 clang_analyzer_eval(true); // expected-warning{{TRUE}} 228 } 229 } 230 } 231 232#endif // TEMPORARY_DTORS 233} 234 235void testStaticMaterializeTemporaryExpr() { 236 static const Trivial &ref = getTrivial(); 237 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} 238 239 static const Trivial &directRef = Trivial(42); 240 clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}} 241 242#if __has_feature(cxx_thread_local) 243 thread_local static const Trivial &threadRef = getTrivial(); 244 clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}} 245 246 thread_local static const Trivial &threadDirectRef = Trivial(42); 247 clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}} 248#endif 249} 250 251namespace PR16629 { 252 struct A { 253 explicit A(int* p_) : p(p_) {} 254 int* p; 255 }; 256 257 extern void escape(const A*[]); 258 extern void check(int); 259 260 void callEscape(const A& a) { 261 const A* args[] = { &a }; 262 escape(args); 263 } 264 265 void testNoWarning() { 266 int x; 267 callEscape(A(&x)); 268 check(x); // Analyzer used to give a "x is uninitialized warning" here 269 } 270 271 void set(const A*a[]) { 272 *a[0]->p = 47; 273 } 274 275 void callSet(const A& a) { 276 const A* args[] = { &a }; 277 set(args); 278 } 279 280 void testConsistency() { 281 int x; 282 callSet(A(&x)); 283 clang_analyzer_eval(x == 47); // expected-warning{{TRUE}} 284 } 285} 286