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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

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