1 | // RUN: %check_clang_tidy %s bugprone-fold-init-type -std=c++17 %t |
2 | |
3 | namespace std { |
4 | template <class InputIt, class T> |
5 | T accumulate(InputIt first, InputIt last, T init) { |
6 | // When `InputIt::operator*` returns a deduced `auto` type that refers to a |
7 | // dependent type, the return type is deduced only if `InputIt::operator*` |
8 | // is instantiated. In practice this happens somewhere in the implementation |
9 | // of `accumulate`. For tests, do it here. |
10 | (void)*first; |
11 | } |
12 | |
13 | template <class InputIt, class T> |
14 | T reduce(InputIt first, InputIt last, T init) { (void)*first; } |
15 | template <class ExecutionPolicy, class InputIt, class T> |
16 | T reduce(ExecutionPolicy &&policy, |
17 | InputIt first, InputIt last, T init) { (void)*first; } |
18 | |
19 | struct parallel_execution_policy {}; |
20 | constexpr parallel_execution_policy par{}; |
21 | |
22 | template <class InputIt1, class InputIt2, class T> |
23 | T inner_product(InputIt1 first1, InputIt1 last1, |
24 | InputIt2 first2, T value) { (void)*first1; (void)*first2; } |
25 | |
26 | template <class ExecutionPolicy, class InputIt1, class InputIt2, class T> |
27 | T inner_product(ExecutionPolicy &&policy, InputIt1 first1, InputIt1 last1, |
28 | InputIt2 first2, T value) { (void)*first1; (void)*first2; } |
29 | |
30 | } // namespace std |
31 | |
32 | struct FloatIterator { |
33 | const float &operator*() const; |
34 | }; |
35 | |
36 | struct DerivedFloatIterator : public FloatIterator { |
37 | }; |
38 | |
39 | template <typename ValueType> struct ByValueTemplateIterator { |
40 | ValueType operator*() const; |
41 | }; |
42 | |
43 | template <typename ValueType> struct ByRefTemplateIterator { |
44 | ValueType &operator*(); |
45 | }; |
46 | |
47 | template <typename ValueType> struct ByRefTemplateIteratorWithAlias { |
48 | using reference = const ValueType&; |
49 | reference operator*(); |
50 | }; |
51 | |
52 | template <typename ValueType> struct AutoByValueTemplateIterator { |
53 | auto operator*() const { return ValueType{}; } |
54 | }; |
55 | |
56 | template <typename ValueType> struct AutoByRefTemplateIterator { |
57 | decltype(auto) operator*() const { return value_; } |
58 | ValueType value_; |
59 | }; |
60 | |
61 | template <typename ValueType> |
62 | struct InheritingByConstRefTemplateIterator |
63 | : public ByRefTemplateIterator<const ValueType> {}; |
64 | |
65 | using TypedeffedIterator = FloatIterator; |
66 | |
67 | // Positives. |
68 | |
69 | int accumulatePositive1() { |
70 | float a[1] = {0.5f}; |
71 | return std::accumulate(first: a, last: a + 1, init: 0); |
72 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int' |
73 | } |
74 | |
75 | int accumulatePositive2() { |
76 | FloatIterator it; |
77 | return std::accumulate(first: it, last: it, init: 0); |
78 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int' |
79 | } |
80 | |
81 | int accumulatePositive3() { |
82 | DerivedFloatIterator it; |
83 | return std::accumulate(first: it, last: it, init: 0); |
84 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int' |
85 | } |
86 | |
87 | int accumulatePositive4() { |
88 | double a[1] = {0.0}; |
89 | return std::accumulate(first: a, last: a + 1, init: 0.0f); |
90 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'double' into type 'float' |
91 | } |
92 | |
93 | int accumulatePositive5() { |
94 | ByValueTemplateIterator<unsigned> it; |
95 | return std::accumulate(first: it, last: it, init: 0); |
96 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int' |
97 | } |
98 | |
99 | int accumulatePositive6() { |
100 | ByRefTemplateIterator<unsigned> it; |
101 | return std::accumulate(first: it, last: it, init: 0); |
102 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int' |
103 | } |
104 | |
105 | int accumulatePositive7() { |
106 | AutoByValueTemplateIterator<unsigned> it; |
107 | return std::accumulate(first: it, last: it, init: 0); |
108 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int' |
109 | } |
110 | |
111 | int accumulatePositive8() { |
112 | TypedeffedIterator it; |
113 | return std::accumulate(first: it, last: it, init: 0); |
114 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int' |
115 | } |
116 | |
117 | int accumulatePositive9() { |
118 | InheritingByConstRefTemplateIterator<unsigned> it; |
119 | return std::accumulate(first: it, last: it, init: 0); |
120 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int' |
121 | } |
122 | |
123 | int accumulatePositive10() { |
124 | AutoByRefTemplateIterator<unsigned> it; |
125 | return std::accumulate(first: it, last: it, init: 0); |
126 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int' |
127 | } |
128 | |
129 | int accumulatePositive11() { |
130 | ByRefTemplateIteratorWithAlias<unsigned> it; |
131 | return std::accumulate(first: it, last: it, init: 0); |
132 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int' |
133 | } |
134 | |
135 | int reducePositive1() { |
136 | float a[1] = {0.5f}; |
137 | return std::reduce(first: a, last: a + 1, init: 0); |
138 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int' |
139 | } |
140 | |
141 | int reducePositive2() { |
142 | float a[1] = {0.5f}; |
143 | return std::reduce(policy: std::par, first: a, last: a + 1, init: 0); |
144 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int' |
145 | } |
146 | |
147 | int innerProductPositive1() { |
148 | float a[1] = {0.5f}; |
149 | int b[1] = {1}; |
150 | return std::inner_product(policy: std::par, first1: a, last1: a + 1, first2: b, value: 0); |
151 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int' |
152 | } |
153 | |
154 | int innerProductPositive2() { |
155 | float a[1] = {0.5f}; |
156 | int b[1] = {1}; |
157 | return std::inner_product(policy: std::par, first1: a, last1: a + 1, first2: b, value: 0); |
158 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int' |
159 | } |
160 | |
161 | // Negatives. |
162 | |
163 | int negative1() { |
164 | float a[1] = {0.5f}; |
165 | // This is OK because types match. |
166 | return std::accumulate(first: a, last: a + 1, init: 0.0); |
167 | } |
168 | |
169 | int negative2() { |
170 | float a[1] = {0.5f}; |
171 | // This is OK because double is bigger than float. |
172 | return std::accumulate(first: a, last: a + 1, init: 0.0); |
173 | } |
174 | |
175 | int negative3() { |
176 | float a[1] = {0.5f}; |
177 | // This is OK because the user explicitly specified T. |
178 | return std::accumulate<float *, float>(first: a, last: a + 1, init: 0); |
179 | } |
180 | |
181 | int negative4() { |
182 | ByValueTemplateIterator<unsigned> it; |
183 | // For now this is OK. |
184 | return std::accumulate(first: it, last: it, init: 0.0); |
185 | } |
186 | |
187 | int negative5() { |
188 | float a[1] = {0.5f}; |
189 | float b[1] = {1.0f}; |
190 | return std::inner_product(policy: std::par, first1: a, last1: a + 1, first2: b, value: 0.0f); |
191 | } |
192 | |
193 | namespace blah { |
194 | namespace std { |
195 | template <class InputIt, class T> |
196 | T accumulate(InputIt, InputIt, T); // We should not care about this one. |
197 | } |
198 | |
199 | int negative5() { |
200 | float a[1] = {0.5f}; |
201 | // Note that this is using blah::std::accumulate. |
202 | return std::accumulate(a, a + 1, 0); |
203 | } |
204 | } |
205 | |