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