1 // RUN: %check_clang_tidy %s bugprone-fold-init-type %t
2 
3 namespace std {
4 template <class InputIt, class T>
5 T accumulate(InputIt first, InputIt last, T init);
6 
7 template <class InputIt, class T>
8 T reduce(InputIt first, InputIt last, T init);
9 template <class ExecutionPolicy, class InputIt, class T>
10 T reduce(ExecutionPolicy &&policy,
11          InputIt first, InputIt last, T init);
12 
13 struct parallel_execution_policy {};
14 constexpr parallel_execution_policy par{};
15 
16 template <class InputIt1, class InputIt2, class T>
17 T inner_product(InputIt1 first1, InputIt1 last1,
18                 InputIt2 first2, T value);
19 
20 template <class ExecutionPolicy, class InputIt1, class InputIt2, class T>
21 T inner_product(ExecutionPolicy &&policy, InputIt1 first1, InputIt1 last1,
22                 InputIt2 first2, T value);
23 
24 } // namespace std
25 
26 struct FloatIterator {
27   typedef float value_type;
28 };
29 template <typename ValueType>
30 struct TypedefTemplateIterator { typedef ValueType value_type; };
31 template <typename ValueType>
32 struct UsingTemplateIterator { using value_type = ValueType; };
33 template <typename ValueType>
34 struct DependentTypedefTemplateIterator { typedef typename ValueType::value_type value_type; };
35 template <typename ValueType>
36 struct DependentUsingTemplateIterator : public TypedefTemplateIterator<ValueType> { using typename TypedefTemplateIterator<ValueType>::value_type; };
37 using TypedeffedIterator = FloatIterator;
38 
39 // Positives.
40 
accumulatePositive1()41 int accumulatePositive1() {
42   float a[1] = {0.5f};
43   return std::accumulate(a, a + 1, 0);
44   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
45 }
46 
accumulatePositive2()47 int accumulatePositive2() {
48   FloatIterator it;
49   return std::accumulate(it, it, 0);
50   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
51 }
52 
accumulatePositive3()53 int accumulatePositive3() {
54   double a[1] = {0.0};
55   return std::accumulate(a, a + 1, 0.0f);
56   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'double' into type 'float'
57 }
58 
accumulatePositive4()59 int accumulatePositive4() {
60   TypedefTemplateIterator<unsigned> it;
61   return std::accumulate(it, it, 0);
62   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int'
63 }
64 
accumulatePositive5()65 int accumulatePositive5() {
66   UsingTemplateIterator<unsigned> it;
67   return std::accumulate(it, it, 0);
68   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int'
69 }
70 
accumulatePositive6()71 int accumulatePositive6() {
72   DependentTypedefTemplateIterator<UsingTemplateIterator<unsigned>> it;
73   return std::accumulate(it, it, 0);
74   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int'
75 }
76 
accumulatePositive7()77 int accumulatePositive7() {
78   TypedeffedIterator it;
79   return std::accumulate(it, it, 0);
80   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
81 }
82 
accumulatePositive8()83 int accumulatePositive8() {
84   DependentUsingTemplateIterator<unsigned> it;
85   return std::accumulate(it, it, 0);
86   // FIXME: this one should trigger too.
87 }
88 
reducePositive1()89 int reducePositive1() {
90   float a[1] = {0.5f};
91   return std::reduce(a, a + 1, 0);
92   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
93 }
94 
reducePositive2()95 int reducePositive2() {
96   float a[1] = {0.5f};
97   return std::reduce(std::par, a, a + 1, 0);
98   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
99 }
100 
innerProductPositive1()101 int innerProductPositive1() {
102   float a[1] = {0.5f};
103   int b[1] = {1};
104   return std::inner_product(std::par, a, a + 1, b, 0);
105   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
106 }
107 
innerProductPositive2()108 int innerProductPositive2() {
109   float a[1] = {0.5f};
110   int b[1] = {1};
111   return std::inner_product(std::par, a, a + 1, b, 0);
112   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
113 }
114 
115 // Negatives.
116 
negative1()117 int negative1() {
118   float a[1] = {0.5f};
119   // This is OK because types match.
120   return std::accumulate(a, a + 1, 0.0);
121 }
122 
negative2()123 int negative2() {
124   float a[1] = {0.5f};
125   // This is OK because double is bigger than float.
126   return std::accumulate(a, a + 1, 0.0);
127 }
128 
negative3()129 int negative3() {
130   float a[1] = {0.5f};
131   // This is OK because the user explicitly specified T.
132   return std::accumulate<float *, float>(a, a + 1, 0);
133 }
134 
negative4()135 int negative4() {
136   TypedefTemplateIterator<unsigned> it;
137   // For now this is OK.
138   return std::accumulate(it, it, 0.0);
139 }
140 
negative5()141 int negative5() {
142   float a[1] = {0.5f};
143   float b[1] = {1.0f};
144   return std::inner_product(std::par, a, a + 1, b, 0.0f);
145 }
146 
147 namespace blah {
148 namespace std {
149 template <class InputIt, class T>
150 T accumulate(InputIt, InputIt, T); // We should not care about this one.
151 }
152 
negative5()153 int negative5() {
154   float a[1] = {0.5f};
155   // Note that this is using blah::std::accumulate.
156   return std::accumulate(a, a + 1, 0);
157 }
158 }
159