Improve the wording for integer promotions

Jens Gustedt, INRIA and ICube, France

2026-09-27

target

integration into IS ISO/IEC 9899:202y

document number date comment
n3970 202609 This paper
n3886 Working draft
n2958 202204 Bit-fields, expressions and types
C23 issue 1021 202512
C23 issue 1077 202606

license

CC BY, see https://creativecommons.org/licenses/by/4.0

1 Rationale

C23 issue 1021 asked about the conversion of enumerated types when the rank of the underlying type is greater than the rank of int. Consensus in WG14 seems to be that the necessity of such a conversion had been overlooked when wider enumeration types were introduced in C23. This was in particular not treated clearly and satisfactory for bit-precise types. Several wording proposals have then been made to integrate this type of conversion into the integer promotions.

When doing so, other problems appeared. The first of them being that the handling of bit-fields was unclear between different parts of the standard, see also C23 issue 1077. In particular, in principle integer promotions only kick in after lvalue conversion, and since the declared width of a bit-field is not part of the type system for integer types, it is not imminently clear how this information would be transferred into the integer promotions.

Therefore, in this proposal, we insist of talking about the operand of a expression that has to undergo promotion. This leaves us the possibility to add a special rule for the situation where an operand stems from a bit-field.

Then, the intent seemingly had been that if the underlying type is a bit-precise type T, that promotion always leads to that type, regardless of whether the operand refers to a bit-field. This proposal clarifies that.

Also, surprisingly, some implementations that we tested are not conforming when it comes to bit-fields with an underlying standard integer type that is wider than int (which is permitted by the standard as implementation-defined extension). Here the current standard clearly stipulates that the integer promotions only apply to

For all other types it normatively requires without exception:

All other types are unchanged by the integer promotions.

Nevertheless, some the implementations that we tested also apply integer promotions for example to long long bit-fields, as long as their possible values fit in signed int or in unsigned int.

This can be tested by the following program.

#include <limits.h>
#include <stdio.h>

struct tt {
  long long K:INT_WIDTH-1;
  long long L:INT_WIDTH;
  long long M:INT_WIDTH+1;
} x;

#define TYPE_NAME(X)                            \
_Generic(+(X), /* apply integer promotion */    \
         int : "int",                           \
         long : "long",                         \
         long long : "long long",               \
         default: "other")

#define FORMAT "promoted `long long:%d` has type `%s`\n"

int main() {
  printf(FORMAT, INT_WIDTH-1, TYPE_NAME(x.K));
  printf(FORMAT, INT_WIDTH,   TYPE_NAME(x.L));
  printf(FORMAT, INT_WIDTH+1, TYPE_NAME(x.M));
}

For clang this program prints

promoted `long long:31` has type `int`
promoted `long long:32` has type `int`
promoted `long long:33` has type `long long`

for gcc

promoted `long long:31` has type `int`
promoted `long long:32` has type `int`
promoted `long long:33` has type `other`

In contrast to that, MSVC is conforming

promoted `long long:31` has type `long long`
promoted `long long:32` has type `long long`
promoted `long long:33` has type `long long`

In the proposed text we weaken the requirements in that case such that these compilers become conforming and such that C imposes less restrictions than C++.

But note also, that this proposal here is not meant to resolve other apparent discrepancies between gcc and other C compiler implementations, see n2958, namely that gcc extends the type system by the bit-field width and exposes this non-standard type to their users. (Thus the “other”, above.) Resolving this discrepancy would require more changes than just for integer promotions, and probably also some convincing such that the gcc behavior is recognized as erroneous.

Then, when revisiting the whole, it appears that the text was more complicated than it ought to be and also that it still contained some factual errors in non-normative text.

2 Proposed wording

Append the following sentence to 6.3.2.1 p1 (which defines the integer conversion rank)

A narrow integer type is an integer type with a rank that is less than the rank of int; a wide integer type is a type where it is greater.YY)

YY) The types signed int and unsigned int and enumerated types that have these as underlying type are neither narrow nor wide integer types.

Replace 6.3.2.1 p2 to p4 and footnote 38) as follows. Change a non-normative phrase in p4 into a footnote.

2 The following can be used in an expression wherever an int or unsigned int can be used:

The value from a bit-field of a bit-precise integer type is converted to the corresponding bit-precise integer type. If the original type is neither a bit-precise integer type (6.2.5) nor an enumerated type compatible with a bit-precise integer type: if an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int;38) otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.

2 As defined in the following, the integer promotions preserve the value (including sign) and potentially change the type of operands of expressions where this is specified in their respective subclauses. Let T be the type of the operand, or if the operand has an enumerated type, the underlying type of the enumeration. If the original operand before lvalue conversion refers to a bit-field member, T is determined without consideration of the declared width. If T is a bit-precise integer type38), the promoted type is T.

3 Otherwise, if T is not a wide integer type, let w be the declared width of the member if the original operand is a bit-field member; otherwise, let w be the width of T:

  • if negative values are representable in TXX), the promoted type is signed int,
  • otherwise, the promoted type is unsigned int.

Otherwise, if T is a wide integer type and if the original operand is a bit-field member, the promoted type is an integer type that is not narrow, that is able to hold all possible values of the bit-field and that is otherwise unspecified. Otherwise, the promoted type is T.

38) E.g. unsigned _BitInt(7)BF: 2 is declares a bit-field member BF that can hold the values 0, 1, 2, 3, and converts to retains the type unsigned _BitInt(7) when it undergoes integer promotion.

34 NOTE The integer promotions are applied only:

  1. as part of the usual arithmetic conversions (6.3.2.8),
  2. to certain argument expressions, as part of the default argument promotions (6.5.3.3),
  3. to the operands of the unary +, -, and ~ operators (6.5.4.4),
  4. and to both operands of the bitwise shift operators (6.5.8),
  5. and to the controlling expression of a switch statement (6.8.5.3).
as specified by their respective subclauses.
4 The integer promotions preserve value including sign.

XX) As discussed earlier, whether a “plain” char can hold negative values is implementation-defined.

3 Note to the editor

It also seems that indexing of the words “promotion(s)” is not entirely consistent. Integer promotions are classified under “promotion” (singular) and default argument promotions are classified under “promotions” (plural).

4 Possible future directions

There are several remaining issues concerning integer promotions and bit-fields.

Acknowledgements

Thanks to Joseph Myers for discussions and pointing out errors in previous versions of this paper.