1 | // RUN: %check_clang_tidy %s cppcoreguidelines-narrowing-conversions %t \ |
2 | // RUN: -config="{CheckOptions: { \ |
3 | // RUN: cppcoreguidelines-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' [cppcoreguidelines-narrowing-conversions] |
24 | i = 0.5f; |
25 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from constant 'float' to 'int' [cppcoreguidelines-narrowing-conversions] |
26 | i = static_cast<float>(d); |
27 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions] |
28 | i = ConvertsToFloat(); |
29 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions] |
30 | i = 15_float; |
31 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions] |
32 | i += d; |
33 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions] |
34 | i += 0.5; |
35 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'double' to 'int' [cppcoreguidelines-narrowing-conversions] |
36 | i += 0.5f; |
37 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'float' to 'int' [cppcoreguidelines-narrowing-conversions] |
38 | i *= 0.5f; |
39 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'float' to 'int' [cppcoreguidelines-narrowing-conversions] |
40 | i /= 0.5f; |
41 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'float' to 'int' [cppcoreguidelines-narrowing-conversions] |
42 | i += (double)0.5f; |
43 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'double' to 'int' [cppcoreguidelines-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' [cppcoreguidelines-narrowing-conversions] |
88 | bool b2 = 1.0f; |
89 | // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: narrowing conversion from constant 'float' to 'bool' [cppcoreguidelines-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' [cppcoreguidelines-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' [cppcoreguidelines-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' [cppcoreguidelines-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' [cppcoreguidelines-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 [cppcoreguidelines-narrowing-conversions] |
160 | c = i; |
161 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'int' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions] |
162 | c = l; |
163 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'long' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions] |
164 | c = ll; |
165 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'long long' to signed type 'char' is implementation-defined [cppcoreguidelines-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 [cppcoreguidelines-narrowing-conversions] |
169 | c = us; |
170 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned short' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions] |
171 | c = ui; |
172 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned int' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions] |
173 | c = ul; |
174 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned long' to signed type 'char' is implementation-defined [cppcoreguidelines-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 [cppcoreguidelines-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 [cppcoreguidelines-narrowing-conversions] |
183 | i = ll; |
184 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'long long' to signed type 'int' is implementation-defined [cppcoreguidelines-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 [cppcoreguidelines-narrowing-conversions] |
190 | i = ul; |
191 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned long' to signed type 'int' is implementation-defined [cppcoreguidelines-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 [cppcoreguidelines-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 [cppcoreguidelines-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 [cppcoreguidelines-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 [cppcoreguidelines-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 [cppcoreguidelines-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 [cppcoreguidelines-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 [cppcoreguidelines-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 [cppcoreguidelines-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 [cppcoreguidelines-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 [cppcoreguidelines-narrowing-conversions] |
253 | // CHECK-MESSAGES: :[[@LINE-2]]:37: warning: narrowing conversion from 'unsigned long long' to signed type 'long long' is implementation-defined [cppcoreguidelines-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' [cppcoreguidelines-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' [cppcoreguidelines-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' [cppcoreguidelines-narrowing-conversions] |
279 | } |
280 | for (; f;) { |
281 | // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: narrowing conversion from 'float' to 'bool' [cppcoreguidelines-narrowing-conversions] |
282 | } |
283 | if (f) { |
284 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'bool' [cppcoreguidelines-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(one: 1, two: 2); |
330 | f(one: 1, two: .5f); |
331 | f(one: 1, two: .5); |
332 | f(one: 1, two: .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 [cppcoreguidelines-narrowing-conversions] |
356 | } |
357 | |
358 | } // namespace floats |
359 | |