xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/bugprone/narrowing-conversions.cpp (revision e45e091b90896023584b303539bd8ae16d8932b3)
1 // RUN: %check_clang_tidy %s bugprone-narrowing-conversions %t \
2 // RUN: -config="{CheckOptions: { \
3 // RUN:   bugprone-narrowing-conversions.WarnOnFloatingPointNarrowingConversion: false}}" \
4 // RUN: -- -target x86_64-unknown-linux -fsigned-char
5 
6 float ceil(float);
7 namespace std {
8 double ceil(double);
9 long double floor(long double);
10 } // namespace std
11 
12 namespace floats {
13 
14 struct ConvertsToFloat {
15   operator float() const { return 0.5f; }
16 };
17 
18 float operator"" _float(unsigned long long);
19 
20 void narrow_fp_to_int_not_ok(double d) {
21   int i = 0;
22   i = d;
23   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'double' to 'int' [bugprone-narrowing-conversions]
24   i = 0.5f;
25   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from constant 'float' to 'int' [bugprone-narrowing-conversions]
26   i = static_cast<float>(d);
27   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [bugprone-narrowing-conversions]
28   i = ConvertsToFloat();
29   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [bugprone-narrowing-conversions]
30   i = 15_float;
31   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [bugprone-narrowing-conversions]
32   i += d;
33   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'double' to 'int' [bugprone-narrowing-conversions]
34   i += 0.5;
35   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'double' to 'int' [bugprone-narrowing-conversions]
36   i += 0.5f;
37   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'float' to 'int' [bugprone-narrowing-conversions]
38   i *= 0.5f;
39   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'float' to 'int' [bugprone-narrowing-conversions]
40   i /= 0.5f;
41   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'float' to 'int' [bugprone-narrowing-conversions]
42   i += (double)0.5f;
43   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'double' to 'int' [bugprone-narrowing-conversions]
44   i += 2.0;
45   i += 2.0f;
46 }
47 
48 double operator"" _double(unsigned long long);
49 
50 float narrow_double_to_float_return() {
51   return 0.5; // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
52 }
53 
54 void narrow_double_to_float_ok(double d) {
55   float f;
56   f = d;
57   f = 15_double;
58 }
59 
60 void narrow_fp_constants() {
61   float f;
62   f = 0.5; // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
63 
64   f = __builtin_huge_valf();  // max float is not narrowing.
65   f = -__builtin_huge_valf(); // -max float is not narrowing.
66   f = __builtin_inff();       // float infinity is not narrowing.
67   f = __builtin_nanf("0");    // float NaN is not narrowing.
68 
69   f = __builtin_huge_val();  // max double is not within-range of float.
70   f = -__builtin_huge_val(); // -max double is not within-range of float.
71   f = __builtin_inf();       // double infinity is not within-range of float.
72   f = __builtin_nan("0");    // double NaN is not narrowing.
73 }
74 
75 void narrow_double_to_float_not_ok_binary_ops(double d) {
76   float f;
77   f += 0.5;          // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
78   f += 2.0;          // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
79   f *= 0.5;          // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
80   f /= 0.5;          // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
81   f += (double)0.5f; // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
82   f += d;            // We do not warn about floating point narrowing by default.
83 }
84 
85 void narrow_fp_constant_to_bool_not_ok() {
86   bool b1 = 1.0;
87   // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: narrowing conversion from constant 'double' to 'bool' [bugprone-narrowing-conversions]
88   bool b2 = 1.0f;
89   // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: narrowing conversion from constant 'float' to 'bool' [bugprone-narrowing-conversions]
90 }
91 
92 void narrow_integer_to_floating() {
93   {
94     long long ll; // 64 bits
95     float f = ll; // doesn't fit in 24 bits
96     // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: narrowing conversion from 'long long' to 'float' [bugprone-narrowing-conversions]
97     double d = ll; // doesn't fit in 53 bits.
98     // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: narrowing conversion from 'long long' to 'double' [bugprone-narrowing-conversions]
99   }
100   {
101     int i;       // 32 bits
102     float f = i; // doesn't fit in 24 bits
103     // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: narrowing conversion from 'int' to 'float' [bugprone-narrowing-conversions]
104     double d = i; // fits in 53 bits.
105   }
106   {
107     short n1, n2;
108     float f = n1 + n2; // 'n1 + n2' is of type 'int' because of integer rules
109     // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: narrowing conversion from 'int' to 'float' [bugprone-narrowing-conversions]
110   }
111   {
112     short s;      // 16 bits
113     float f = s;  // fits in 24 bits
114     double d = s; // fits in 53 bits.
115   }
116 }
117 
118 void narrow_integer_to_unsigned_integer_is_ok() {
119   char c;
120   short s;
121   int i;
122   long l;
123   long long ll;
124 
125   unsigned char uc;
126   unsigned short us;
127   unsigned int ui;
128   unsigned long ul;
129   unsigned long long ull;
130 
131   ui = c;
132   uc = s;
133   uc = i;
134   uc = l;
135   uc = ll;
136 
137   uc = uc;
138   uc = us;
139   uc = ui;
140   uc = ul;
141   uc = ull;
142 }
143 
144 void narrow_integer_to_signed_integer_is_not_ok() {
145   char c;
146   short s;
147   int i;
148   long l;
149   long long ll;
150 
151   unsigned char uc;
152   unsigned short us;
153   unsigned int ui;
154   unsigned long ul;
155   unsigned long long ull;
156 
157   c = c;
158   c = s;
159   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'short' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
160   c = i;
161   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'int' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
162   c = l;
163   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'long' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
164   c = ll;
165   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'long long' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
166 
167   c = uc;
168   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned char' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
169   c = us;
170   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned short' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
171   c = ui;
172   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned int' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
173   c = ul;
174   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned long' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
175   c = ull;
176   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned long long' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
177 
178   i = c;
179   i = s;
180   i = i;
181   i = l;
182   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'long' to signed type 'int' is implementation-defined [bugprone-narrowing-conversions]
183   i = ll;
184   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'long long' to signed type 'int' is implementation-defined [bugprone-narrowing-conversions]
185 
186   i = uc;
187   i = us;
188   i = ui;
189   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned int' to signed type 'int' is implementation-defined [bugprone-narrowing-conversions]
190   i = ul;
191   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned long' to signed type 'int' is implementation-defined [bugprone-narrowing-conversions]
192   i = ull;
193   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned long long' to signed type 'int' is implementation-defined [bugprone-narrowing-conversions]
194 
195   ll = c;
196   ll = s;
197   ll = i;
198   ll = l;
199   ll = ll;
200 
201   ll = uc;
202   ll = us;
203   ll = ui;
204   ll = ul;
205   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'unsigned long' to signed type 'long long' is implementation-defined [bugprone-narrowing-conversions]
206   ll = ull;
207   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'unsigned long long' to signed type 'long long' is implementation-defined [bugprone-narrowing-conversions]
208 }
209 
210 void narrow_constant_to_unsigned_integer_is_ok() {
211   unsigned char uc1 = 0;
212   unsigned char uc2 = 255;
213   unsigned char uc3 = -1;  // unsigned dst type is well defined.
214   unsigned char uc4 = 256; // unsigned dst type is well defined.
215   unsigned short us1 = 0;
216   unsigned short us2 = 65535;
217   unsigned short us3 = -1;    // unsigned dst type is well defined.
218   unsigned short us4 = 65536; // unsigned dst type is well defined.
219 }
220 
221 void narrow_constant_to_signed_integer_is_not_ok() {
222   char c1 = -128;
223   char c2 = 127;
224   char c3 = -129;
225   // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: narrowing conversion from constant value -129 (0xFFFFFF7F) of type 'int' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
226   char c4 = 128;
227   // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: narrowing conversion from constant value 128 (0x00000080) of type 'int' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
228 
229   short s1 = -32768;
230   short s2 = 32767;
231   short s3 = -32769;
232   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: narrowing conversion from constant value -32769 (0xFFFF7FFF) of type 'int' to signed type 'short' is implementation-defined [bugprone-narrowing-conversions]
233   short s4 = 32768;
234   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: narrowing conversion from constant value 32768 (0x00008000) of type 'int' to signed type 'short' is implementation-defined [bugprone-narrowing-conversions]
235 }
236 
237 void narrow_conditional_operator_contant_to_unsigned_is_ok(bool b) {
238   // conversion to unsigned dst type is well defined.
239   unsigned char c1 = b ? 1 : 0;
240   unsigned char c2 = b ? 1 : 256;
241   unsigned char c3 = b ? -1 : 0;
242 }
243 
244 void narrow_conditional_operator_contant_to_signed_is_not_ok(bool b) {
245   char uc1 = b ? 1 : 0;
246   char uc2 = b ? 1 : 128;
247   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: narrowing conversion from constant value 128 (0x00000080) of type 'int' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
248   char uc3 = b ? -129 : 0;
249   // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: narrowing conversion from constant value -129 (0xFFFFFF7F) of type 'int' to signed type 'char' is implementation-defined [bugprone-narrowing-conversions]
250   unsigned long long ysize;
251   long long mirror = b ? -1 : ysize - 1;
252   // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: narrowing conversion from constant value 18446744073709551615 (0xFFFFFFFFFFFFFFFF) of type 'unsigned long long' to signed type 'long long' is implementation-defined [bugprone-narrowing-conversions]
253   // CHECK-MESSAGES: :[[@LINE-2]]:37: warning: narrowing conversion from 'unsigned long long' to signed type 'long long' is implementation-defined [bugprone-narrowing-conversions]
254 }
255 
256 void narrow_constant_to_floating_point() {
257   float f_ok = 1ULL << 24;              // fits in 24 bits mantissa.
258   float f_not_ok = (1ULL << 24) + 1ULL; // doesn't fit in 24 bits mantissa.
259   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: narrowing conversion from constant value 16777217 of type 'unsigned long long' to 'float' [bugprone-narrowing-conversions]
260   double d_ok = 1ULL << 53;              // fits in 53 bits mantissa.
261   double d_not_ok = (1ULL << 53) + 1ULL; // doesn't fit in 53 bits mantissa.
262   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: narrowing conversion from constant value 9007199254740993 of type 'unsigned long long' to 'double' [bugprone-narrowing-conversions]
263 }
264 
265 void casting_integer_to_bool_is_ok() {
266   int i;
267   while (i) {
268   }
269   for (; i;) {
270   }
271   if (i) {
272   }
273 }
274 
275 void casting_float_to_bool_is_not_ok() {
276   float f;
277   while (f) {
278     // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: narrowing conversion from 'float' to 'bool' [bugprone-narrowing-conversions]
279   }
280   for (; f;) {
281     // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: narrowing conversion from 'float' to 'bool' [bugprone-narrowing-conversions]
282   }
283   if (f) {
284     // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'bool' [bugprone-narrowing-conversions]
285   }
286 }
287 
288 void legitimate_comparison_do_not_warn(unsigned long long size) {
289   for (int i = 0; i < size; ++i) {
290   }
291 }
292 
293 void ok(double d) {
294   int i = 0;
295   i = 1;
296   i = static_cast<int>(0.5);
297   i = static_cast<int>(d);
298   i = std::ceil(0.5);
299   i = ::std::floor(0.5);
300   {
301     using std::ceil;
302     i = ceil(0.5f);
303   }
304   i = ceil(0.5f);
305 }
306 
307 void ok_binary_ops(double d) {
308   int i = 0;
309   i += 1;
310   i += static_cast<int>(0.5);
311   i += static_cast<int>(d);
312   i += (int)d;
313   i += std::ceil(0.5);
314   i += ::std::floor(0.5);
315   {
316     using std::ceil;
317     i += ceil(0.5f);
318   }
319   i += ceil(0.5f);
320 }
321 
322 // We're bailing out in templates and macros.
323 template <typename T1, typename T2>
324 void f(T1 one, T2 two) {
325   one += two;
326 }
327 
328 void template_context() {
329   f(1, 2);
330   f(1, .5f);
331   f(1, .5);
332   f(1, .5l);
333 }
334 
335 #define DERP(i, j) (i += j)
336 
337 void macro_context() {
338   int i = 0;
339   DERP(i, 2);
340   DERP(i, .5f);
341   DERP(i, .5);
342   DERP(i, .5l);
343 }
344 
345 // We understand typedefs.
346 void typedef_context() {
347   typedef long long myint64_t;
348   int i;
349   myint64_t i64;
350 
351   i64 = i64; // Okay, no conversion.
352   i64 = i;   // Okay, no narrowing.
353 
354   i = i64;
355   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'myint64_t' (aka 'long long') to signed type 'int' is implementation-defined [bugprone-narrowing-conversions]
356 }
357 
358 } // namespace floats
359