1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify %s 2 3 void clang_analyzer_eval(bool); 4 void clang_analyzer_checkInlined(bool); 5 6 // A simplified version of std::move. 7 template <typename T> 8 T &&move(T &obj) { 9 return static_cast<T &&>(obj); 10 } 11 12 13 struct Wrapper { 14 __strong id obj; 15 }; 16 17 void test() { 18 Wrapper w; 19 // force a diagnostic 20 *(char *)0 = 1; // expected-warning{{Dereference of null pointer}} 21 } 22 23 24 struct IntWrapper { 25 int x; 26 }; 27 28 void testCopyConstructor() { 29 IntWrapper a; 30 a.x = 42; 31 32 IntWrapper b(a); 33 clang_analyzer_eval(b.x == 42); // expected-warning{{TRUE}} 34 } 35 36 struct NonPODIntWrapper { 37 int x; 38 39 virtual int get(); 40 }; 41 42 void testNonPODCopyConstructor() { 43 NonPODIntWrapper a; 44 a.x = 42; 45 46 NonPODIntWrapper b(a); 47 clang_analyzer_eval(b.x == 42); // expected-warning{{TRUE}} 48 } 49 50 51 namespace ConstructorVirtualCalls { 52 class A { 53 public: 54 int *out1, *out2, *out3; 55 56 virtual int get() { return 1; } 57 58 A(int *out1) { 59 *out1 = get(); 60 } 61 }; 62 63 class B : public A { 64 public: 65 virtual int get() { return 2; } 66 67 B(int *out1, int *out2) : A(out1) { 68 *out2 = get(); 69 } 70 }; 71 72 class C : public B { 73 public: 74 virtual int get() { return 3; } 75 76 C(int *out1, int *out2, int *out3) : B(out1, out2) { 77 *out3 = get(); 78 } 79 }; 80 81 void test() { 82 int a, b, c; 83 84 C obj(&a, &b, &c); 85 clang_analyzer_eval(a == 1); // expected-warning{{TRUE}} 86 clang_analyzer_eval(b == 2); // expected-warning{{TRUE}} 87 clang_analyzer_eval(c == 3); // expected-warning{{TRUE}} 88 89 clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}} 90 91 // Sanity check for devirtualization. 92 A *base = &obj; 93 clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}} 94 } 95 } 96 97 namespace TemporaryConstructor { 98 class BoolWrapper { 99 public: 100 BoolWrapper() { 101 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 102 value = true; 103 } 104 bool value; 105 }; 106 107 void test() { 108 // PR13717 - Don't crash when a CXXTemporaryObjectExpr is inlined. 109 if (BoolWrapper().value) 110 return; 111 } 112 } 113 114 115 namespace ConstructorUsedAsRValue { 116 using TemporaryConstructor::BoolWrapper; 117 118 bool extractValue(BoolWrapper b) { 119 return b.value; 120 } 121 122 void test() { 123 bool result = extractValue(BoolWrapper()); 124 clang_analyzer_eval(result); // expected-warning{{TRUE}} 125 } 126 } 127 128 namespace PODUninitialized { 129 class POD { 130 public: 131 int x, y; 132 }; 133 134 class PODWrapper { 135 public: 136 POD p; 137 }; 138 139 class NonPOD { 140 public: 141 int x, y; 142 143 NonPOD() {} 144 NonPOD(const NonPOD &Other) 145 : x(Other.x), y(Other.y) // expected-warning {{undefined}} 146 { 147 } 148 NonPOD(NonPOD &&Other) 149 : x(Other.x), y(Other.y) // expected-warning {{undefined}} 150 { 151 } 152 153 NonPOD &operator=(const NonPOD &Other) 154 { 155 x = Other.x; 156 y = Other.y; // expected-warning {{undefined}} 157 return *this; 158 } 159 NonPOD &operator=(NonPOD &&Other) 160 { 161 x = Other.x; 162 y = Other.y; // expected-warning {{undefined}} 163 return *this; 164 } 165 }; 166 167 class NonPODWrapper { 168 public: 169 class Inner { 170 public: 171 int x, y; 172 173 Inner() {} 174 Inner(const Inner &Other) 175 : x(Other.x), y(Other.y) // expected-warning {{undefined}} 176 { 177 } 178 Inner(Inner &&Other) 179 : x(Other.x), y(Other.y) // expected-warning {{undefined}} 180 { 181 } 182 183 Inner &operator=(const Inner &Other) 184 { 185 x = Other.x; // expected-warning {{undefined}} 186 y = Other.y; 187 return *this; 188 } 189 Inner &operator=(Inner &&Other) 190 { 191 x = Other.x; // expected-warning {{undefined}} 192 y = Other.y; 193 return *this; 194 } 195 }; 196 197 Inner p; 198 }; 199 200 void testPOD() { 201 POD p; 202 p.x = 1; 203 POD p2 = p; // no-warning 204 clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}} 205 POD p3 = move(p); // no-warning 206 clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}} 207 208 // Use rvalues as well. 209 clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}} 210 211 PODWrapper w; 212 w.p.y = 1; 213 PODWrapper w2 = w; // no-warning 214 clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}} 215 PODWrapper w3 = move(w); // no-warning 216 clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}} 217 218 // Use rvalues as well. 219 clang_analyzer_eval(PODWrapper(w3).p.y == 1); // expected-warning{{TRUE}} 220 } 221 222 void testNonPOD() { 223 NonPOD p; 224 p.x = 1; 225 NonPOD p2 = p; 226 } 227 228 void testNonPODMove() { 229 NonPOD p; 230 p.x = 1; 231 NonPOD p2 = move(p); 232 } 233 234 void testNonPODWrapper() { 235 NonPODWrapper w; 236 w.p.y = 1; 237 NonPODWrapper w2 = w; 238 } 239 240 void testNonPODWrapperMove() { 241 NonPODWrapper w; 242 w.p.y = 1; 243 NonPODWrapper w2 = move(w); 244 } 245 246 // Not strictly about constructors, but trivial assignment operators should 247 // essentially work the same way. 248 namespace AssignmentOperator { 249 void testPOD() { 250 POD p; 251 p.x = 1; 252 POD p2; 253 p2 = p; // no-warning 254 clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}} 255 POD p3; 256 p3 = move(p); // no-warning 257 clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}} 258 259 PODWrapper w; 260 w.p.y = 1; 261 PODWrapper w2; 262 w2 = w; // no-warning 263 clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}} 264 PODWrapper w3; 265 w3 = move(w); // no-warning 266 clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}} 267 } 268 269 void testReturnValue() { 270 POD p; 271 p.x = 1; 272 POD p2; 273 clang_analyzer_eval(&(p2 = p) == &p2); // expected-warning{{TRUE}} 274 275 PODWrapper w; 276 w.p.y = 1; 277 PODWrapper w2; 278 clang_analyzer_eval(&(w2 = w) == &w2); // expected-warning{{TRUE}} 279 } 280 281 void testNonPOD() { 282 NonPOD p; 283 p.x = 1; 284 NonPOD p2; 285 p2 = p; 286 } 287 288 void testNonPODMove() { 289 NonPOD p; 290 p.x = 1; 291 NonPOD p2; 292 p2 = move(p); 293 } 294 295 void testNonPODWrapper() { 296 NonPODWrapper w; 297 w.p.y = 1; 298 NonPODWrapper w2; 299 w2 = w; 300 } 301 302 void testNonPODWrapperMove() { 303 NonPODWrapper w; 304 w.p.y = 1; 305 NonPODWrapper w2; 306 w2 = move(w); 307 } 308 } 309 } 310