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