Module: AdLint::Cc1::UsualArithmeticTypeConversion

Included in:
ScalarDataType
Defined in:
lib/adlint/cc1/conv.rb

Overview

Host class of this module must include StandardTypeCatalogAccessor.

Instance Method Summary collapse

Instance Method Details

#do_usual_arithmetic_type_conversion(lhs, rhs) ⇒ Object

Raises:

  • (TypeError)


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