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
6float ceil(float);
7namespace std {
8double ceil(double);
9long double floor(long double);
10} // namespace std
11
12namespace floats {
13
14struct ConvertsToFloat {
15 operator float() const { return 0.5f; }
16};
17
18float operator"" _float(unsigned long long);
19
20void 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
48double operator"" _double(unsigned long long);
49
50float 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
54void narrow_double_to_float_ok(double d) {
55 float f;
56 f = d;
57 f = 15_double;
58}
59
60void 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
75void 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
85void 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
92void 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
118void 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
144void 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
210void 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
221void 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
237void 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
244void 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
256void 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
265void casting_integer_to_bool_is_ok() {
266 int i;
267 while (i) {
268 }
269 for (; i;) {
270 }
271 if (i) {
272 }
273}
274
275void 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
288void legitimate_comparison_do_not_warn(unsigned long long size) {
289 for (int i = 0; i < size; ++i) {
290 }
291}
292
293void 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
307void 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.
323template <typename T1, typename T2>
324void f(T1 one, T2 two) {
325 one += two;
326}
327
328void 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
337void 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.
346void 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

source code of clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/narrowing-conversions.cpp