xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/bugprone/fold-init-type.cpp (revision 1012677284b87091f76542c3c79da641101578ae)
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