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 347 348 349 350 351 352 353 354 355 356 357 358 359
|
// RUN: %check_clang_tidy %s cppcoreguidelines-narrowing-conversions %t \
// RUN: -config="{CheckOptions: [ \
// RUN: {key: "cppcoreguidelines-narrowing-conversions.WarnOnFloatingPointNarrowingConversion", value: false}, \
// 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);
}
// We understand typedefs.
void typedef_context() {
typedef long long myint64_t;
int i;
myint64_t i64;
i64 = i64; // Okay, no conversion.
i64 = i; // Okay, no narrowing.
i = i64;
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'myint64_t' (aka 'long long') to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
}
} // namespace floats
|