Hi!

This patch adds the C FE support, c-family support, small libcpp change
so that 123wb and 42uwb suffixes are handled plus glimits.h change
to define BITINT_MAXWIDTH macro.

The previous patches really do nothing without this, which enables
all the support.

2023-08-09  Jakub Jelinek  <ja...@redhat.com>

        PR c/102989
gcc/
        * glimits.h (BITINT_MAXWIDTH): Define if __BITINT_MAXWIDTH__ is
        predefined.
gcc/c-family/
        * c-common.cc (c_common_reswords): Add _BitInt as keyword.
        (c_common_signed_or_unsigned_type): Handle BITINT_TYPE.
        (check_builtin_function_arguments): Handle BITINT_TYPE like
        INTEGER_TYPE.
        (sync_resolve_size): Add ORIG_FORMAT argument.  If
        FETCH && !ORIG_FORMAT, type is BITINT_TYPE, return -1 if size isn't
        one of 1, 2, 4, 8 or 16 or if it is 16 but TImode is not supported.
        (atomic_bitint_fetch_using_cas_loop): New function.
        (resolve_overloaded_builtin): Adjust sync_resolve_size caller.  If
        -1 is returned, use atomic_bitint_fetch_using_cas_loop to lower it.
        Formatting fix.
        (keyword_begins_type_specifier): Handle RID_BITINT.
        * c-common.h (enum rid): Add RID_BITINT enumerator.
        * c-cppbuiltin.cc (c_cpp_builtins): For C call
        targetm.c.bitint_type_info and predefine __BITINT_MAXWIDTH__
        and for -fbuilding-libgcc also __LIBGCC_BITINT_LIMB_WIDTH__ and
        __LIBGCC_BITINT_ORDER__ macros if _BitInt is supported.
        * c-lex.cc (interpret_integer): Handle CPP_N_BITINT.
        * c-pretty-print.cc (c_pretty_printer::simple_type_specifier,
        c_pretty_printer::direct_abstract_declarator): Handle BITINT_TYPE.
        (pp_c_integer_constant): Handle printing of large precision wide_ints
        which would buffer overflow digit_buffer.
gcc/c/
        * c-convert.cc (c_convert): Handle BITINT_TYPE like INTEGER_TYPE.
        * c-decl.cc (check_bitfield_type_and_width): Allow BITINT_TYPE
        bit-fields.
        (finish_struct): Prefer to use BITINT_TYPE for BITINT_TYPE bit-fields
        if possible.
        (declspecs_add_type): Formatting fixes.  Handle cts_bitint.  Adjust
        for added union in *specs.  Handle RID_BITINT.
        (finish_declspecs): Handle cts_bitint.  Adjust for added union
        in *specs.
        * c-parser.cc (c_keyword_starts_typename, c_token_starts_declspecs,
        c_parser_declspecs, c_parser_gnu_attribute_any_word): Handle
        RID_BITINT.
        * c-tree.h (enum c_typespec_keyword): Mention _BitInt in comment.
        Add cts_bitint enumerator.
        (struct c_declspecs): Move int_n_idx and floatn_nx_idx into a union
        and add bitint_prec there as well.
        * c-typeck.cc (composite_type, c_common_type, comptypes_internal):
        Handle BITINT_TYPE.
        (perform_integral_promotions): Promote BITINT_TYPE bit-fields to
        their declared type.
        (build_array_ref, build_unary_op, build_conditional_expr,
        convert_for_assignment, digest_init, build_binary_op): Likewise.
libcpp/
        * expr.cc (interpret_int_suffix): Handle wb and WB suffixes.
        * include/cpplib.h (CPP_N_BITINT): Define.

--- gcc/glimits.h.jj    2023-08-08 15:54:34.481612931 +0200
+++ gcc/glimits.h       2023-08-08 16:12:02.321939910 +0200
@@ -157,6 +157,11 @@ see the files COPYING3 and COPYING.RUNTI
 # undef BOOL_WIDTH
 # define BOOL_WIDTH 1
 
+# ifdef __BITINT_MAXWIDTH__
+#  undef BITINT_MAXWIDTH
+#  define BITINT_MAXWIDTH __BITINT_MAXWIDTH__
+# endif
+
 # define __STDC_VERSION_LIMITS_H__     202311L
 #endif
 
--- gcc/c-family/c-common.cc.jj 2023-08-08 15:55:05.243182143 +0200
+++ gcc/c-family/c-common.cc    2023-08-08 16:19:29.102683903 +0200
@@ -349,6 +349,7 @@ const struct c_common_resword c_common_r
   { "_Alignas",                RID_ALIGNAS,   D_CONLY },
   { "_Alignof",                RID_ALIGNOF,   D_CONLY },
   { "_Atomic",         RID_ATOMIC,    D_CONLY },
+  { "_BitInt",         RID_BITINT,    D_CONLY },
   { "_Bool",           RID_BOOL,      D_CONLY },
   { "_Complex",                RID_COMPLEX,    0 },
   { "_Imaginary",      RID_IMAGINARY, D_CONLY },
@@ -2728,6 +2729,9 @@ c_common_signed_or_unsigned_type (int un
       || TYPE_UNSIGNED (type) == unsignedp)
     return type;
 
+  if (TREE_CODE (type) == BITINT_TYPE)
+    return build_bitint_type (TYPE_PRECISION (type), unsignedp);
+
 #define TYPE_OK(node)                                                      \
   (TYPE_MODE (type) == TYPE_MODE (node)                                        
    \
    && TYPE_PRECISION (type) == TYPE_PRECISION (node))
