| // 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 |