temporaries.cpp revision dd9e9cec6f863afa15dd91b34fbf15c66c678c02
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 crash here when tmp dtros 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/* 175 // PR16664 and PR18159 176 FIXME: Don't crash here. 177 void testConsistencyNested(int i) { 178 extern bool compute(bool); 179 180 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 181 clang_analyzer_eval(true); // expected TRUE 182 183 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor()))) 184 clang_analyzer_eval(true); // expected TRUE 185 186 if (i != 5) 187 return; 188 189 if (compute(i == 5 && 190 (i == 4 || compute(true) || 191 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) || 192 i != 4) { 193 clang_analyzer_eval(true); // expected TRUE 194 } 195 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#endif // TEMPORARY_DTORS 205} 206 207void testStaticMaterializeTemporaryExpr() { 208 static const Trivial &ref = getTrivial(); 209 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} 210 211 static const Trivial &directRef = Trivial(42); 212 clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}} 213 214#if __has_feature(cxx_thread_local) 215 thread_local static const Trivial &threadRef = getTrivial(); 216 clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}} 217 218 thread_local static const Trivial &threadDirectRef = Trivial(42); 219 clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}} 220#endif 221} 222 223namespace PR16629 { 224 struct A { 225 explicit A(int* p_) : p(p_) {} 226 int* p; 227 }; 228 229 extern void escape(const A*[]); 230 extern void check(int); 231 232 void callEscape(const A& a) { 233 const A* args[] = { &a }; 234 escape(args); 235 } 236 237 void testNoWarning() { 238 int x; 239 callEscape(A(&x)); 240 check(x); // Analyzer used to give a "x is uninitialized warning" here 241 } 242 243 void set(const A*a[]) { 244 *a[0]->p = 47; 245 } 246 247 void callSet(const A& a) { 248 const A* args[] = { &a }; 249 set(args); 250 } 251 252 void testConsistency() { 253 int x; 254 callSet(A(&x)); 255 clang_analyzer_eval(x == 47); // expected-warning{{TRUE}} 256 } 257} 258