1 // RUN: %check_clang_tidy %s bugprone-fold-init-type -std=c++17 %t
2
3 namespace std {
4 template <class InputIt, class T>
accumulate(InputIt first,InputIt last,T init)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>
reduce(InputIt first,InputIt last,T init)14 T reduce(InputIt first, InputIt last, T init) { (void)*first; }
15 template <class ExecutionPolicy, class InputIt, class T>
reduce(ExecutionPolicy && policy,InputIt first,InputIt last,T init)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>
inner_product(InputIt1 first1,InputIt1 last1,InputIt2 first2,T value)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>
inner_product(ExecutionPolicy && policy,InputIt1 first1,InputIt1 last1,InputIt2 first2,T value)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 {
operator *AutoByValueTemplateIterator53 auto operator*() const { return ValueType{}; }
54 };
55
56 template <typename ValueType> struct AutoByRefTemplateIterator {
operator *AutoByRefTemplateIterator57 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
accumulatePositive1()69 int accumulatePositive1() {
70 float a[1] = {0.5f};
71 return std::accumulate(a, a + 1, 0);
72 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
73 }
74
accumulatePositive2()75 int accumulatePositive2() {
76 FloatIterator it;
77 return std::accumulate(it, it, 0);
78 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
79 }
80
accumulatePositive3()81 int accumulatePositive3() {
82 DerivedFloatIterator it;
83 return std::accumulate(it, it, 0);
84 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
85 }
86
accumulatePositive4()87 int accumulatePositive4() {
88 double a[1] = {0.0};
89 return std::accumulate(a, a + 1, 0.0f);
90 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'double' into type 'float'
91 }
92
accumulatePositive5()93 int accumulatePositive5() {
94 ByValueTemplateIterator<unsigned> it;
95 return std::accumulate(it, it, 0);
96 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int'
97 }
98
accumulatePositive6()99 int accumulatePositive6() {
100 ByRefTemplateIterator<unsigned> it;
101 return std::accumulate(it, it, 0);
102 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int'
103 }
104
accumulatePositive7()105 int accumulatePositive7() {
106 AutoByValueTemplateIterator<unsigned> it;
107 return std::accumulate(it, it, 0);
108 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int'
109 }
110
accumulatePositive8()111 int accumulatePositive8() {
112 TypedeffedIterator it;
113 return std::accumulate(it, it, 0);
114 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
115 }
116
accumulatePositive9()117 int accumulatePositive9() {
118 InheritingByConstRefTemplateIterator<unsigned> it;
119 return std::accumulate(it, it, 0);
120 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int'
121 }
122
accumulatePositive10()123 int accumulatePositive10() {
124 AutoByRefTemplateIterator<unsigned> it;
125 return std::accumulate(it, it, 0);
126 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int'
127 }
128
accumulatePositive11()129 int accumulatePositive11() {
130 ByRefTemplateIteratorWithAlias<unsigned> it;
131 return std::accumulate(it, it, 0);
132 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int'
133 }
134
reducePositive1()135 int reducePositive1() {
136 float a[1] = {0.5f};
137 return std::reduce(a, a + 1, 0);
138 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
139 }
140
reducePositive2()141 int reducePositive2() {
142 float a[1] = {0.5f};
143 return std::reduce(std::par, a, a + 1, 0);
144 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
145 }
146
innerProductPositive1()147 int innerProductPositive1() {
148 float a[1] = {0.5f};
149 int b[1] = {1};
150 return std::inner_product(std::par, a, a + 1, b, 0);
151 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
152 }
153
innerProductPositive2()154 int innerProductPositive2() {
155 float a[1] = {0.5f};
156 int b[1] = {1};
157 return std::inner_product(std::par, a, a + 1, b, 0);
158 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
159 }
160
161 // Negatives.
162
negative1()163 int negative1() {
164 float a[1] = {0.5f};
165 // This is OK because types match.
166 return std::accumulate(a, a + 1, 0.0);
167 }
168
negative2()169 int negative2() {
170 float a[1] = {0.5f};
171 // This is OK because double is bigger than float.
172 return std::accumulate(a, a + 1, 0.0);
173 }
174
negative3()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>(a, a + 1, 0);
179 }
180
negative4()181 int negative4() {
182 ByValueTemplateIterator<unsigned> it;
183 // For now this is OK.
184 return std::accumulate(it, it, 0.0);
185 }
186
negative5()187 int negative5() {
188 float a[1] = {0.5f};
189 float b[1] = {1.0f};
190 return std::inner_product(std::par, a, a + 1, b, 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
negative5()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