1// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c %s 2// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ -analyzer-config c++-inlining=constructors %s 3// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c %s 4// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c++ -analyzer-config c++-inlining=constructors %s 5 6void clang_analyzer_eval(int); 7 8struct S { 9 int field; 10 11#if __cplusplus 12 const struct S *getThis() const { return this; } 13 const struct S *operator +() const { return this; } 14 15 bool check() const { return this == this; } 16 bool operator !() const { return this != this; } 17 18 int operator *() const { return field; } 19#endif 20}; 21 22#if __cplusplus 23const struct S *operator -(const struct S &s) { return &s; } 24bool operator ~(const struct S &s) { return (&s) != &s; } 25#endif 26 27 28#ifdef INLINE 29struct S getS() { 30 struct S s = { 42 }; 31 return s; 32} 33#else 34struct S getS(); 35#endif 36 37 38void testAssignment() { 39 struct S s = getS(); 40 41 if (s.field != 42) return; 42 clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}} 43 44 s.field = 0; 45 clang_analyzer_eval(s.field == 0); // expected-warning{{TRUE}} 46 47#if __cplusplus 48 clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}} 49 clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}} 50 clang_analyzer_eval(-s == &s); // expected-warning{{TRUE}} 51 52 clang_analyzer_eval(s.check()); // expected-warning{{TRUE}} 53 clang_analyzer_eval(!s); // expected-warning{{FALSE}} 54 clang_analyzer_eval(~s); // expected-warning{{FALSE}} 55 56 clang_analyzer_eval(*s == 0); // expected-warning{{TRUE}} 57#endif 58} 59 60 61void testImmediateUse() { 62 int x = getS().field; 63 64 if (x != 42) return; 65 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 66 67#if __cplusplus 68 clang_analyzer_eval((void *)getS().getThis() == (void *)&x); // expected-warning{{FALSE}} 69 clang_analyzer_eval((void *)+getS() == (void *)&x); // expected-warning{{FALSE}} 70 clang_analyzer_eval((void *)-getS() == (void *)&x); // expected-warning{{FALSE}} 71 72 clang_analyzer_eval(getS().check()); // expected-warning{{TRUE}} 73 clang_analyzer_eval(!getS()); // expected-warning{{FALSE}} 74 clang_analyzer_eval(~getS()); // expected-warning{{FALSE}} 75#endif 76} 77 78int getConstrainedField(struct S s) { 79 if (s.field != 42) return 42; 80 return s.field; 81} 82 83int getAssignedField(struct S s) { 84 s.field = 42; 85 return s.field; 86} 87 88void testArgument() { 89 clang_analyzer_eval(getConstrainedField(getS()) == 42); // expected-warning{{TRUE}} 90 clang_analyzer_eval(getAssignedField(getS()) == 42); // expected-warning{{TRUE}} 91} 92 93void testImmediateUseParens() { 94 int x = ((getS())).field; 95 96 if (x != 42) return; 97 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 98 99 clang_analyzer_eval(getConstrainedField(((getS()))) == 42); // expected-warning{{TRUE}} 100 clang_analyzer_eval(getAssignedField(((getS()))) == 42); // expected-warning{{TRUE}} 101 102#if __cplusplus 103 clang_analyzer_eval(((getS())).check()); // expected-warning{{TRUE}} 104 clang_analyzer_eval(!((getS()))); // expected-warning{{FALSE}} 105 clang_analyzer_eval(~((getS()))); // expected-warning{{FALSE}} 106#endif 107} 108 109 110//-------------------- 111// C++-only tests 112//-------------------- 113 114#if __cplusplus 115void testReferenceAssignment() { 116 const S &s = getS(); 117 118 if (s.field != 42) return; 119 clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}} 120 121 clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}} 122 clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}} 123 124 clang_analyzer_eval(s.check()); // expected-warning{{TRUE}} 125 clang_analyzer_eval(!s); // expected-warning{{FALSE}} 126 clang_analyzer_eval(~s); // expected-warning{{FALSE}} 127 128 clang_analyzer_eval(*s == 42); // expected-warning{{TRUE}} 129} 130 131 132int getConstrainedFieldRef(const S &s) { 133 if (s.field != 42) return 42; 134 return s.field; 135} 136 137bool checkThis(const S &s) { 138 return s.getThis() == &s; 139} 140 141bool checkThisOp(const S &s) { 142 return +s == &s; 143} 144 145bool checkThisStaticOp(const S &s) { 146 return -s == &s; 147} 148 149void testReferenceArgument() { 150 clang_analyzer_eval(getConstrainedFieldRef(getS()) == 42); // expected-warning{{TRUE}} 151 clang_analyzer_eval(checkThis(getS())); // expected-warning{{TRUE}} 152 clang_analyzer_eval(checkThisOp(getS())); // expected-warning{{TRUE}} 153 clang_analyzer_eval(checkThisStaticOp(getS())); // expected-warning{{TRUE}} 154} 155 156 157int getConstrainedFieldOp(S s) { 158 if (*s != 42) return 42; 159 return *s; 160} 161 162int getConstrainedFieldRefOp(const S &s) { 163 if (*s != 42) return 42; 164 return *s; 165} 166 167void testImmediateUseOp() { 168 int x = *getS(); 169 if (x != 42) return; 170 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 171 172 clang_analyzer_eval(getConstrainedFieldOp(getS()) == 42); // expected-warning{{TRUE}} 173 clang_analyzer_eval(getConstrainedFieldRefOp(getS()) == 42); // expected-warning{{TRUE}} 174} 175 176namespace EmptyClass { 177 struct Base { 178 int& x; 179 180 Base(int& x) : x(x) {} 181 }; 182 183 struct Derived : public Base { 184 Derived(int& x) : Base(x) {} 185 186 void operator=(int a) { x = a; } 187 }; 188 189 Derived ref(int& a) { return Derived(a); } 190 191 // There used to be a warning here, because analyzer treated Derived as empty. 192 int test() { 193 int a; 194 ref(a) = 42; 195 return a; // no warning 196 } 197} 198 199#endif 200