1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ 2 // RUN: -analyzer-checker=debug.ExprInspection -verify\ 3 // RUN: -Wno-tautological-compare\ 4 // RUN: -x c %s 5 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ 6 // RUN: -analyzer-checker=debug.ExprInspection -verify\ 7 // RUN: -Wno-tautological-compare\ 8 // RUN: -x c++ -std=c++14 %s 9 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ 10 // RUN: -analyzer-checker=debug.ExprInspection -verify\ 11 // RUN: -Wno-tautological-compare\ 12 // RUN: -x c++ -std=c++17 %s 13 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ 14 // RUN: -analyzer-checker=debug.ExprInspection -verify\ 15 // RUN: -Wno-tautological-compare\ 16 // RUN: -DINLINE -x c %s 17 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ 18 // RUN: -analyzer-checker=debug.ExprInspection -verify\ 19 // RUN: -Wno-tautological-compare\ 20 // RUN: -DINLINE -x c++ -std=c++14 %s 21 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ 22 // RUN: -analyzer-checker=debug.ExprInspection -verify\ 23 // RUN: -Wno-tautological-compare\ 24 // RUN: -DINLINE -x c++ -std=c++17 %s 25 26 void clang_analyzer_eval(int); 27 28 struct S { 29 int field; 30 31 #if __cplusplus 32 const struct S *getThis() const { return this; } 33 const struct S *operator +() const { return this; } 34 35 bool check() const { return this == this; } 36 bool operator !() const { return this != this; } 37 38 int operator *() const { return field; } 39 #endif 40 }; 41 42 #if __cplusplus 43 const struct S *operator -(const struct S &s) { return &s; } 44 bool operator ~(const struct S &s) { return (&s) != &s; } 45 #endif 46 47 48 #ifdef INLINE 49 struct S getS() { 50 struct S s = { 42 }; 51 return s; 52 } 53 #else 54 struct S getS(); 55 #endif 56 57 58 void testAssignment() { 59 struct S s = getS(); 60 61 if (s.field != 42) return; 62 clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}} 63 64 s.field = 0; 65 clang_analyzer_eval(s.field == 0); // expected-warning{{TRUE}} 66 67 #if __cplusplus 68 clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}} 69 clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}} 70 clang_analyzer_eval(-s == &s); // expected-warning{{TRUE}} 71 72 clang_analyzer_eval(s.check()); // expected-warning{{TRUE}} 73 clang_analyzer_eval(!s); // expected-warning{{FALSE}} 74 clang_analyzer_eval(~s); // expected-warning{{FALSE}} 75 76 clang_analyzer_eval(*s == 0); // expected-warning{{TRUE}} 77 #endif 78 } 79 80 81 void testImmediateUse() { 82 int x = getS().field; 83 84 if (x != 42) return; 85 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 86 87 #if __cplusplus 88 clang_analyzer_eval((void *)getS().getThis() == (void *)&x); // expected-warning{{FALSE}} 89 clang_analyzer_eval((void *)+getS() == (void *)&x); // expected-warning{{FALSE}} 90 clang_analyzer_eval((void *)-getS() == (void *)&x); // expected-warning{{FALSE}} 91 92 clang_analyzer_eval(getS().check()); // expected-warning{{TRUE}} 93 clang_analyzer_eval(!getS()); // expected-warning{{FALSE}} 94 clang_analyzer_eval(~getS()); // expected-warning{{FALSE}} 95 #endif 96 } 97 98 int getConstrainedField(struct S s) { 99 if (s.field != 42) return 42; 100 return s.field; 101 } 102 103 int getAssignedField(struct S s) { 104 s.field = 42; 105 return s.field; 106 } 107 108 void testArgument() { 109 clang_analyzer_eval(getConstrainedField(getS()) == 42); // expected-warning{{TRUE}} 110 clang_analyzer_eval(getAssignedField(getS()) == 42); // expected-warning{{TRUE}} 111 } 112 113 void testImmediateUseParens() { 114 int x = ((getS())).field; 115 116 if (x != 42) return; 117 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 118 119 clang_analyzer_eval(getConstrainedField(((getS()))) == 42); // expected-warning{{TRUE}} 120 clang_analyzer_eval(getAssignedField(((getS()))) == 42); // expected-warning{{TRUE}} 121 122 #if __cplusplus 123 clang_analyzer_eval(((getS())).check()); // expected-warning{{TRUE}} 124 clang_analyzer_eval(!((getS()))); // expected-warning{{FALSE}} 125 clang_analyzer_eval(~((getS()))); // expected-warning{{FALSE}} 126 #endif 127 } 128 129 130 //-------------------- 131 // C++-only tests 132 //-------------------- 133 134 #if __cplusplus 135 void testReferenceAssignment() { 136 const S &s = getS(); 137 138 if (s.field != 42) return; 139 clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}} 140 141 clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}} 142 clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}} 143 144 clang_analyzer_eval(s.check()); // expected-warning{{TRUE}} 145 clang_analyzer_eval(!s); // expected-warning{{FALSE}} 146 clang_analyzer_eval(~s); // expected-warning{{FALSE}} 147 148 clang_analyzer_eval(*s == 42); // expected-warning{{TRUE}} 149 } 150 151 152 int getConstrainedFieldRef(const S &s) { 153 if (s.field != 42) return 42; 154 return s.field; 155 } 156 157 bool checkThis(const S &s) { 158 return s.getThis() == &s; 159 } 160 161 bool checkThisOp(const S &s) { 162 return +s == &s; 163 } 164 165 bool checkThisStaticOp(const S &s) { 166 return -s == &s; 167 } 168 169 void testReferenceArgument() { 170 clang_analyzer_eval(getConstrainedFieldRef(getS()) == 42); // expected-warning{{TRUE}} 171 clang_analyzer_eval(checkThis(getS())); // expected-warning{{TRUE}} 172 clang_analyzer_eval(checkThisOp(getS())); // expected-warning{{TRUE}} 173 clang_analyzer_eval(checkThisStaticOp(getS())); // expected-warning{{TRUE}} 174 } 175 176 177 int getConstrainedFieldOp(S s) { 178 if (*s != 42) return 42; 179 return *s; 180 } 181 182 int getConstrainedFieldRefOp(const S &s) { 183 if (*s != 42) return 42; 184 return *s; 185 } 186 187 void testImmediateUseOp() { 188 int x = *getS(); 189 if (x != 42) return; 190 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 191 192 clang_analyzer_eval(getConstrainedFieldOp(getS()) == 42); // expected-warning{{TRUE}} 193 clang_analyzer_eval(getConstrainedFieldRefOp(getS()) == 42); // expected-warning{{TRUE}} 194 } 195 196 namespace EmptyClass { 197 struct Base { 198 int& x; 199 200 Base(int& x) : x(x) {} 201 }; 202 203 struct Derived : public Base { 204 Derived(int& x) : Base(x) {} 205 206 void operator=(int a) { x = a; } 207 }; 208 209 Derived ref(int& a) { return Derived(a); } 210 211 // There used to be a warning here, because analyzer treated Derived as empty. 212 int test() { 213 int a; 214 ref(a) = 42; 215 return a; // no warning 216 } 217 } 218 219 #if __cplusplus >= 201703L 220 namespace aggregate_inheritance_cxx17 { 221 struct A { 222 int x; 223 }; 224 225 struct B { 226 int y; 227 }; 228 229 struct C: B { 230 int z; 231 }; 232 233 struct D: A, C { 234 int w; 235 }; 236 237 void foo() { 238 D d{1, 2, 3, 4}; 239 clang_analyzer_eval(d.x == 1); // expected-warning{{TRUE}} 240 clang_analyzer_eval(d.y == 2); // expected-warning{{TRUE}} 241 clang_analyzer_eval(d.z == 3); // expected-warning{{TRUE}} 242 clang_analyzer_eval(d.w == 4); // expected-warning{{TRUE}} 243 } 244 } // namespace aggregate_inheritance_cxx17 245 #endif 246 247 namespace flex_array_inheritance_cxx17 { 248 struct A { 249 int flexible_array[]; 250 }; 251 252 struct B { 253 long cookie; 254 }; 255 256 struct C : B { 257 A a; 258 }; 259 260 void foo() { 261 C c{}; // no-crash 262 } 263 } // namespace flex_array_inheritance_cxx17 264 #endif 265