xref: /llvm-project/clang/test/Analysis/operator-calls.cpp (revision b032e3ff6121a969b2e90ad7bf493c2d5d7ac3a2)
1 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-output=text -verify %s
2 void clang_analyzer_eval(bool);
3 
4 struct X0 { };
5 bool operator==(const X0&, const X0&);
6 
7 // PR7287
8 struct test { int a[2]; };
9 
t2()10 void t2() {
11   test p = {{1,2}};
12   test q;
13   q = p;
14 }
15 
PR7287(X0 a,X0 b)16 bool PR7287(X0 a, X0 b) {
17   return operator==(a, b);
18 }
19 
20 
21 // Inlining non-static member operators mistakenly treated 'this' as the first
22 // argument for a while.
23 
24 struct IntComparable {
operator ==IntComparable25   bool operator==(int x) const {
26     return x == 0;
27   }
28 };
29 
testMemberOperator(IntComparable B)30 void testMemberOperator(IntComparable B) {
31   clang_analyzer_eval(B == 0); // expected-warning{{TRUE}}
32   // expected-note@-1{{TRUE}}
33 }
34 
35 
36 
37 namespace UserDefinedConversions {
38   class Convertible {
39   public:
operator int() const40     operator int() const {
41       return 42;
42     }
operator bool() const43     operator bool() const {
44       return true;
45     }
46   };
47 
test(const Convertible & obj)48   void test(const Convertible &obj) {
49     clang_analyzer_eval((int)obj == 42); // expected-warning{{TRUE}}
50     // expected-note@-1{{TRUE}}
51     clang_analyzer_eval(obj); // expected-warning{{TRUE}}
52     // expected-note@-1{{TRUE}}
53   }
54 }
55 
56 
57 namespace RValues {
58   struct SmallOpaque {
59     float x;
operator +RValues::SmallOpaque60     int operator +() const {
61       return (int)x;
62     }
63   };
64 
65   struct LargeOpaque {
66     float x[4];
operator +RValues::LargeOpaque67     int operator +() const {
68       return (int)x[0];
69     }
70   };
71 
getSmallOpaque()72   SmallOpaque getSmallOpaque() {
73     SmallOpaque obj;
74     obj.x = 1.0;
75     return obj;
76   }
77 
getLargeOpaque()78   LargeOpaque getLargeOpaque() {
79     LargeOpaque obj = LargeOpaque();
80     obj.x[0] = 1.0;
81     return obj;
82   }
83 
test(int coin)84   void test(int coin) {
85     // Force a cache-out when we try to conjure a temporary region for the operator call.
86     // ...then, don't crash.
87     clang_analyzer_eval(+(coin ? getSmallOpaque() : getSmallOpaque())); // expected-warning{{UNKNOWN}}
88     // expected-note@-1{{Assuming 'coin' is 0}}
89     // expected-note@-2{{'?' condition is false}}
90     // expected-note@-3{{UNKNOWN}}
91     // expected-note@-4{{Assuming 'coin' is 0}}
92     // expected-note@-5{{'?' condition is false}}
93     clang_analyzer_eval(+(coin ? getLargeOpaque() : getLargeOpaque())); // expected-warning{{UNKNOWN}}
94     // expected-note@-1{{'coin' is 0}}
95     // expected-note@-2{{'?' condition is false}}
96     // expected-note@-3{{UNKNOWN}}
97   }
98 }
99 
100 namespace SynthesizedAssignment {
101   struct A {
102     int a;
operator =SynthesizedAssignment::A103     A& operator=(A& other) { a = -other.a; return *this; }
operator =SynthesizedAssignment::A104     A& operator=(A&& other) { a = other.a+1; return *this; }
105   };
106 
107   struct B {
108     int x;
109     A a[3];
110     B& operator=(B&) = default;
111     B& operator=(B&&) = default;
112   };
113 
114   // This used to produce a warning about the iteration variable in the
115   // synthesized assignment operator being undefined.
116   //
117   // Note: The warning we want to avoid can be found in https://bugs.llvm.org/show_bug.cgi?id=16745.
118   // Back in the day, this function was created we couldn't evaluate non-POD type array construction,
119   // so we couldn't evaluate the copy assignment either, hence we didn't detect that a field is
120   // uninitialized.
testNoWarning()121   void testNoWarning() {
122 
123     B v, u;
124     u = v; // expected-warning@110{{Assigned value is garbage or undefined}}
125     // expected-note@-1{{Calling defaulted copy assignment operator for 'B'}}
126     // expected-note@110{{Assigned value is garbage or undefined}}
127   }
128 
testNoWarningMove()129   void testNoWarningMove() {
130     B v, u;
131     u = static_cast<B &&>(v); // expected-warning@111{{Assigned value is garbage or undefined}}
132     // expected-note@-1{{Calling defaulted move assignment operator for 'B'}}
133     // expected-note@111{{Assigned value is garbage or undefined}}
134   }
135 
testConsistency()136   void testConsistency() {
137     B v, u;
138     v.x = 0;
139     v.a[0].a = 24;
140     v.a[1].a = 47;
141     v.a[2].a = 42;
142     u = v;
143     clang_analyzer_eval(u.a[0].a == -24); // expected-warning{{TRUE}}
144     // expected-note@-1{{TRUE}}
145     clang_analyzer_eval(u.a[1].a == -47); // expected-warning{{TRUE}}
146     // expected-note@-1{{TRUE}}
147     clang_analyzer_eval(u.a[2].a == -42); // expected-warning{{TRUE}}
148     // expected-note@-1{{TRUE}}
149   }
150 
testConsistencyMove()151   void testConsistencyMove() {
152     B v, u;
153     v.x = 0;
154     v.a[0].a = 24;
155     v.a[1].a = 47;
156     v.a[2].a = 42;
157     u = static_cast<B &&>(v);
158     clang_analyzer_eval(u.a[0].a == 25); // expected-warning{{TRUE}}
159     // expected-note@-1{{TRUE}}
160     clang_analyzer_eval(u.a[1].a == 48); // expected-warning{{TRUE}}
161     // expected-note@-1{{TRUE}}
162     clang_analyzer_eval(u.a[2].a == 43); // expected-warning{{TRUE}}
163     // expected-note@-1{{TRUE}}
164   }
165 }
166