@@ -6341,8 +6345,10 @@ check_builtin_function_arguments (locati
          code0 = TREE_CODE (TREE_TYPE (args[0]));
          code1 = TREE_CODE (TREE_TYPE (args[1]));
          if (!((code0 == REAL_TYPE && code1 == REAL_TYPE)
-               || (code0 == REAL_TYPE && code1 == INTEGER_TYPE)
-               || (code0 == INTEGER_TYPE && code1 == REAL_TYPE)))
+               || (code0 == REAL_TYPE
+                   && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
+               || ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE)
+                   && code1 == REAL_TYPE)))
            {
              error_at (loc, "non-floating-point arguments in call to "
                        "function %qE", fndecl);
@@ -7185,12 +7191,16 @@ speculation_safe_value_resolve_return (t
 /* A helper function for resolve_overloaded_builtin in resolving the
    overloaded __sync_ builtins.  Returns a positive power of 2 if the
    first operand of PARAMS is a pointer to a supported data type.
-   Returns 0 if an error is encountered.
+   Returns 0 if an error is encountered.  Return -1 for _BitInt
+   __atomic*fetch* with unsupported type which should be handled by
+   a cas loop.
    FETCH is true when FUNCTION is one of the _FETCH_OP_ or _OP_FETCH_
+   built-ins.  ORIG_FORMAT is for __sync_* rather than __atomic_*
    built-ins.  */
 
 static int
-sync_resolve_size (tree function, vec<tree, va_gc> *params, bool fetch)
+sync_resolve_size (tree function, vec<tree, va_gc> *params, bool fetch,
+                  bool orig_format)
 {
   /* Type of the argument.  */
   tree argtype;
@@ -7225,9 +7235,19 @@ sync_resolve_size (tree function, vec<tr
     goto incompatible;
 
   size = tree_to_uhwi (TYPE_SIZE_UNIT (type));
+  if (size == 16
+      && fetch
+      && !orig_format
+      && TREE_CODE (type) == BITINT_TYPE
+      && !targetm.scalar_mode_supported_p (TImode))
+    return -1;
+
   if (size == 1 || size == 2 || size == 4 || size == 8 || size == 16)
     return size;
 
+  if (fetch && !orig_format && TREE_CODE (type) == BITINT_TYPE)
+    return -1;
+
  incompatible:
   /* Issue the diagnostic only if the argument is valid, otherwise
      it would be redundant at best and could be misleading.  */
@@ -7844,6 +7864,223 @@ resolve_overloaded_atomic_store (locatio
 }
 
 
+/* Emit __atomic*fetch* on _BitInt which doesn't have a size of
+   1, 2, 4, 8 or 16 bytes using __atomic_compare_exchange loop.
+   ORIG_CODE is the DECL_FUNCTION_CODE of ORIG_FUNCTION and
+   ORIG_PARAMS arguments of the call.  */
+
+static tree
+atomic_bitint_fetch_using_cas_loop (location_t loc,
+                                   enum built_in_function orig_code,
+                                   tree orig_function,
+                                   vec<tree, va_gc> *orig_params)
+{
+  enum tree_code code = ERROR_MARK;
+  bool return_old_p = false;
+  switch (orig_code)
+    {
+    case BUILT_IN_ATOMIC_ADD_FETCH_N:
+      code = PLUS_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_SUB_FETCH_N:
+      code = MINUS_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_AND_FETCH_N:
+      code = BIT_AND_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_NAND_FETCH_N:
+      break;
+    case BUILT_IN_ATOMIC_XOR_FETCH_N:
+      code = BIT_XOR_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_OR_FETCH_N:
+      code = BIT_IOR_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_ADD_N:
+      code = PLUS_EXPR;
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_SUB_N:
+      code = MINUS_EXPR;
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_AND_N:
+      code = BIT_AND_EXPR;
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_NAND_N:
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_XOR_N:
+      code = BIT_XOR_EXPR;
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_OR_N:
+      code = BIT_IOR_EXPR;
+      return_old_p = true;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (orig_params->length () != 3)
+    {
+      if (orig_params->length () < 3)
+       error_at (loc, "too few arguments to function %qE", orig_function);
+      else
+       error_at (loc, "too many arguments to function %qE", orig_function);
+      return error_mark_node;
+    }
+
+  tree stmts = push_stmt_list ();
+
+  tree nonatomic_lhs_type = TREE_TYPE (TREE_TYPE ((*orig_params)[0]));
+  nonatomic_lhs_type = TYPE_MAIN_VARIANT (nonatomic_lhs_type);
+  gcc_assert (TREE_CODE (nonatomic_lhs_type) == BITINT_TYPE);
+
+  tree lhs_addr = (*orig_params)[0];
+  tree val = convert (nonatomic_lhs_type, (*orig_params)[1]);
+  tree model = convert (integer_type_node, (*orig_params)[2]);
+  if (TREE_SIDE_EFFECTS (lhs_addr))
+    {
+      tree var = create_tmp_var_raw (TREE_TYPE (lhs_addr));
+      lhs_addr = build4 (TARGET_EXPR, TREE_TYPE (lhs_addr), var, lhs_addr,
+                        NULL_TREE, NULL_TREE);
+      add_stmt (lhs_addr);
+    }
+  if (TREE_SIDE_EFFECTS (val))
+    {
+      tree var = create_tmp_var_raw (nonatomic_lhs_type);
+      val = build4 (TARGET_EXPR, nonatomic_lhs_type, var, val, NULL_TREE,
+                   NULL_TREE);
+      add_stmt (val);
+    }
+  if (TREE_SIDE_EFFECTS (model))
+    {
+      tree var = create_tmp_var_raw (integer_type_node);
+      model = build4 (TARGET_EXPR, integer_type_node, var, model, NULL_TREE,
+                     NULL_TREE);
+      add_stmt (model);
+    }
+
+  tree old = create_tmp_var_raw (nonatomic_lhs_type);
+  tree old_addr = build_unary_op (loc, ADDR_EXPR, old, false);
+  TREE_ADDRESSABLE (old) = 1;
+  suppress_warning (old);
+
+  tree newval = create_tmp_var_raw (nonatomic_lhs_type);
+  tree newval_addr = build_unary_op (loc, ADDR_EXPR, newval, false);
+  TREE_ADDRESSABLE (newval) = 1;
+  suppress_warning (newval);
+
+  tree loop_decl = create_artificial_label (loc);
+  tree loop_label = build1 (LABEL_EXPR, void_type_node, loop_decl);
+
+  tree done_decl = create_artificial_label (loc);
+  tree done_label = build1 (LABEL_EXPR, void_type_node, done_decl);
+
+  vec<tree, va_gc> *params;
+  vec_alloc (params, 6);
+
+  /* __atomic_load (addr, &old, SEQ_CST).  */
+  tree fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD);
+  params->quick_push (lhs_addr);
+  params->quick_push (old_addr);
+  params->quick_push (build_int_cst (integer_type_node, MEMMODEL_RELAXED));
+  tree func_call = resolve_overloaded_builtin (loc, fndecl, params);
+  if (func_call == NULL_TREE)
+    func_call = build_function_call_vec (loc, vNULL, fndecl, params, NULL);
+  old = build4 (TARGET_EXPR, nonatomic_lhs_type, old, func_call, NULL_TREE,
+               NULL_TREE);
+  add_stmt (old);
+  params->truncate (0);
+
+  /* loop:  */
+  add_stmt (loop_label);
+
+  /* newval = old + val;  */
+  tree rhs;
+  switch (code)
+    {
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      if (!TYPE_OVERFLOW_WRAPS (nonatomic_lhs_type))
+       {
+         tree utype
+           = build_bitint_type (TYPE_PRECISION (nonatomic_lhs_type), 1);
+         rhs = convert (nonatomic_lhs_type,
+                        build2_loc (loc, code, utype,
+                                    convert (utype, old),
+                                    convert (utype, val)));
+       }
+      else
+       rhs = build2_loc (loc, code, nonatomic_lhs_type, old, val);
+      break;
+    case BIT_AND_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+      rhs = build2_loc (loc, code, nonatomic_lhs_type, old, val);
+      break;
+    case ERROR_MARK:
+      rhs = build2_loc (loc, BIT_AND_EXPR, nonatomic_lhs_type,
+                       build1_loc (loc, BIT_NOT_EXPR,
+                                   nonatomic_lhs_type, old), val);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  rhs = build4 (TARGET_EXPR, nonatomic_lhs_type, newval, rhs, NULL_TREE,
+               NULL_TREE);
+  SET_EXPR_LOCATION (rhs, loc);
+  add_stmt (rhs);
+
+  /* if (__atomic_compare_exchange (addr, &old, &new, false, model, model))
+       goto done;  */
+  fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_COMPARE_EXCHANGE);
+  params->quick_push (lhs_addr);
+  params->quick_push (old_addr);
+  params->quick_push (newval_addr);
+  params->quick_push (integer_zero_node);
+  params->quick_push (model);
+  if (tree_fits_uhwi_p (model)
+      && (tree_to_uhwi (model) == MEMMODEL_RELEASE
+         || tree_to_uhwi (model) == MEMMODEL_ACQ_REL))
+    params->quick_push (build_int_cst (integer_type_node, MEMMODEL_RELAXED));
+  else
+    params->quick_push (model);
+  func_call = resolve_overloaded_builtin (loc, fndecl, params);
+  if (func_call == NULL_TREE)
+    func_call = build_function_call_vec (loc, vNULL, fndecl, params, NULL);
+
+  tree goto_stmt = build1 (GOTO_EXPR, void_type_node, done_decl);
+  SET_EXPR_LOCATION (goto_stmt, loc);
+
+  tree stmt
+    = build3 (COND_EXPR, void_type_node, func_call, goto_stmt, NULL_TREE);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+
+  /* goto loop;  */
+  goto_stmt = build1 (GOTO_EXPR, void_type_node, loop_decl);
+  SET_EXPR_LOCATION (goto_stmt, loc);
+  add_stmt (goto_stmt);
+
+  /* done:  */
+  add_stmt (done_label);
+
+  tree ret = create_tmp_var_raw (nonatomic_lhs_type);
+  stmt = build2_loc (loc, MODIFY_EXPR, void_type_node, ret,
+                    return_old_p ? old : newval);
+  add_stmt (stmt);
+
+  /* Finish the compound statement.  */
+  stmts = pop_stmt_list (stmts);
+
+  return build4 (TARGET_EXPR, nonatomic_lhs_type, ret, stmts, NULL_TREE,
+                NULL_TREE);
+}
+
+
 /* Some builtin functions are placeholders for other expressions.  This
    function should be called immediately after parsing the call expression
    before surrounding code has committed to the type of the expression.
@@ -8025,19 +8262,22 @@ resolve_overloaded_builtin (location_t l
        /* The following are not _FETCH_OPs and must be accepted with
           pointers to _Bool (or C++ bool).  */
        if (fetch_op)
-         fetch_op =
-           (orig_code != BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N
-            && orig_code != BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N
-            && orig_code != BUILT_IN_SYNC_LOCK_TEST_AND_SET_N
-            && orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N);
+         fetch_op = (orig_code != BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N
+                     && orig_code != BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N
+                     && orig_code != BUILT_IN_SYNC_LOCK_TEST_AND_SET_N
+                     && orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N);
 
-       int n = sync_resolve_size (function, params, fetch_op);
+       int n = sync_resolve_size (function, params, fetch_op, orig_format);
        tree new_function, first_param, result;
        enum built_in_function fncode;
 
        if (n == 0)
          return error_mark_node;
 
+       if (n == -1)
+         return atomic_bitint_fetch_using_cas_loop (loc, orig_code,
+                                                    function, params);
+
        fncode = (enum built_in_function)((int)orig_code + exact_log2 (n) + 1);
        new_function = builtin_decl_explicit (fncode);
        if (!sync_resolve_params (loc, function, new_function, params,
@@ -8402,6 +8642,7 @@ keyword_begins_type_specifier (enum rid
     case RID_FRACT:
     case RID_ACCUM:
     case RID_BOOL:
+    case RID_BITINT:
     case RID_WCHAR:
     case RID_CHAR8:
     case RID_CHAR16:
--- gcc/c-family/c-common.h.jj  2023-08-08 15:55:05.244182129 +0200
+++ gcc/c-family/c-common.h     2023-08-08 16:12:02.331939770 +0200
@@ -101,7 +101,7 @@ enum rid
   RID_ENUM,    RID_STRUCT, RID_UNION,    RID_IF,     RID_ELSE,
   RID_WHILE,   RID_DO,     RID_FOR,      RID_SWITCH, RID_CASE,
   RID_DEFAULT, RID_BREAK,  RID_CONTINUE, RID_RETURN, RID_GOTO,
-  RID_SIZEOF,
+  RID_SIZEOF,  RID_BITINT,
 
   /* C extensions */
   RID_ASM,       RID_TYPEOF,   RID_TYPEOF_UNQUAL, RID_ALIGNOF,  RID_ATTRIBUTE,
--- gcc/c-family/c-cppbuiltin.cc.jj     2023-08-08 15:54:33.448627395 +0200
+++ gcc/c-family/c-cppbuiltin.cc        2023-08-08 16:12:02.331939770 +0200
@@ -1190,6 +1190,29 @@ c_cpp_builtins (cpp_reader *pfile)
   builtin_define_type_width ("__PTRDIFF_WIDTH__", ptrdiff_type_node, 
NULL_TREE);
   builtin_define_type_width ("__SIZE_WIDTH__", size_type_node, NULL_TREE);
 
+  if (!c_dialect_cxx ())
+    {
+      struct bitint_info info;
+      /* For now, restrict __BITINT_MAXWIDTH__ to what can be represented in
+        wide_int and widest_int.  */
+      if (targetm.c.bitint_type_info (WIDE_INT_MAX_PRECISION - 1, &info))
+       {
+         cpp_define_formatted (pfile, "__BITINT_MAXWIDTH__=%d",
+                               (int) WIDE_INT_MAX_PRECISION - 1);
+         if (flag_building_libgcc)
+           {
+             scalar_int_mode limb_mode
+               = as_a <scalar_int_mode> (info.limb_mode);
+             cpp_define_formatted (pfile, "__LIBGCC_BITINT_LIMB_WIDTH__=%d",
+                                   (int) GET_MODE_PRECISION (limb_mode));
+             cpp_define_formatted (pfile, "__LIBGCC_BITINT_ORDER__=%s",
+                                   info.big_endian
+                                   ? "__ORDER_BIG_ENDIAN__"
+                                   : "__ORDER_LITTLE_ENDIAN__");
+           }
+       }
+    }
+
   if (c_dialect_cxx ())
     for (i = 0; i < NUM_INT_N_ENTS; i ++)
       if (int_n_enabled_p[i])
--- gcc/c-family/c-lex.cc.jj    2023-08-08 15:55:05.245182116 +0200
+++ gcc/c-family/c-lex.cc       2023-08-08 16:12:02.332939756 +0200
@@ -837,6 +837,170 @@ interpret_integer (const cpp_token *toke
 
   *overflow = OT_NONE;
 
+  if (UNLIKELY (flags & CPP_N_BITINT))
+    {
+      unsigned int suffix_len = 2 + ((flags & CPP_N_UNSIGNED) ? 1 : 0);
+      int max_bits_per_digit = 4; // ceil (log2 (10))
+      unsigned int prefix_len = 0;
+      bool hex = false;
+      const int bitint_maxwidth = WIDE_INT_MAX_PRECISION - 1;
+      if ((flags & CPP_N_RADIX) == CPP_N_OCTAL)
+       {
+         max_bits_per_digit = 3;
+         prefix_len = 1;
+       }
+      else if ((flags & CPP_N_RADIX) == CPP_N_HEX)
+       {
+         max_bits_per_digit = 4;
+         prefix_len = 2;
+         hex = true;
+       }
+      else if ((flags & CPP_N_RADIX) == CPP_N_BINARY)
+       {
+         max_bits_per_digit = 1;
+         prefix_len = 2;
+       }
+      int max_digits
+       = TYPE_PRECISION (intmax_type_node) >> max_bits_per_digit;
+      const int max_buf = 128;
+      if (max_digits > max_buf)
+       max_digits = max_buf;
+
+      widest_int wval;
+      unsigned int prec;
+      gcc_checking_assert (token->val.str.len > prefix_len + suffix_len
+                          || token->val.str.len == 1 + suffix_len);
+      if (token->val.str.len - (prefix_len + suffix_len)
+         <= (unsigned) max_digits)
+       {
+         integer = cpp_interpret_integer (parse_in, token,
+                                          (flags & CPP_N_RADIX)
+                                          | CPP_N_UNSIGNED);
+         ival[0] = integer.low;
+         ival[1] = integer.high;
+         ival[2] = 0;
+         wval = widest_int::from_array (ival, 3);
+       }
+      else
+       {
+         unsigned char buf[3 + max_buf];
+         memcpy (buf, token->val.str.text, prefix_len);
+         wval = 0U;
+         const unsigned char *p = token->val.str.text + prefix_len;
+         cpp_token tok = *token;
+         tok.val.str.text = buf;
+         if (!prefix_len)
+           max_digits = 19;
+         do
+           {
+             unsigned char *q = buf + prefix_len;
+             do
+               {
+                 unsigned char c = *p++;
+                 if (ISDIGIT (c) || (hex && ISXDIGIT (c)))
+                   {
+                     *q++ = c;
+                     if (q == buf + prefix_len + max_digits)
+                       break;
+                   }
+                 else if (c != '\'')
+                   {
+                     --p;
+                     break;
+                   }
+               }
+             while (1);
+             if (q == buf + prefix_len)
+               break;
+             else
+               {
+                 wi::overflow_type wioverflow;
+                 *q = '\0';
+                 tok.val.str.len = q - buf;
+                 if (wval == 0)
+                   ;
+                 else if (prefix_len)
+                   {
+                     prec = wi::min_precision (wval, UNSIGNED);
+                     unsigned HOST_WIDE_INT shift
+                       = (tok.val.str.len - prefix_len) * max_bits_per_digit;
+                     if (prec + shift > bitint_maxwidth)
+                       goto bitint_overflow;
+                     wval = wi::lshift (wval, shift);
+                   }
+                 else
+                   {
+                     static unsigned HOST_WIDE_INT tens[]
+                       = { 1U, 10U, 100U, 1000U,
+                           HOST_WIDE_INT_UC (10000),
+                           HOST_WIDE_INT_UC (100000),
+                           HOST_WIDE_INT_UC (1000000),
+                           HOST_WIDE_INT_UC (10000000),
+                           HOST_WIDE_INT_UC (100000000),
+                           HOST_WIDE_INT_UC (1000000000),
+                           HOST_WIDE_INT_UC (10000000000),
+                           HOST_WIDE_INT_UC (100000000000),
+                           HOST_WIDE_INT_UC (1000000000000),
+                           HOST_WIDE_INT_UC (10000000000000),
+                           HOST_WIDE_INT_UC (100000000000000),
+                           HOST_WIDE_INT_UC (1000000000000000),
+                           HOST_WIDE_INT_UC (10000000000000000),
+                           HOST_WIDE_INT_UC (100000000000000000),
+                           HOST_WIDE_INT_UC (1000000000000000000),
+                           HOST_WIDE_INT_UC (10000000000000000000) };
+                     widest_int ten = tens[q - buf];
+                     wval = wi::umul (wval, ten, &wioverflow);
+                     if (wioverflow)
+                       goto bitint_overflow;
+                   }
+                 integer = cpp_interpret_integer (parse_in, &tok,
+                                                  (flags & CPP_N_RADIX)
+                                                  | CPP_N_UNSIGNED);
+                 ival[0] = integer.low;
+                 ival[1] = integer.high;
+                 ival[2] = 0;
+                 if (prefix_len)
+                   wval = wval + widest_int::from_array (ival, 3);
+                 else
+                   {
+                     widest_int addend = widest_int::from_array (ival, 3);
+                     wval = wi::add (wval, addend, UNSIGNED, &wioverflow);
+                     if (wioverflow)
+                       goto bitint_overflow;
+                   }
+               }
+           }
+         while (1);
+       }
+
+      prec = wi::min_precision (wval, UNSIGNED);
+      if (prec == 0)
+       prec = 1;
+      if ((flags & CPP_N_UNSIGNED) == 0)
+       ++prec;
+      if (prec > bitint_maxwidth)
+       {
+       bitint_overflow:
+         if ((flags & CPP_N_UNSIGNED) != 0)
+           error ("integer constant is too large for "
+                  "%<unsigned _BitInt(%d)%> type", bitint_maxwidth);
+         else
+           error ("integer constant is too large for "
+                  "%<_BitInt(%d)%> type", bitint_maxwidth);
+         return integer_zero_node;
+       }
+
+      struct bitint_info info;
+      if (!targetm.c.bitint_type_info (prec, &info))
+       {
+         sorry ("%<_BitInt(%d)%> is not supported on this target", prec);
+         return integer_zero_node;
+       }
+
+      type = build_bitint_type (prec, (flags & CPP_N_UNSIGNED) != 0);
+      return wide_int_to_tree (type, wval);
+    }
+
   integer = cpp_interpret_integer (parse_in, token, flags);
   if (integer.overflow)
     *overflow = OT_OVERFLOW;
--- gcc/c-family/c-pretty-print.cc.jj   2023-08-08 15:54:33.553625925 +0200
+++ gcc/c-family/c-pretty-print.cc      2023-08-08 16:12:02.332939756 +0200
@@ -399,6 +399,23 @@ c_pretty_printer::simple_type_specifier
        }
       break;
 
+    case BITINT_TYPE:
+      if (TYPE_NAME (t))
+       {
+         t = TYPE_NAME (t);
+         simple_type_specifier (t);
+       }
+      else
+       {
+         int prec = TYPE_PRECISION (t);
+         if (TYPE_UNSIGNED (t))
+           pp_c_ws_string (this, "unsigned");
+         pp_c_ws_string (this, "_BitInt(");;
+         pp_decimal_int (this, prec);
+         pp_right_paren (this);
+       }
+      break;
+
     case TYPE_DECL:
       if (DECL_NAME (t))
        id_expression (t);
@@ -688,6 +705,7 @@ c_pretty_printer::direct_abstract_declar
     case REAL_TYPE:
     case FIXED_POINT_TYPE:
     case ENUMERAL_TYPE:
+    case BITINT_TYPE:
     case RECORD_TYPE:
     case UNION_TYPE:
     case VECTOR_TYPE:
@@ -1019,8 +1037,18 @@ pp_c_integer_constant (c_pretty_printer
          pp_minus (pp);
          wi = -wi;
        }
-      print_hex (wi, pp_buffer (pp)->digit_buffer);
-      pp_string (pp, pp_buffer (pp)->digit_buffer);
+      unsigned int prec = wi.get_precision ();
+      if ((prec + 3) / 4 > sizeof (pp_buffer (pp)->digit_buffer) - 3)
+       {
+         char *buf = XALLOCAVEC (char, (prec + 3) / 4 + 3);
+         print_hex (wi, buf);
+         pp_string (pp, buf);
+       }
+      else
+       {
+         print_hex (wi, pp_buffer (pp)->digit_buffer);
+         pp_string (pp, pp_buffer (pp)->digit_buffer);
+       }
     }
 }
 
--- gcc/c/c-convert.cc.jj       2023-08-08 15:54:33.642624678 +0200
+++ gcc/c/c-convert.cc  2023-08-08 16:12:02.332939756 +0200
@@ -117,6 +117,7 @@ c_convert (tree type, tree expr, bool in
       gcc_fallthrough ();
 
     case INTEGER_TYPE:
+    case BITINT_TYPE:
       if (sanitize_flags_p (SANITIZE_FLOAT_CAST)
          && current_function_decl != NULL_TREE
          && SCALAR_FLOAT_TYPE_P (TREE_TYPE (expr))
--- gcc/c/c-decl.cc.jj  2023-08-08 15:55:05.277181667 +0200
+++ gcc/c/c-decl.cc     2023-08-08 16:15:41.006877794 +0200
@@ -6390,7 +6390,8 @@ check_bitfield_type_and_width (location_
   /* Detect invalid bit-field type.  */
   if (TREE_CODE (*type) != INTEGER_TYPE
       && TREE_CODE (*type) != BOOLEAN_TYPE
-      && TREE_CODE (*type) != ENUMERAL_TYPE)
+      && TREE_CODE (*type) != ENUMERAL_TYPE
+      && TREE_CODE (*type) != BITINT_TYPE)
     {
       error_at (loc, "bit-field %qs has invalid type", name);
       *type = unsigned_type_node;
@@ -9330,8 +9331,14 @@ finish_struct (location_t loc, tree t, t
          tree type = TREE_TYPE (field);
          if (width != TYPE_PRECISION (type))
            {
-             TREE_TYPE (field)
-               = c_build_bitfield_integer_type (width, TYPE_UNSIGNED (type));
+             if (TREE_CODE (type) == BITINT_TYPE
+                 && (width > 1 || TYPE_UNSIGNED (type)))
+               TREE_TYPE (field)
+                 = build_bitint_type (width, TYPE_UNSIGNED (type));
+             else
+               TREE_TYPE (field)
+                 = c_build_bitfield_integer_type (width,
+                                                  TYPE_UNSIGNED (type));
              SET_DECL_MODE (field, TYPE_MODE (TREE_TYPE (field)));
            }
          DECL_INITIAL (field) = NULL_TREE;
@@ -11546,14 +11553,18 @@ declspecs_add_type (location_t loc, stru
                          ("both %<long%> and %<void%> in "
                           "declaration specifiers"));
              else if (specs->typespec_word == cts_int_n)
-                 error_at (loc,
-                           ("both %<long%> and %<__int%d%> in "
-                            "declaration specifiers"),
-                           int_n_data[specs->int_n_idx].bitsize);
+               error_at (loc,
+                         ("both %<long%> and %<__int%d%> in "
+                          "declaration specifiers"),
+                         int_n_data[specs->u.int_n_idx].bitsize);
              else if (specs->typespec_word == cts_bool)
                error_at (loc,
                          ("both %<long%> and %<_Bool%> in "
                           "declaration specifiers"));
+             else if (specs->typespec_word == cts_bitint)
+               error_at (loc,
+                         ("both %<long%> and %<_BitInt%> in "
+                          "declaration specifiers"));
              else if (specs->typespec_word == cts_char)
                error_at (loc,
                          ("both %<long%> and %<char%> in "
@@ -11566,8 +11577,8 @@ declspecs_add_type (location_t loc, stru
                error_at (loc,
                          ("both %<long%> and %<_Float%d%s%> in "
                           "declaration specifiers"),
-                         floatn_nx_types[specs->floatn_nx_idx].n,
-                         (floatn_nx_types[specs->floatn_nx_idx].extended
+                         floatn_nx_types[specs->u.floatn_nx_idx].n,
+                         (floatn_nx_types[specs->u.floatn_nx_idx].extended
                           ? "x"
                           : ""));
              else if (specs->typespec_word == cts_dfloat32)
@@ -11606,11 +11617,15 @@ declspecs_add_type (location_t loc, stru
                error_at (loc,
                          ("both %<short%> and %<__int%d%> in "
                           "declaration specifiers"),
-                         int_n_data[specs->int_n_idx].bitsize);
+                         int_n_data[specs->u.int_n_idx].bitsize);
              else if (specs->typespec_word == cts_bool)
                error_at (loc,
                          ("both %<short%> and %<_Bool%> in "
                           "declaration specifiers"));
+             else if (specs->typespec_word == cts_bitint)
+               error_at (loc,
+                         ("both %<short%> and %<_BitInt%> in "
+                          "declaration specifiers"));
              else if (specs->typespec_word == cts_char)
                error_at (loc,
                          ("both %<short%> and %<char%> in "
@@ -11627,8 +11642,8 @@ declspecs_add_type (location_t loc, stru
                error_at (loc,
                          ("both %<short%> and %<_Float%d%s%> in "
                           "declaration specifiers"),
-                         floatn_nx_types[specs->floatn_nx_idx].n,
-                         (floatn_nx_types[specs->floatn_nx_idx].extended
+                         floatn_nx_types[specs->u.floatn_nx_idx].n,
+                         (floatn_nx_types[specs->u.floatn_nx_idx].extended
                           ? "x"
                           : ""));
              else if (specs->typespec_word == cts_dfloat32)
@@ -11679,8 +11694,8 @@ declspecs_add_type (location_t loc, stru
                error_at (loc,
                          ("both %<signed%> and %<_Float%d%s%> in "
                           "declaration specifiers"),
-                         floatn_nx_types[specs->floatn_nx_idx].n,
-                         (floatn_nx_types[specs->floatn_nx_idx].extended
+                         floatn_nx_types[specs->u.floatn_nx_idx].n,
+                         (floatn_nx_types[specs->u.floatn_nx_idx].extended
                           ? "x"
                           : ""));
              else if (specs->typespec_word == cts_dfloat32)
@@ -11731,8 +11746,8 @@ declspecs_add_type (location_t loc, stru
                error_at (loc,
                          ("both %<unsigned%> and %<_Float%d%s%> in "
                           "declaration specifiers"),
-                         floatn_nx_types[specs->floatn_nx_idx].n,
-                         (floatn_nx_types[specs->floatn_nx_idx].extended
+                         floatn_nx_types[specs->u.floatn_nx_idx].n,
+                         (floatn_nx_types[specs->u.floatn_nx_idx].extended
                           ? "x"
                           : ""));
               else if (specs->typespec_word == cts_dfloat32)
@@ -11770,6 +11785,10 @@ declspecs_add_type (location_t loc, stru
                error_at (loc,
                          ("both %<complex%> and %<_Bool%> in "
                           "declaration specifiers"));
+             else if (specs->typespec_word == cts_bitint)
+               error_at (loc,
+                         ("both %<complex%> and %<_BitInt%> in "
+                          "declaration specifiers"));
               else if (specs->typespec_word == cts_dfloat32)
                error_at (loc,
                          ("both %<complex%> and %<_Decimal32%> in "
@@ -11809,7 +11828,7 @@ declspecs_add_type (location_t loc, stru
                  error_at (loc,
                            ("both %<_Sat%> and %<__int%d%> in "
                             "declaration specifiers"),
-                           int_n_data[specs->int_n_idx].bitsize);
+                           int_n_data[specs->u.int_n_idx].bitsize);
                }
              else if (specs->typespec_word == cts_auto_type)
                error_at (loc,
@@ -11823,6 +11842,10 @@ declspecs_add_type (location_t loc, stru
                error_at (loc,
                          ("both %<_Sat%> and %<_Bool%> in "
                           "declaration specifiers"));
+             else if (specs->typespec_word == cts_bitint)
+               error_at (loc,
+                         ("both %<_Sat%> and %<_BitInt%> in "
+                          "declaration specifiers"));
              else if (specs->typespec_word == cts_char)
                error_at (loc,
                          ("both %<_Sat%> and %<char%> in "
@@ -11843,8 +11866,8 @@ declspecs_add_type (location_t loc, stru
                error_at (loc,
                          ("both %<_Sat%> and %<_Float%d%s%> in "
                           "declaration specifiers"),
-                         floatn_nx_types[specs->floatn_nx_idx].n,
-                         (floatn_nx_types[specs->floatn_nx_idx].extended
+                         floatn_nx_types[specs->u.floatn_nx_idx].n,
+                         (floatn_nx_types[specs->u.floatn_nx_idx].extended
                           ? "x"
                           : ""));
               else if (specs->typespec_word == cts_dfloat32)
@@ -11882,7 +11905,7 @@ declspecs_add_type (location_t loc, stru
        {
          /* "void", "_Bool", "char", "int", "float", "double",
             "_FloatN", "_FloatNx", "_Decimal32", "__intN",
-            "_Decimal64", "_Decimal128", "_Fract", "_Accum" or
+            "_Decimal64", "_Decimal128", "_Fract", "_Accum", "_BitInt(N)" or
             "__auto_type".  */
          if (specs->typespec_word != cts_none)
            {
@@ -11927,7 +11950,7 @@ declspecs_add_type (location_t loc, stru
            case RID_INT_N_1:
            case RID_INT_N_2:
            case RID_INT_N_3:
-             specs->int_n_idx = i - RID_INT_N_0;
+             specs->u.int_n_idx = i - RID_INT_N_0;
              if (!in_system_header_at (input_location)
                  /* If the INT_N type ends in "__", and so is of the format
                     "__intN__", don't pedwarn.  */
@@ -11935,29 +11958,29 @@ declspecs_add_type (location_t loc, stru
                               + (IDENTIFIER_LENGTH (type) - 2), "__", 2) != 0))
                pedwarn (loc, OPT_Wpedantic,
                         "ISO C does not support %<__int%d%> types",
-                        int_n_data[specs->int_n_idx].bitsize);
+                        int_n_data[specs->u.int_n_idx].bitsize);
 
              if (specs->long_p)
                error_at (loc,
                          ("both %<__int%d%> and %<long%> in "
                           "declaration specifiers"),
-                         int_n_data[specs->int_n_idx].bitsize);
+                         int_n_data[specs->u.int_n_idx].bitsize);
              else if (specs->saturating_p)
                error_at (loc,
                          ("both %<_Sat%> and %<__int%d%> in "
                           "declaration specifiers"),
-                         int_n_data[specs->int_n_idx].bitsize);
+                         int_n_data[specs->u.int_n_idx].bitsize);
              else if (specs->short_p)
                error_at (loc,
                          ("both %<__int%d%> and %<short%> in "
                           "declaration specifiers"),
-                         int_n_data[specs->int_n_idx].bitsize);
-             else if (! int_n_enabled_p[specs->int_n_idx])
+                         int_n_data[specs->u.int_n_idx].bitsize);
+             else if (! int_n_enabled_p[specs->u.int_n_idx])
                {
                  specs->typespec_word = cts_int_n;
                  error_at (loc,
                            "%<__int%d%> is not supported on this target",
-                           int_n_data[specs->int_n_idx].bitsize);
+                           int_n_data[specs->u.int_n_idx].bitsize);
                }
              else
                {
@@ -12115,12 +12138,12 @@ declspecs_add_type (location_t loc, stru
                }
              return specs;
            CASE_RID_FLOATN_NX:
-             specs->floatn_nx_idx = i - RID_FLOATN_NX_FIRST;
+             specs->u.floatn_nx_idx = i - RID_FLOATN_NX_FIRST;
              if (!in_system_header_at (input_location))
                pedwarn (loc, OPT_Wpedantic,
                         "ISO C does not support the %<_Float%d%s%> type",
-                        floatn_nx_types[specs->floatn_nx_idx].n,
-                        (floatn_nx_types[specs->floatn_nx_idx].extended
+                        floatn_nx_types[specs->u.floatn_nx_idx].n,
+                        (floatn_nx_types[specs->u.floatn_nx_idx].extended
                          ? "x"
                          : ""));
 
@@ -12128,49 +12151,49 @@ declspecs_add_type (location_t loc, stru
                error_at (loc,
                          ("both %<long%> and %<_Float%d%s%> in "
                           "declaration specifiers"),
-                         floatn_nx_types[specs->floatn_nx_idx].n,
-                         (floatn_nx_types[specs->floatn_nx_idx].extended
+                         floatn_nx_types[specs->u.floatn_nx_idx].n,
+                         (floatn_nx_types[specs->u.floatn_nx_idx].extended
                           ? "x"
                           : ""));
              else if (specs->short_p)
                error_at (loc,
                          ("both %<short%> and %<_Float%d%s%> in "
                           "declaration specifiers"),
-                         floatn_nx_types[specs->floatn_nx_idx].n,
-                         (floatn_nx_types[specs->floatn_nx_idx].extended
+                         floatn_nx_types[specs->u.floatn_nx_idx].n,
+                         (floatn_nx_types[specs->u.floatn_nx_idx].extended
                           ? "x"
                           : ""));
              else if (specs->signed_p)
                error_at (loc,
                          ("both %<signed%> and %<_Float%d%s%> in "
                           "declaration specifiers"),
-                         floatn_nx_types[specs->floatn_nx_idx].n,
-                         (floatn_nx_types[specs->floatn_nx_idx].extended
+                         floatn_nx_types[specs->u.floatn_nx_idx].n,
+                         (floatn_nx_types[specs->u.floatn_nx_idx].extended
                           ? "x"
                           : ""));
              else if (specs->unsigned_p)
                error_at (loc,
                          ("both %<unsigned%> and %<_Float%d%s%> in "
                           "declaration specifiers"),
-                         floatn_nx_types[specs->floatn_nx_idx].n,
-                         (floatn_nx_types[specs->floatn_nx_idx].extended
+                         floatn_nx_types[specs->u.floatn_nx_idx].n,
+                         (floatn_nx_types[specs->u.floatn_nx_idx].extended
                           ? "x"
                           : ""));
              else if (specs->saturating_p)
                error_at (loc,
                          ("both %<_Sat%> and %<_Float%d%s%> in "
                           "declaration specifiers"),
-                         floatn_nx_types[specs->floatn_nx_idx].n,
-                         (floatn_nx_types[specs->floatn_nx_idx].extended
+                         floatn_nx_types[specs->u.floatn_nx_idx].n,
+                         (floatn_nx_types[specs->u.floatn_nx_idx].extended
                           ? "x"
                           : ""));
-             else if (FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx) == NULL_TREE)
+             else if (FLOATN_NX_TYPE_NODE (specs->u.floatn_nx_idx) == 
NULL_TREE)
                {
                  specs->typespec_word = cts_floatn_nx;
                  error_at (loc,
                            "%<_Float%d%s%> is not supported on this target",
-                           floatn_nx_types[specs->floatn_nx_idx].n,
-                           (floatn_nx_types[specs->floatn_nx_idx].extended
+                           floatn_nx_types[specs->u.floatn_nx_idx].n,
+                           (floatn_nx_types[specs->u.floatn_nx_idx].extended
                             ? "x"
                             : ""));
                }
@@ -12267,6 +12290,63 @@ declspecs_add_type (location_t loc, stru
              pedwarn (loc, OPT_Wpedantic,
                       "ISO C does not support fixed-point types");
              return specs;
+           case RID_BITINT:
+             if (specs->long_p)
+               error_at (loc,
+                         ("both %<long%> and %<_BitInt%> in "
+                          "declaration specifiers"));
+             else if (specs->short_p)
+               error_at (loc,
+                         ("both %<short%> and %<_BitInt%> in "
+                          "declaration specifiers"));
+             else if (specs->complex_p)
+               error_at (loc,
+                         ("both %<complex%> and %<_BitInt%> in "
+                          "declaration specifiers"));
+             else if (specs->saturating_p)
+               error_at (loc,
+                         ("both %<_Sat%> and %<_BitInt%> in "
+                          "declaration specifiers"));
+             else
+               {
+                 specs->typespec_word = cts_bitint;
+                 specs->locations[cdw_typespec] = loc;
+                 specs->u.bitint_prec = -1;
+                 if (error_operand_p (spec.expr))
+                   return specs;
+                 if (TREE_CODE (spec.expr) != INTEGER_CST
+                     || !INTEGRAL_TYPE_P (TREE_TYPE (spec.expr)))
+                   {
+                     error_at (loc, "%<_BitInt%> argument is not an integer "
+                                    "constant expression");
+                     return specs;
+                   }
+                 if (tree_int_cst_sgn (spec.expr) <= 0)
+                   {
+                     error_at (loc, "%<_BitInt%> argument %qE is not "
+                                    "positive integer constant expression",
+                               spec.expr);
+                     return specs;
+                   }
+                 if (wi::to_widest (spec.expr) > WIDE_INT_MAX_PRECISION - 1)
+                   {
+                     error_at (loc, "%<_BitInt%> argument %qE is larger than "
+                                    "%<BITINT_MAXWIDTH%> %qd",
+                               spec.expr, (int) WIDE_INT_MAX_PRECISION - 1);
+                     return specs;
+                   }
+                 specs->u.bitint_prec = tree_to_uhwi (spec.expr);
+                 struct bitint_info info;
+                 if (!targetm.c.bitint_type_info (specs->u.bitint_prec,
+                                                  &info))
+                   {
+                     sorry_at (loc, "%<_BitInt(%d)%> is not supported on "
+                                    "this target", specs->u.bitint_prec);
+                     specs->u.bitint_prec = -1;
+                     return specs;
+                   }
+               }
+             return specs;
            default:
              /* ObjC reserved word "id", handled below.  */
              break;
@@ -12668,12 +12748,12 @@ finish_declspecs (struct c_declspecs *sp
     case cts_int_n:
       gcc_assert (!specs->long_p && !specs->short_p && !specs->long_long_p);
       gcc_assert (!(specs->signed_p && specs->unsigned_p));
-      if (! int_n_enabled_p[specs->int_n_idx])
+      if (! int_n_enabled_p[specs->u.int_n_idx])
        specs->type = integer_type_node;
       else
        specs->type = (specs->unsigned_p
-                      ? int_n_trees[specs->int_n_idx].unsigned_type
-                      : int_n_trees[specs->int_n_idx].signed_type);
+                      ? int_n_trees[specs->u.int_n_idx].unsigned_type
+                      : int_n_trees[specs->u.int_n_idx].signed_type);
       if (specs->complex_p)
        {
          pedwarn (specs->locations[cdw_complex], OPT_Wpedantic,
@@ -12733,12 +12813,12 @@ finish_declspecs (struct c_declspecs *sp
     case cts_floatn_nx:
       gcc_assert (!specs->long_p && !specs->short_p
                  && !specs->signed_p && !specs->unsigned_p);
-      if (FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx) == NULL_TREE)
+      if (FLOATN_NX_TYPE_NODE (specs->u.floatn_nx_idx) == NULL_TREE)
        specs->type = integer_type_node;
       else if (specs->complex_p)
-       specs->type = COMPLEX_FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx);
+       specs->type = COMPLEX_FLOATN_NX_TYPE_NODE (specs->u.floatn_nx_idx);
       else
-       specs->type = FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx);
+       specs->type = FLOATN_NX_TYPE_NODE (specs->u.floatn_nx_idx);
       break;
     case cts_dfloat32:
     case cts_dfloat64:
@@ -12840,6 +12920,22 @@ finish_declspecs (struct c_declspecs *sp
                          : accum_type_node;
        }
       break;
+    case cts_bitint:
+      gcc_assert (!specs->long_p && !specs->short_p
+                 && !specs->complex_p);
+      if (!specs->unsigned_p && specs->u.bitint_prec == 1)
+       {
+         error_at (specs->locations[cdw_typespec],
+                   "%<signed _BitInt%> argument must be at least 2");
+         specs->type = integer_type_node;
+         break;
+       }
+      if (specs->u.bitint_prec == -1)
+       specs->type = integer_type_node;
+      else
+       specs->type = build_bitint_type (specs->u.bitint_prec,
+                                        specs->unsigned_p);
+      break;
     default:
       gcc_unreachable ();
     }
--- gcc/c/c-parser.cc.jj        2023-08-08 15:55:05.286181541 +0200
+++ gcc/c/c-parser.cc   2023-08-08 16:12:02.336939700 +0200
@@ -580,6 +580,7 @@ c_keyword_starts_typename (enum rid keyw
     case RID_DFLOAT128:
     CASE_RID_FLOATN_NX:
     case RID_BOOL:
+    case RID_BITINT:
     case RID_ENUM:
     case RID_STRUCT:
     case RID_UNION:
@@ -783,6 +784,7 @@ c_token_starts_declspecs (c_token *token
        case RID_DFLOAT128:
        CASE_RID_FLOATN_NX:
        case RID_BOOL:
+       case RID_BITINT:
        case RID_ENUM:
        case RID_STRUCT:
        case RID_UNION:
@@ -3358,6 +3360,30 @@ c_parser_declspecs (c_parser *parser, st
          t = c_parser_typeof_specifier (parser);
          declspecs_add_type (loc, specs, t);
          break;
+       case RID_BITINT:
+         if (!typespec_ok)
+           goto out;
+         else
+           {
+             attrs_ok = true;
+             seen_type = true;
+             t.kind = ctsk_resword;
+             t.spec = c_parser_peek_token (parser)->value;
+             t.expr = error_mark_node;
+             t.expr_const_operands = true;
+             t.has_enum_type_specifier = false;
+             c_parser_consume_token (parser);
+             matching_parens parens;
+             if (parens.require_open (parser))
+               {
+                 c_expr expr = c_parser_expr_no_commas (parser, NULL);
+                 t.expr = convert_lvalue_to_rvalue (loc, expr, true,
+                                                    true).value;
+                 parens.skip_until_found_close (parser);
+               }
+             declspecs_add_type (loc, specs, t);
+           }
+         break;
        case RID_ATOMIC:
          /* C parser handling of Objective-C constructs needs
             checking for correct lvalue-to-rvalue conversions, and
@@ -5005,6 +5031,7 @@ c_parser_gnu_attribute_any_word (c_parse
        case RID_DFLOAT128:
        CASE_RID_FLOATN_NX:
        case RID_BOOL:
+       case RID_BITINT:
        case RID_FRACT:
        case RID_ACCUM:
        case RID_SAT:
--- gcc/c/c-tree.h.jj   2023-08-08 15:54:33.812622298 +0200
+++ gcc/c/c-tree.h      2023-08-08 16:12:02.336939700 +0200
@@ -270,7 +270,7 @@ enum c_storage_class {
 
 /* A type specifier keyword "void", "_Bool", "char", "int", "float",
    "double", "_Decimal32", "_Decimal64", "_Decimal128", "_Fract", "_Accum",
-   or none of these.  */
+   "_BitInt", or none of these.  */
 enum c_typespec_keyword {
   cts_none,
   cts_void,
@@ -286,6 +286,7 @@ enum c_typespec_keyword {
   cts_floatn_nx,
   cts_fract,
   cts_accum,
+  cts_bitint,
   cts_auto_type
 };
 
@@ -366,11 +367,16 @@ struct c_declspecs {
      specifier, in bytes, or -1 if no such specifiers with nonzero
      alignment.  */
   int align_log;
-  /* For the __intN declspec, this stores the index into the int_n_* arrays.  
*/
-  int int_n_idx;
-  /* For the _FloatN and _FloatNx declspec, this stores the index into
-     the floatn_nx_types array.  */
-  int floatn_nx_idx;
+  union {
+    /* For the __intN declspec, this stores the index into the int_n_*
+       arrays.  */
+    int int_n_idx;
+    /* For the _FloatN and _FloatNx declspec, this stores the index into
+       the floatn_nx_types array.  */
+    int floatn_nx_idx;
+    /* For _BitInt(N) this stores the N.  */
+    int bitint_prec;
+  } u;
   /* The storage class specifier, or csc_none if none.  */
   enum c_storage_class storage_class;
   /* Any type specifier keyword used such as "int", not reflecting
--- gcc/c/c-typeck.cc.jj        2023-08-08 15:54:33.822622158 +0200
+++ gcc/c/c-typeck.cc   2023-08-08 16:15:41.008877766 +0200
@@ -413,10 +413,14 @@ composite_type (tree t1, tree t2)
      the composite type.  */
 
   if (code1 == ENUMERAL_TYPE
-      && (code2 == INTEGER_TYPE || code2 == BOOLEAN_TYPE))
+      && (code2 == INTEGER_TYPE
+         || code2 == BOOLEAN_TYPE
+         || code2 == BITINT_TYPE))
     return t1;
   if (code2 == ENUMERAL_TYPE
-      && (code1 == INTEGER_TYPE || code1 == BOOLEAN_TYPE))
+      && (code1 == INTEGER_TYPE
+         || code1 == BOOLEAN_TYPE
+         || code1 == BITINT_TYPE))
     return t2;
 
   gcc_assert (code1 == code2);
@@ -764,10 +768,10 @@ c_common_type (tree t1, tree t2)
 
   gcc_assert (code1 == VECTOR_TYPE || code1 == COMPLEX_TYPE
              || code1 == FIXED_POINT_TYPE || code1 == REAL_TYPE
-             || code1 == INTEGER_TYPE);
+             || code1 == INTEGER_TYPE || code1 == BITINT_TYPE);
   gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE
              || code2 == FIXED_POINT_TYPE || code2 == REAL_TYPE
-             || code2 == INTEGER_TYPE);
+             || code2 == INTEGER_TYPE || code2 == BITINT_TYPE);
 
   /* When one operand is a decimal float type, the other operand cannot be
      a generic float type or a complex type.  We also disallow vector types
@@ -1004,6 +1008,20 @@ c_common_type (tree t1, tree t2)
     if (mv1 == FLOATNX_TYPE_NODE (i) || mv2 == FLOATNX_TYPE_NODE (i))
       return FLOATNX_TYPE_NODE (i);
 
+  if ((code1 == BITINT_TYPE || code2 == BITINT_TYPE) && code1 != code2)
+    {
+      /* Prefer any other integral types over bit-precise integer types.  */
+      if (TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2))
+       return code1 == BITINT_TYPE ? t2 : t1;
+      /* If BITINT_TYPE is unsigned and the other type is signed
+        non-BITINT_TYPE with the same precision, the latter has higher rank.
+        In that case:
+        Otherwise, both operands are converted to the unsigned integer type
+        corresponding to the type of the operand with signed integer type.  */
+      if (TYPE_UNSIGNED (code1 == BITINT_TYPE ? t1 : t2))
+       return c_common_unsigned_type (code1 == BITINT_TYPE ? t2 : t1);
+    }
+
   /* Otherwise prefer the unsigned one.  */
 
   if (TYPE_UNSIGNED (t1))
@@ -1177,6 +1195,7 @@ comptypes_internal (const_tree type1, co
     case INTEGER_TYPE:
     case FIXED_POINT_TYPE:
     case REAL_TYPE:
+    case BITINT_TYPE:
       /* With these nodes, we can't determine type equivalence by
         looking at what is stored in the nodes themselves, because
         two nodes might have different TYPE_MAIN_VARIANTs but still
@@ -2260,12 +2279,17 @@ perform_integral_promotions (tree exp)
   /* ??? This should no longer be needed now bit-fields have their
      proper types.  */
   if (TREE_CODE (exp) == COMPONENT_REF
-      && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1))
+      && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1)))
+    {
+      if (TREE_CODE (DECL_BIT_FIELD_TYPE (TREE_OPERAND (exp, 1)))
+         == BITINT_TYPE)
+       return convert (DECL_BIT_FIELD_TYPE (TREE_OPERAND (exp, 1)), exp);
       /* If it's thinner than an int, promote it like a
         c_promoting_integer_type_p, otherwise leave it alone.  */
-      && compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)),
-                          TYPE_PRECISION (integer_type_node)) < 0)
-    return convert (integer_type_node, exp);
+      if (compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)),
+                           TYPE_PRECISION (integer_type_node)) < 0)
+       return convert (integer_type_node, exp);
+    }
 
   if (c_promoting_integer_type_p (type))
     {
@@ -2790,7 +2814,8 @@ build_array_ref (location_t loc, tree ar
   if (index == error_mark_node)
     return error_mark_node;
 
-  gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE);
+  gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE
+             || TREE_CODE (TREE_TYPE (index)) == BITINT_TYPE);
 
   bool was_vector = VECTOR_TYPE_P (TREE_TYPE (array));
   bool non_lvalue = convert_vector_to_array_for_subscript (loc, &array, index);
@@ -4558,6 +4583,7 @@ build_unary_op (location_t location, enu
         associativity, but won't generate any code.  */
       if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
            || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE
+           || typecode == BITINT_TYPE
            || gnu_vector_type_p (TREE_TYPE (arg))))
        {
          error_at (location, "wrong type argument to unary plus");
@@ -4571,6 +4597,7 @@ build_unary_op (location_t location, enu
     case NEGATE_EXPR:
       if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
            || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE
+           || typecode == BITINT_TYPE
            || gnu_vector_type_p (TREE_TYPE (arg))))
        {
          error_at (location, "wrong type argument to unary minus");
@@ -4583,6 +4610,7 @@ build_unary_op (location_t location, enu
     case BIT_NOT_EXPR:
       /* ~ works on integer types and non float vectors. */
       if (typecode == INTEGER_TYPE
+         || typecode == BITINT_TYPE
          || (gnu_vector_type_p (TREE_TYPE (arg))
              && !VECTOR_FLOAT_TYPE_P (TREE_TYPE (arg))))
        {
@@ -4657,7 +4685,8 @@ build_unary_op (location_t location, enu
     case TRUTH_NOT_EXPR:
       if (typecode != INTEGER_TYPE && typecode != FIXED_POINT_TYPE
          && typecode != REAL_TYPE && typecode != POINTER_TYPE
-         && typecode != COMPLEX_TYPE && typecode != NULLPTR_TYPE)
+         && typecode != COMPLEX_TYPE && typecode != NULLPTR_TYPE
+         && typecode != BITINT_TYPE)
        {
          error_at (location,
                    "wrong type argument to unary exclamation mark");
@@ -4769,7 +4798,7 @@ build_unary_op (location_t location, enu
 
       if (typecode != POINTER_TYPE && typecode != FIXED_POINT_TYPE
          && typecode != INTEGER_TYPE && typecode != REAL_TYPE
-         && typecode != COMPLEX_TYPE
+         && typecode != COMPLEX_TYPE && typecode != BITINT_TYPE
          && !gnu_vector_type_p (TREE_TYPE (arg)))
        {
          if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
@@ -5394,9 +5423,9 @@ build_conditional_expr (location_t colon
        result_type = TYPE_MAIN_VARIANT (type1);
     }
   else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE
-           || code1 == COMPLEX_TYPE)
+           || code1 == COMPLEX_TYPE || code1 == BITINT_TYPE)
           && (code2 == INTEGER_TYPE || code2 == REAL_TYPE
-              || code2 == COMPLEX_TYPE))
+              || code2 == COMPLEX_TYPE || code2 == BITINT_TYPE))
     {
       /* In C11, a conditional expression between a floating-point
         type and an integer type should convert the integer type to
@@ -5583,7 +5612,8 @@ build_conditional_expr (location_t colon
                          (build_qualified_type (void_type_node, qual));
        }
     }
-  else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
+  else if (code1 == POINTER_TYPE
+          && (code2 == INTEGER_TYPE || code2 == BITINT_TYPE))
     {
       if (!null_pointer_constant_p (orig_op2))
        pedwarn (colon_loc, 0,
@@ -5594,7 +5624,8 @@ build_conditional_expr (location_t colon
        }
       result_type = type1;
     }
-  else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
+  else if (code2 == POINTER_TYPE
+          && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
     {
       if (!null_pointer_constant_p (orig_op1))
        pedwarn (colon_loc, 0,
@@ -7131,11 +7162,11 @@ convert_for_assignment (location_t locat
   else if ((codel == INTEGER_TYPE || codel == REAL_TYPE
            || codel == FIXED_POINT_TYPE
            || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE
-           || codel == BOOLEAN_TYPE)
+           || codel == BOOLEAN_TYPE || codel == BITINT_TYPE)
           && (coder == INTEGER_TYPE || coder == REAL_TYPE
               || coder == FIXED_POINT_TYPE
               || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE
-              || coder == BOOLEAN_TYPE))
+              || coder == BOOLEAN_TYPE || coder == BITINT_TYPE))
     {
       if (warnopt && errtype == ic_argpass)
        maybe_warn_builtin_no_proto_arg (expr_loc, fundecl, parmnum, type,
@@ -8562,7 +8593,8 @@ digest_init (location_t init_loc, tree t
 
   if (code == INTEGER_TYPE || code == REAL_TYPE || code == FIXED_POINT_TYPE
       || code == POINTER_TYPE || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE
-      || code == COMPLEX_TYPE || code == VECTOR_TYPE || code == NULLPTR_TYPE)
+      || code == COMPLEX_TYPE || code == VECTOR_TYPE || code == NULLPTR_TYPE
+      || code == BITINT_TYPE)
     {
       tree unconverted_init = inside_init;
       if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
@@ -12357,12 +12389,14 @@ build_binary_op (location_t location, en
     {
     case PLUS_EXPR:
       /* Handle the pointer + int case.  */
-      if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+      if (code0 == POINTER_TYPE
+         && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
        {
          ret = pointer_int_sum (location, PLUS_EXPR, op0, op1);
          goto return_build_binary_op;
        }
-      else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
+      else if (code1 == POINTER_TYPE
+              && (code0 == INTEGER_TYPE || code0 == BITINT_TYPE))
        {
          ret = pointer_int_sum (location, PLUS_EXPR, op1, op0);
          goto return_build_binary_op;
@@ -12381,7 +12415,8 @@ build_binary_op (location_t location, en
          goto return_build_binary_op;
        }
       /* Handle pointer minus int.  Just like pointer plus int.  */
-      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+      else if (code0 == POINTER_TYPE
+              && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
        {
          ret = pointer_int_sum (location, MINUS_EXPR, op0, op1);
          goto return_build_binary_op;
@@ -12403,11 +12438,11 @@ build_binary_op (location_t location, en
       warn_for_div_by_zero (location, op1);
 
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
-          || code0 == FIXED_POINT_TYPE
+          || code0 == FIXED_POINT_TYPE || code0 == BITINT_TYPE
           || code0 == COMPLEX_TYPE
           || gnu_vector_type_p (type0))
          && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
-             || code1 == FIXED_POINT_TYPE
+             || code1 == FIXED_POINT_TYPE || code1 == BITINT_TYPE
              || code1 == COMPLEX_TYPE
              || gnu_vector_type_p (type1)))
        {
@@ -12418,8 +12453,9 @@ build_binary_op (location_t location, en
          if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)
            tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
 
-         if (!((tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE)
-             || (tcode0 == FIXED_POINT_TYPE && tcode1 == FIXED_POINT_TYPE)))
+         if (!(((tcode0 == INTEGER_TYPE || tcode0 == BITINT_TYPE)
+                && (tcode1 == INTEGER_TYPE || tcode1 == BITINT_TYPE))
+               || (tcode0 == FIXED_POINT_TYPE && tcode1 == FIXED_POINT_TYPE)))
            resultcode = RDIV_EXPR;
          else
            /* Although it would be tempting to shorten always here, that
@@ -12435,7 +12471,8 @@ build_binary_op (location_t location, en
     case BIT_AND_EXPR:
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
-      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+      if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE)
+         && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
        shorten = -1;
       /* Allow vector types which are not floating point types.   */
       else if (gnu_vector_type_p (type0)
@@ -12455,7 +12492,8 @@ build_binary_op (location_t location, en
          && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE
          && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
        common = 1;
-      else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+      else if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE)
+              && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
        {
          /* Although it would be tempting to shorten always here, that loses
             on some targets, since the modulo instruction is undefined if the
@@ -12473,10 +12511,12 @@ build_binary_op (location_t location, en
     case TRUTH_XOR_EXPR:
       if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE
           || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
-          || code0 == FIXED_POINT_TYPE || code0 == NULLPTR_TYPE)
+          || code0 == FIXED_POINT_TYPE || code0 == NULLPTR_TYPE
+          || code0 == BITINT_TYPE)
          && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE
              || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
-             || code1 == FIXED_POINT_TYPE || code1 ==  NULLPTR_TYPE))
+             || code1 == FIXED_POINT_TYPE || code1 == NULLPTR_TYPE
+             || code1 == BITINT_TYPE))
        {
          /* Result of these operations is always an int,
             but that does not mean the operands should be
@@ -12539,9 +12579,10 @@ build_binary_op (location_t location, en
          converted = 1;
        }
       else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE
+               || code0 == BITINT_TYPE
                || (gnu_vector_type_p (type0)
                    && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE))
-              && code1 == INTEGER_TYPE)
+              && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
        {
          doing_shift = true;
          if (TREE_CODE (op1) == INTEGER_CST)
@@ -12599,9 +12640,10 @@ build_binary_op (location_t location, en
          converted = 1;
        }
       else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE
+               || code0 == BITINT_TYPE
                || (gnu_vector_type_p (type0)
                    && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE))
-              && code1 == INTEGER_TYPE)
+              && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
        {
          doing_shift = true;
          if (TREE_CODE (op0) == INTEGER_CST
@@ -12715,9 +12757,10 @@ build_binary_op (location_t location, en
       /* Result of comparison is always int,
         but don't convert the args to int!  */
       build_type = integer_type_node;
-      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == BITINT_TYPE
           || code0 == FIXED_POINT_TYPE || code0 == COMPLEX_TYPE)
          && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+             || code1 == BITINT_TYPE
              || code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE))
        short_compare = 1;
       else if (code0 == POINTER_TYPE
@@ -12778,12 +12821,14 @@ build_binary_op (location_t location, en
                              (build_qualified_type (void_type_node, qual));
            }
        }
-      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+      else if (code0 == POINTER_TYPE
+              && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
        {
          result_type = type0;
          pedwarn (location, 0, "comparison between pointer and integer");
        }
-      else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
+      else if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE)
+              && code1 == POINTER_TYPE)
        {
          result_type = type1;
          pedwarn (location, 0, "comparison between pointer and integer");
@@ -12871,9 +12916,9 @@ build_binary_op (location_t location, en
         }
       build_type = integer_type_node;
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
-          || code0 == FIXED_POINT_TYPE)
+          || code0 == BITINT_TYPE || code0 == FIXED_POINT_TYPE)
          && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
-             || code1 == FIXED_POINT_TYPE))
+             || code1 == BITINT_TYPE || code1 == FIXED_POINT_TYPE))
        short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        {
@@ -12932,12 +12977,14 @@ build_binary_op (location_t location, en
            warning_at (location, OPT_Wextra,
                        "ordered comparison of pointer with integer zero");
        }
-      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+      else if (code0 == POINTER_TYPE
+              && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
        {
          result_type = type0;
          pedwarn (location, 0, "comparison between pointer and integer");
        }
-      else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
+      else if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE)
+              && code1 == POINTER_TYPE)
        {
          result_type = type1;
          pedwarn (location, 0, "comparison between pointer and integer");
@@ -12991,12 +13038,11 @@ build_binary_op (location_t location, en
     }
 
   if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
-       || code0 == FIXED_POINT_TYPE
+       || code0 == FIXED_POINT_TYPE || code0 == BITINT_TYPE
        || gnu_vector_type_p (type0))
-      &&
-      (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
-       || code1 == FIXED_POINT_TYPE
-       || gnu_vector_type_p (type1)))
+      && (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
+         || code1 == FIXED_POINT_TYPE || code1 == BITINT_TYPE
+         || gnu_vector_type_p (type1)))
     {
       bool first_complex = (code0 == COMPLEX_TYPE);
       bool second_complex = (code1 == COMPLEX_TYPE);
--- libcpp/expr.cc.jj   2023-08-08 15:54:35.666596337 +0200
+++ libcpp/expr.cc      2023-08-08 16:12:02.346939560 +0200
@@ -327,9 +327,9 @@ static unsigned int
 interpret_int_suffix (cpp_reader *pfile, const uchar *s, size_t len)
 {
   size_t orig_len = len;
-  size_t u, l, i, z;
+  size_t u, l, i, z, wb;
 
-  u = l = i = z = 0;
+  u = l = i = z = wb = 0;
 
   while (len--)
     switch (s[len])
@@ -343,11 +343,23 @@ interpret_int_suffix (cpp_reader *pfile,
        if (l == 2 && s[len] != s[len + 1])
          return 0;
        break;
+      case 'b':
+       if (len == 0 || s[len - 1] != 'w')
+         return 0;
+       wb++;
+       len--;
+       break;
+      case 'B':
+       if (len == 0 || s[len - 1] != 'W')
+         return 0;
+       wb++;
+       len--;
+       break;
       default:
        return 0;
       }
 
-  if (l > 2 || u > 1 || i > 1 || z > 1)
+  if (l > 2 || u > 1 || i > 1 || z > 1 || wb > 1)
     return 0;
 
   if (z)
@@ -358,6 +370,14 @@ interpret_int_suffix (cpp_reader *pfile,
        return 0;
     }
 
+  if (wb)
+    {
+      if (CPP_OPTION (pfile, cplusplus))
+       return 0;
+      if (l > 0 || i > 0 || z > 0)
+       return 0;
+    }
+
   if (i)
     {
       if (!CPP_OPTION (pfile, ext_numeric_literals))
@@ -376,7 +396,8 @@ interpret_int_suffix (cpp_reader *pfile,
          | (u ? CPP_N_UNSIGNED : 0)
          | ((l == 0) ? CPP_N_SMALL
             : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE)
-         | (z ? CPP_N_SIZE_T : 0));
+         | (z ? CPP_N_SIZE_T : 0)
+         | (wb ? CPP_N_BITINT : 0));
 }
 
 /* Return the classification flags for an int suffix.  */
--- libcpp/include/cpplib.h.jj  2023-08-08 15:54:35.691595987 +0200
+++ libcpp/include/cpplib.h     2023-08-08 16:12:02.346939560 +0200
@@ -1284,6 +1284,7 @@ struct cpp_num
 
 #define CPP_N_SIZE_T   0x2000000 /* C++23 size_t literal.  */
 #define CPP_N_BFLOAT16 0x4000000 /* std::bfloat16_t type.  */
+#define CPP_N_BITINT   0x8000000 /* C2X _BitInt literal.  */
 
 #define CPP_N_WIDTH_FLOATN_NX  0xF0000000 /* _FloatN / _FloatNx value
                                              of N, divided by 16.  */

        Jakub

Reply via email to