<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<TITLE>
    CWG Issue 2528</TITLE>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<STYLE TYPE="text/css">
  INS { text-decoration:none; font-weight:bold; background-color:#A0FFA0 }
  .INS { text-decoration:none; background-color:#D0FFD0 }
  DEL { text-decoration:line-through; background-color:#FFA0A0 }
  .DEL { text-decoration:line-through; background-color: #FFD0D0 }
  @media (prefers-color-scheme: dark) {
    HTML { background-color:#202020; color:#f0f0f0; }
    A { color:#5bc0ff; }
    A:visited { color:#c6a8ff; }
    A:hover, a:focus { color:#afd7ff; }
    INS { background-color:#033a16; color:#aff5b4; }
    .INS { background-color: #033a16; }
    DEL { background-color:#67060c; color:#ffdcd7; }
    .DEL { background-color:#67060c; }
  }
  SPAN.cmnt { font-family:Times; font-style:italic }
</STYLE>
</HEAD>
<BODY>
<P><EM>This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21
  Core Issues List revision 118b.
  See http://www.open-std.org/jtc1/sc22/wg21/ for the official
  list.</EM></P>
<P>2025-09-28</P>
<HR>
<A NAME="2528"></A><H4>2528.
  
Three-way comparison and the usual arithmetic conversions
</H4>
<B>Section: </B>7.4&#160; [<A href="https://wg21.link/expr.arith.conv">expr.arith.conv</A>]
 &#160;&#160;&#160;

 <B>Status: </B>C++23
 &#160;&#160;&#160;

 <B>Submitter: </B>Cameron DaCamara
 &#160;&#160;&#160;

 <B>Date: </B>2022-01-26<BR>


<P>[Accepted as a DR at the February, 2023 meeting.]</P>



<P>Consider an example like:</P>

<PRE>
  void f(unsigned char i, unsigned ui) {
    i &lt;=&gt; ui;
  }
</PRE>

<P>According to 7.6.8 [<A href="https://wg21.link/expr.spaceship">expr.spaceship</A>] paragraph
4, the usual arithmetic conversions are applied to the
operands. According to 7.4 [<A href="https://wg21.link/expr.arith.conv">expr.arith.conv</A>] bullet
1.5, the integral promotions are performed on both
operands, resulting in <TT>i</TT> being converted from
<TT>unsigned char</TT> to <TT>int</TT>. The operands
are then of types <TT>int</TT> and <TT>unsigned int</TT>,
so bullet 1.5.5 applies, further converting <TT>i</TT>
to type <TT>unsigned int</TT>.</P>

<P>Unfortunately, that latter conversion, from <TT>int</TT>
to <TT>unsigned int</TT>, is a narrowing conversion, which
runs afoul of 7.6.8 [<A href="https://wg21.link/expr.spaceship#4.1">expr.spaceship</A>] bullet 4.1, which
prohibits narrowing conversions other than integral to
floating in three-way comparisons.</P>

<P><U>Suggested resolution [SUPERSEDED]:</U></P>

<P>Change 7.4 [<A href="https://wg21.link/expr.arith.conv#1.5">expr.arith.conv</A>] bullet 1.5 as follows:</P>

<BLOCKQUOTE>

<P>Otherwise, <DEL>the integral promotions
(7.3.7 [<A href="https://wg21.link/conv.prom">conv.prom</A>]) shall be performed on both
operands</DEL> <INS>each operand shall be converted to a
common type <I>C</I>. The integral promotion rules
(7.3.7 [<A href="https://wg21.link/conv.prom">conv.prom</A>] shall be used to determine a
type <I>T1</I> and type <I>T2</I> for each
operand</INS>.<SUP>50</SUP> Then the following rules shall
be applied to <DEL>the promoted operands</DEL>
<INS>determine <I>C</I></INS>:</P>

<UL>
<LI><P>If <DEL>both operands have</DEL> <INS><I>T1</I>
and <I>T2</I> are</INS> the same type, <DEL>no further
conversion is needed</DEL> <INS><I>C</I> shall
be that type</INS>.</P></LI>

<LI><P>Otherwise, if <DEL>both operands have</DEL>
<INS><I>T1</I> and <I>T2</I> are both</INS> signed integer
types or both <DEL>have</DEL> <INS>are</INS> unsigned
integer types, <DEL>the operand with the type of lesser
integer conversion rank shall be converted to the type of
the operand</DEL> <INS><I>C</I> shall be the type</INS> with
greater rank.</P></LI>

<LI><P>Otherwise, if the <DEL>operand that has</DEL>
<INS>the type <I>U</I> that is an</INS> unsigned integer
type has rank greater than or equal to the rank of
the <INS>other</INS> type<DEL> of the other operand, the
operand with signed integer type shall be converted to the
type of the operand with unsigned integer
type</DEL><INS>, <I>C</I> shall be <I>U</I></INS>.</P></LI>

<LI><P>Otherwise, if the type <DEL>of the operand with</DEL>
<INS><I>S</I> that is a</INS> signed integer type can
represent all of the values of the <INS>other</INS>
type<DEL> of the operand with unsigned integer type, the
operand with unsigned integer type shall be converted to the
type of the operand with signed integer
type</DEL><INS>, <I>C</I> shall be <I>S</I></INS>.</P></LI>

<LI><P>Otherwise, <DEL>both operands shall be converted to</DEL>
<INS><I>C</I> shall be</INS> the unsigned integer type
corresponding to the <DEL>type of the operand with</DEL>
signed integer type.</P></LI>

</UL>

</BLOCKQUOTE>

<P><B>Proposed resolution (approved by CWG 2023-02-09):</B></P>

<P>Change in 7.4 [<A href="https://wg21.link/expr.arith.conv#1.3">expr.arith.conv</A>] bullet 1.3 as follows, adding sub-bullets:</P>

<BLOCKQUOTE>

Otherwise, <DEL>the integral promotions (7.3.7 [<A href="https://wg21.link/conv.prom">conv.prom</A>]) are
performed on both operands</DEL>
<INS>each operand is converted to a common type C. The integral
promotion rules (7.3.7 [<A href="https://wg21.link/conv.prom">conv.prom</A>]) are used to determine a
type T1 and type T2 for each operand</INS>. [ Footnote: ... ] Then the
following rules are applied to <DEL>the promoted
operands</DEL> <INS>determine C</INS>:
<UL>
<LI>If <DEL>both operands have</DEL> <INS>T1 and T2 are</INS> the same type,
<DEL>no further conversion is needed</DEL> <INS>C is that type</INS>.
</LI>
<LI>Otherwise, if <INS>T1 and T2 are</INS> both <DEL>operands have</DEL> 
signed integer types or <INS>are</INS> both <DEL>have</DEL> unsigned
integer types, <DEL>the operand with the type of lesser integer
conversion rank is converted to the type of the operand</DEL> <INS>C
is the type</INS> with greater rank.
</LI>
<LI>Otherwise, <DEL>if the operand that has</DEL> <INS>let U be
the</INS> unsigned integer type <INS>and S be the signed integer type.</INS>
<UL>
<LI>
<INS>If U</INS> has rank greater than or equal to the
rank of <DEL>the type of the other operand, the operand with signed integer
type is converted to the type of the operand with unsigned integer
type</DEL>
<INS>S, C is U</INS>.
</LI>
<LI>Otherwise, if <DEL>the type of the operand with signed integer type</DEL> <INS>S</INS> can
represent all of the values of <DEL>the type of the operand with unsigned
integer type, the operand with unsigned integer type is converted to
the type of the operand with signed integer type</DEL> <INS>U, C is S</INS>.
</LI>
<LI>Otherwise, <DEL>both operands are converted to</DEL> <INS>C is</INS> the
unsigned integer type corresponding to <DEL>the type of the operand with
signed integer type</DEL> <INS>S</INS>.
</LI>
</UL>
</LI>
</UL>

</BLOCKQUOTE>

<BR><BR>
</BODY>
</HTML>
