module AdLint::Cc1::UsualArithmeticTypeConversion

Host class of this module must include StandardTypeCatalogAccessor.

Public Instance Methods

do_usual_arithmetic_type_conversion(lhs, rhs) click to toggle source
# File lib/adlint/cc1/conv.rb, line 145
def do_usual_arithmetic_type_conversion(lhs, rhs)
  # NOTE: The ISO C99 standard says;
  #
  # 6.3.1.8 Usual arithmetic conversions
  #
  # 1 Many operators that except operands of arithmetic type cause
  #   conversions and yield result types in a similar way.  The purpose is
  #   to determine a common real type for the operands and result.  For the
  #   specified operands, each operand is converted, without change of type
  #   domain, to a type whose corresponding real type is the common real
  #   type.  Unless explicitly stated otherwise, the common real type is
  #   also the corresponding real type of the result, whose type domain is
  #   the type domain of the operands if they are the same, and complex
  #   otherwise.  This pattern is called the usual arithmetic conversions:
  #
  #     First, if the corresponding real type of either operand is long
  #     double, the other operand is converted, without change of type
  #     domain, to a type whose corresponding real type is long double.
  #
  #     Otherwise, if the corresponding real type of either operand is
  #     double, the other operand is converted, without change of type
  #     domain, to a type whose corresponding real type is double.
  #
  #     Otherwise, if the corresponding real type of either operand is
  #     float, the other operand is converted, without change of type
  #     domain, to a type whose corresponding real type is float.
  #
  #     Otherwise, the integer promotions are performed on both operands.
  #     Then the following rules are applied to the promoted operands:
  #
  #       If both operands have the same type, then no further conversion
  #       is needed.
  #
  #       Otherwise, if both operands have signed integer types or both
  #       have unsigned integer types, the operand with the type of lesser
  #       integer conversion rank is converted to the type of the operand
  #       with greater rank.
  #
  #       Otherwise, if the operand that has unsigned integer type has rank
  #       greater or equal to the rank of the type of the other operand,
  #       then the operand with signed integer type is converted to the
  #       type of the operand with unsigned integer type.
  #
  #       Otherwise, if the type of the operand with signed integer type
  #       can represent all of the values of the type of the operand with
  #       unsigned integer type, then the operand with unsigned integer
  #       type is converted to the type of the operand with signed integer
  #       type.
  #
  #       Otherwise, both operands are converted to the unsigned integer
  #       type corresponding to the type of the operand with signed integer
  #       type.

  if lhs.same_as?(long_double_t) || rhs.same_as?(long_double_t)
    return long_double_t
  end

  if lhs.same_as?(double_t) || rhs.same_as?(double_t)
    return double_t
  end

  if lhs.same_as?(float_t) || rhs.same_as?(float_t)
    return float_t
  end

  lhs_promoted = lhs.integer_promoted_type
  rhs_promoted = rhs.integer_promoted_type

  return lhs_promoted if lhs_promoted.same_as?(rhs_promoted)

  lhs_rank = lhs_promoted.integer_conversion_rank
  rhs_rank = rhs_promoted.integer_conversion_rank

  case
  when lhs_promoted.signed? && rhs_promoted.signed?
    return lhs_rank < rhs_rank ? rhs_promoted : lhs_promoted
  when lhs_promoted.unsigned? && rhs_promoted.unsigned?
    return lhs_rank < rhs_rank ? rhs_promoted : lhs_promoted
  when lhs_promoted.unsigned? && lhs_rank >= rhs_rank
    return lhs_promoted
  when rhs_promoted.unsigned? && lhs_rank <= rhs_rank
    return rhs_promoted
  when lhs_promoted.signed? && rhs_promoted.compatible?(lhs_promoted)
    return lhs_promoted
  when rhs_promoted.signed? && lhs_promoted.compatible?(rhs_promoted)
    return rhs_promoted
  when lhs_promoted.signed?
    return lhs_promoted.corresponding_unsigned_type
  when rhs_promoted.signed?
    return rhs_promoted.corresponding_unsigned_type
  end

  raise TypeError, "cannot do usual arithmetic conversion."
end