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