forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			347 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			347 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
// 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
 |