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