@@ -188,13 +188,23 @@ static bool cast_numbers(Expr **pLhs, Expr **pRhs, bool make_int) {
188188 enum FixnumKind rkind = rtype -> fixnum .kind ;
189189 bool changed = false;
190190 if (ltype -> fixnum .kind >= FX_ENUM ) {
191- ltype = & tyInt ;
192- lkind = FX_INT ;
191+ if (make_int ) {
192+ ltype = & tyInt ;
193+ lkind = FX_INT ;
194+ } else {
195+ ltype = get_fixnum_type_from_size (type_size (ltype ));
196+ lkind = ltype -> fixnum .kind ;
197+ }
193198 changed = true;
194199 }
195200 if (rtype -> fixnum .kind >= FX_ENUM ) {
196- rtype = & tyInt ;
197- rkind = FX_INT ;
201+ if (make_int ) {
202+ rtype = & tyInt ;
203+ rkind = FX_INT ;
204+ } else {
205+ rtype = get_fixnum_type_from_size (type_size (rtype ));
206+ rkind = rtype -> fixnum .kind ;
207+ }
198208 changed = true;
199209 }
200210
@@ -1179,6 +1189,7 @@ Expr *make_expr_cmp(enum ExprKind kind, const Token *tok, Expr *lhs, Expr *rhs)
11791189 {
11801190 Type * lt = lhs -> type , * rt = rhs -> type ;
11811191 if (is_number (lt ) && is_number (rt )) {
1192+ bool make_int = false;
11821193 if (is_fixnum (lt ) && is_fixnum (rt )) {
11831194 if (lc || rc ) {
11841195 Expr * * pLhs = & lhs , * * pRhs = & rhs ;
@@ -1197,14 +1208,37 @@ Expr *make_expr_cmp(enum ExprKind kind, const Token *tok, Expr *lhs, Expr *rhs)
11971208 // Cast constant as non-const type.
11981209 * pRhs = make_cast (dst_type , (* pRhs )-> token , * pRhs , false);
11991210 } else {
1200- if (lt -> fixnum .kind < FX_INT )
1201- lhs = promote_to_int (lhs );
1202- if (rt -> fixnum .kind < FX_INT )
1203- rhs = promote_to_int (rhs );
1211+ bool lu = lt -> fixnum .is_unsigned ;
1212+ bool ru = rt -> fixnum .is_unsigned ;
1213+ make_int = lu != ru ;
1214+ if (lu != ru ) {
1215+ size_t ls = type_size (lt ), rs = type_size (rt );
1216+ if (MAX (ls , rs ) >= type_size (& tyInt )) {
1217+ make_int = true;
1218+ } else {
1219+ // Avoid promote-to-int
1220+ // Cast to larger signed type.
1221+ if (ls >= rs ) {
1222+ if (lt -> fixnum .is_unsigned ) {
1223+ lt = get_fixnum_type_from_size (ls );
1224+ lhs = make_cast (lt , lhs -> token , lhs , false);
1225+ }
1226+ rhs = make_cast (lt , rhs -> token , rhs , false);
1227+ rt = lt ;
1228+ } else {
1229+ if (rt -> fixnum .is_unsigned ) {
1230+ rt = get_fixnum_type_from_size (ls );
1231+ rhs = make_cast (rt , rhs -> token , rhs , false);
1232+ }
1233+ lhs = make_cast (rt , lhs -> token , lhs , false);
1234+ lt = rt ;
1235+ }
1236+ }
1237+ }
12041238 }
12051239 }
12061240 if (!(is_fixnum (lt ) && is_fixnum (rt )) || !(lc || rc )) {
1207- if (!cast_numbers (& lhs , & rhs , false )) {
1241+ if (!cast_numbers (& lhs , & rhs , make_int )) {
12081242 parse_error (PE_NOFATAL , tok , "cannot compare except numbers" );
12091243 return new_expr_fixlit (& tyBool , tok , 0 );
12101244 }
0 commit comments