1// RUN: %check_clang_tidy %s bugprone-fold-init-type -std=c++17 %t
2
3namespace std {
4template <class InputIt, class T>
5T 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
13template <class InputIt, class T>
14T reduce(InputIt first, InputIt last, T init) { (void)*first; }
15template <class ExecutionPolicy, class InputIt, class T>
16T reduce(ExecutionPolicy &&policy,
17 InputIt first, InputIt last, T init) { (void)*first; }
18
19struct parallel_execution_policy {};
20constexpr parallel_execution_policy par{};
21
22template <class InputIt1, class InputIt2, class T>
23T inner_product(InputIt1 first1, InputIt1 last1,
24 InputIt2 first2, T value) { (void)*first1; (void)*first2; }
25
26template <class ExecutionPolicy, class InputIt1, class InputIt2, class T>
27T inner_product(ExecutionPolicy &&policy, InputIt1 first1, InputIt1 last1,
28 InputIt2 first2, T value) { (void)*first1; (void)*first2; }
29
30} // namespace std
31
32struct FloatIterator {
33 const float &operator*() const;
34};
35
36struct DerivedFloatIterator : public FloatIterator {
37};
38
39template <typename ValueType> struct ByValueTemplateIterator {
40 ValueType operator*() const;
41};
42
43template <typename ValueType> struct ByRefTemplateIterator {
44 ValueType &operator*();
45};
46
47template <typename ValueType> struct ByRefTemplateIteratorWithAlias {
48 using reference = const ValueType&;
49 reference operator*();
50};
51
52template <typename ValueType> struct AutoByValueTemplateIterator {
53 auto operator*() const { return ValueType{}; }
54};
55
56template <typename ValueType> struct AutoByRefTemplateIterator {
57 decltype(auto) operator*() const { return value_; }
58 ValueType value_;
59};
60
61template <typename ValueType>
62struct InheritingByConstRefTemplateIterator
63 : public ByRefTemplateIterator<const ValueType> {};
64
65using TypedeffedIterator = FloatIterator;
66
67// Positives.
68
69int 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
75int 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
81int 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
87int 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
93int 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
99int 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
105int 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
111int 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
117int 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
123int 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
129int 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
135int 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
141int 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
147int 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
154int 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
163int 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
169int 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
175int 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
181int negative4() {
182 ByValueTemplateIterator<unsigned> it;
183 // For now this is OK.
184 return std::accumulate(first: it, last: it, init: 0.0);
185}
186
187int 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
193namespace blah {
194namespace std {
195template <class InputIt, class T>
196T accumulate(InputIt, InputIt, T); // We should not care about this one.
197}
198
199int 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

source code of clang-tools-extra/test/clang-tidy/checkers/bugprone/fold-init-type.cpp