Hi Andrew,

On Mon, Oct 13, 2025 at 03:45:20PM -0700, Andrew Pinski wrote:
> On Mon, Oct 13, 2025 at 3:34 PM Alejandro Colomar <[email protected]> wrote:
> >
> > Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3628.txt>
[...]
> > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > index 54e16f708134..2127ba41e94f 100644
> > --- a/gcc/c-family/c-common.cc
> > +++ b/gcc/c-family/c-common.cc
[...]
> > @@ -4130,6 +4132,46 @@ c_countof_type (location_t loc, tree type)
> >    return array_type_nelts_top (type);
> >  }
> >
> > +/* Implement the _Maxof operator:
> > +   Return the maximum representable value of an integer type.  */
> > +
> > +tree
> > +c_maxof_type (location_t loc, tree type)
> > +{
> > +  enum tree_code type_code;
> > +
> > +  type_code = TREE_CODE (type);
> > +  if (type_code != INTEGER_TYPE
> > +      && type_code != BITINT_TYPE
> > +      && type_code != ENUMERAL_TYPE)
> 
> It seems like bool should be handled the same way as the other integer
> types too.

I thought about that while implementing it, and I left bool unsupported
on purpose.  The proposal I wrote for C2y fails to exclude bool, though.

The thing is, bool is not a regular integer type, and I'm not sure it
should be supported (does it make any sense?), so I prefer leaving it
out.  We're always in time to add support for it later.

> If it is supposed to work with bool then you could just use:
> if (!INTEGRAL_TYPE_P (type))
> or if not then why not just use:
> if (!INTEGRAL_TYPE_P (type)
>    || TREE_CODE (type) == BOOLEAN_TYPE)

Thanks!  This seems more readable.  It makes it explicit that we
exclude bool on purpose.

[...]
> > +    {
> > +      error_at (loc, "invalid application of %<_Minof%> to type %qT", 
> > type);
> > +      return error_mark_node;
> > +    }
> > +
> > +  return TYPE_MIN_VALUE (type);
> > +}
> > +
> >  /* Handle C and C++ default attributes.  */
> >
> >  enum built_in_attribute
> > diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def
> > index 0bcc4998afe6..9b1f034579b7 100644
> > --- a/gcc/c-family/c-common.def
> > +++ b/gcc/c-family/c-common.def
> > @@ -53,6 +53,12 @@ DEFTREECODE (USERDEF_LITERAL, "userdef_literal", 
> > tcc_exceptional, 3)
> >  /* Represents a 'countof' expression.  */
> >  DEFTREECODE (COUNTOF_EXPR, "countof_expr", tcc_expression, 1)
> >
> > +/* Represents a 'maxof' expression.  */
> > +DEFTREECODE (MAXOF_EXPR, "maxof_expr", tcc_expression, 1)
> > +
> > +/* Represents a 'minof' expression.  */
> > +DEFTREECODE (MINOF_EXPR, "minof_expr", tcc_expression, 1)
> > +
> >  /* Represents a 'sizeof' expression during C++ template expansion,
> >     or for the purpose of -Wsizeof-pointer-memaccess warning.  */
> >  DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1)
> > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > index bedbd4a94b0e..5c4edf1527a3 100644
> > --- a/gcc/c-family/c-common.h
> > +++ b/gcc/c-family/c-common.h
> > @@ -105,7 +105,7 @@ enum rid
> >
> >    /* C extensions */
> >    RID_ASM,       RID_TYPEOF,   RID_TYPEOF_UNQUAL, RID_ALIGNOF,  
> > RID_ATTRIBUTE,
> > -  RID_COUNTOF,
> > +  RID_COUNTOF,   RID_MAXOF,    RID_MINOF,
> >    RID_C23_VA_START, RID_VA_ARG,
> >    RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
> >    RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,       
> > RID_BUILTIN_SHUFFLE,
> > @@ -893,6 +893,8 @@ extern void c_apply_type_quals_to_decl (int, tree);
> >  extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
> >  extern tree c_alignof_expr (location_t, tree);
> >  extern tree c_countof_type (location_t, tree);
> > +extern tree c_maxof_type (location_t, tree);
> > +extern tree c_minof_type (location_t, tree);
> >  /* Print an error message for invalid operands to arith operation CODE.
> >     NOP_EXPR is used as a special case (see truthvalue_conversion).  */
> >  extern void binary_op_error (rich_location *, enum tree_code, tree, tree);
> > diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
> > index ea0294f0738e..67ce19469963 100644
> > --- a/gcc/c/c-parser.cc
> > +++ b/gcc/c/c-parser.cc
> > @@ -1787,6 +1787,9 @@ static inline struct c_expr 
> > c_parser_countof_expression (c_parser *);
> >  static struct c_expr c_parser_sizeof_or_countof_expression (c_parser *,
> >                                                             enum rid);
> >  static struct c_expr c_parser_alignof_expression (c_parser *);
> > +static inline struct c_expr c_parser_maxof_expression (c_parser *);
> > +static inline struct c_expr c_parser_minof_expression (c_parser *);
> > +static struct c_expr c_parser_maxof_or_minof_expression (c_parser *, enum 
> > rid);
> >  static struct c_expr c_parser_postfix_expression (c_parser *);
> >  static struct c_expr c_parser_postfix_expression_after_paren_type 
> > (c_parser *,
> >                                                                    struct 
> > c_declspecs *,
> > @@ -10513,8 +10516,12 @@ c_parser_cast_expression (c_parser *parser, struct 
> > c_expr *after)
> >       _Countof ( type-name )
> >       sizeof unary-expression
> >       sizeof ( type-name )
> > +     _Maxof unary-expression
> > +     _Maxof ( type-name )
> > +     _Minof unary-expression
> > +     _Minof ( type-name )
> >
> > -   (_Countof is new in C2y.)
> > +   (_Countof, _Maxof, and _Minof are new in C2y.)
> >
> >     unary-operator: one of
> >       & * + - ~ !
> > @@ -10655,6 +10662,10 @@ c_parser_unary_expression (c_parser *parser)
> >           return c_parser_sizeof_expression (parser);
> >         case RID_ALIGNOF:
> >           return c_parser_alignof_expression (parser);
> > +       case RID_MAXOF:
> > +         return c_parser_maxof_expression (parser);
> > +       case RID_MINOF:
> > +         return c_parser_minof_expression (parser);
> 
> Why not just call c_parser_maxof_or_minof_expression for both of these
> and add c_parser_peek_token (parser)->keyword. Like
> c_parser_transaction_expression is handled.
> I suspect c_parser_sizeof_expression should be fixed up that way too.

Good idea.  I propose applying the following patch after this one, to
fix all of these at once.  However, I'd keep the current patch as is
regarding this, to avoid breaking a long line.  The following patch adds
the 'rid' variable, which will make it nicer.  Does it sound good?

        diff --git i/gcc/c/c-parser.cc w/gcc/c/c-parser.cc
        index 67ce19469963..9bf12d4ace2c 100644
        --- i/gcc/c/c-parser.cc
        +++ w/gcc/c/c-parser.cc
        @@ -1782,13 +1782,9 @@ static struct c_expr c_parser_binary_expression 
(c_parser *, struct c_expr *,
                                                         tree);
         static struct c_expr c_parser_cast_expression (c_parser *, struct 
c_expr *);
         static struct c_expr c_parser_unary_expression (c_parser *);
        -static inline struct c_expr c_parser_sizeof_expression (c_parser *);
        -static inline struct c_expr c_parser_countof_expression (c_parser *);
         static struct c_expr c_parser_sizeof_or_countof_expression (c_parser *,
                                                                    enum rid);
         static struct c_expr c_parser_alignof_expression (c_parser *);
        -static inline struct c_expr c_parser_maxof_expression (c_parser *);
        -static inline struct c_expr c_parser_minof_expression (c_parser *);
         static struct c_expr c_parser_maxof_or_minof_expression (c_parser *, 
enum rid);
         static struct c_expr c_parser_postfix_expression (c_parser *);
         static struct c_expr c_parser_postfix_expression_after_paren_type 
(c_parser *,
        @@ -10654,18 +10650,17 @@ c_parser_unary_expression (c_parser *parser)
                }
               return ret;
             case CPP_KEYWORD:
        -      switch (c_parser_peek_token (parser)->keyword)
        +      enum rid rid = c_parser_peek_token (parser)->keyword;
        +      switch (rid)
                {
                case RID_COUNTOF:
        -         return c_parser_countof_expression (parser);
                case RID_SIZEOF:
        -         return c_parser_sizeof_expression (parser);
        +         return c_parser_sizeof_or_countof_expression (parser, rid);
                case RID_ALIGNOF:
                  return c_parser_alignof_expression (parser);
                case RID_MAXOF:
        -         return c_parser_maxof_expression (parser);
                case RID_MINOF:
        -         return c_parser_minof_expression (parser);
        +         return c_parser_maxof_or_minof_expression (parser, rid);
                case RID_BUILTIN_HAS_ATTRIBUTE:
                  return c_parser_has_attribute_expression (parser);
                case RID_EXTENSION:
        @@ -10688,8 +10683,7 @@ c_parser_unary_expression (c_parser *parser)
                  return parser_build_unary_op (op_loc, IMAGPART_EXPR, op);
                case RID_TRANSACTION_ATOMIC:
                case RID_TRANSACTION_RELAXED:
        -         return c_parser_transaction_expression (parser,
        -             c_parser_peek_token (parser)->keyword);
        +         return c_parser_transaction_expression (parser, rid);
                default:
                  return c_parser_postfix_expression (parser);
                }
        @@ -10698,22 +10692,6 @@ c_parser_unary_expression (c_parser *parser)
             }
         }
         
        -/* Parse a sizeof expression.  */
        -
        -static inline struct c_expr
        -c_parser_sizeof_expression (c_parser *parser)
        -{
        -  return c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF);
        -}
        -
        -/* Parse a _Countof expression.  */
        -
        -static inline struct c_expr
        -c_parser_countof_expression (c_parser *parser)
        -{
        -  return c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF);
        -}
        -
         /* Parse a sizeof or _Countof expression.  */
         
         static struct c_expr
        @@ -10916,22 +10894,6 @@ c_parser_alignof_expression (c_parser *parser)
             }
         }
         
        -/* Parse a _Maxof expression.  */
        -
        -static inline struct c_expr
        -c_parser_maxof_expression (c_parser *parser)
        -{
        -  return c_parser_maxof_or_minof_expression (parser, RID_MAXOF);
        -}
        -
        -/* Parse a _Minof expression.  */
        -
        -static inline struct c_expr
        -c_parser_minof_expression (c_parser *parser)
        -{
        -  return c_parser_maxof_or_minof_expression (parser, RID_MINOF);
        -}
        -
         /* Parse a _Maxof or _Minof expression.  */
         
         static struct c_expr

> 
> Thanks,
> Andrew Pinski

Thanks! for the review!

> >         case RID_BUILTIN_HAS_ATTRIBUTE:
> >           return c_parser_has_attribute_expression (parser);
> >         case RID_EXTENSION:
> > @@ -10905,6 +10916,106 @@ c_parser_alignof_expression (c_parser *parser)
> >      }
> >  }
> >
> > +/* Parse a _Maxof expression.  */
> > +
> > +static inline struct c_expr
> > +c_parser_maxof_expression (c_parser *parser)
> > +{
> > +  return c_parser_maxof_or_minof_expression (parser, RID_MAXOF);
> > +}
> > +
> > +/* Parse a _Minof expression.  */
> > +
> > +static inline struct c_expr
> > +c_parser_minof_expression (c_parser *parser)
> > +{
> > +  return c_parser_maxof_or_minof_expression (parser, RID_MINOF);
> > +}
> > +
> > +/* Parse a _Maxof or _Minof expression.  */
> > +
> > +static struct c_expr
> > +c_parser_maxof_or_minof_expression (c_parser *parser, enum rid rid)
> > +{
> > +  const char *op_name = (rid == RID_MAXOF) ? "_Maxof" : "_Minof";
> > +  struct c_expr expr;
> > +  struct c_expr result;
> > +  location_t expr_loc;
> > +  gcc_assert (c_parser_next_token_is_keyword (parser, rid));
> > +
> > +  location_t start;
> > +  location_t finish = UNKNOWN_LOCATION;
> > +
> > +  start = c_parser_peek_token (parser)->location;
> > +
> > +  pedwarn_c23 (start, OPT_Wpedantic,
> > +              "ISO C does not support %qs before C2Y", op_name);
> > +
> > +  c_parser_consume_token (parser);
> > +  c_inhibit_evaluation_warnings++;
> > +  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
> > +      && c_token_starts_compound_literal (c_parser_peek_2nd_token 
> > (parser)))
> > +    {
> > +      /* Either operator ( type-name ) or operator unary-expression
> > +        starting with a compound literal.  */
> > +      struct c_declspecs *scspecs;
> > +      struct c_type_name *type_name;
> > +      matching_parens parens;
> > +      parens.consume_open (parser);
> > +      expr_loc = c_parser_peek_token (parser)->location;
> > +      scspecs = c_parser_compound_literal_scspecs (parser);
> > +      type_name = c_parser_type_name (parser, true);
> > +      parens.skip_until_found_close (parser);
> > +      finish = parser->tokens_buf[0].location;
> > +      if (type_name == NULL)
> > +       {
> > +         /* Let c_expr_*_expr call pop_maybe_used and fill in c_expr
> > +            for parsing error; the parsing of the expression could have
> > +            called record_maybe_used_decl.  */
> > +         expr.set_error ();
> > +         error_at (expr_loc, "%qs XXX: How do we arrive here?", op_name);

Do you know about this?


Have a lovely night!
Alex

> > +         goto Xof_expr;
> > +       }
> > +      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
> > +       {
> > +         expr = c_parser_postfix_expression_after_paren_type (parser, 
> > scspecs,
> > +                                                              type_name,
> > +                                                              expr_loc);
> > +         finish = expr.get_finish ();
> > +         error_at (expr_loc, "invalid application of %qs to a compound 
> > literal",
> > +                   op_name);
> > +         goto Xof_expr;
> > +       }
> > +      /* operator ( type-name ).  */
> > +      if (scspecs)
> > +       error_at (expr_loc, "storage class specifier in %qs", op_name);
> > +      if (type_name->specs->alignas_p)
> > +       error_at (type_name->specs->locations[cdw_alignas],
> > +                 "alignment specified for type name in %qs", op_name);
> > +      c_inhibit_evaluation_warnings--;
> > +      if (rid == RID_MAXOF)
> > +       result = c_expr_maxof_type (expr_loc, type_name);
> > +      else
> > +       result = c_expr_minof_type (expr_loc, type_name);
> > +      set_c_expr_source_range (&result, start, finish);
> > +    }
> > +  else
> > +    {
> > +      expr_loc = c_parser_peek_token (parser)->location;
> > +      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
> > +       error_at (expr_loc, "invalid application of %qs to something not a 
> > type", op_name);
> > +      else
> > +       c_parser_error (parser, "expected %<(%>");
> > +      expr = c_parser_unary_expression (parser);
> > +    Xof_expr:
> > +      c_inhibit_evaluation_warnings--;
> > +      result.set_error ();
> > +      result.original_code = ERROR_MARK;
> > +      result.original_type = NULL;
> > +    }
> > +  return result;
> > +}
> > +
> >  /* Parse the __builtin_has_attribute ([expr|type], attribute-spec)
> >     expression.  */
> >
> > diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
> > index 162add0522ac..6abe98a9f85a 100644
> > --- a/gcc/c/c-tree.h
> > +++ b/gcc/c/c-tree.h
> > @@ -855,6 +855,8 @@ extern struct c_expr c_expr_sizeof_type (location_t, 
> > struct c_type_name *);
> >  extern struct c_expr c_expr_countof_expr (location_t, struct c_expr);
> >  extern struct c_expr c_expr_countof_type (location_t loc,
> >                                           struct c_type_name *);
> > +extern struct c_expr c_expr_maxof_type (location_t loc, struct c_type_name 
> > *);
> > +extern struct c_expr c_expr_minof_type (location_t loc, struct c_type_name 
> > *);
> >  extern struct c_expr parser_build_unary_op (location_t, enum tree_code,
> >                                             struct c_expr);
> >  extern struct c_expr parser_build_binary_op (location_t,
> > diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> > index 371583bd64ed..d8a5819b1e9e 100644
> > --- a/gcc/c/c-typeck.cc
> > +++ b/gcc/c/c-typeck.cc
> > @@ -4117,6 +4117,60 @@ c_expr_countof_type (location_t loc, struct 
> > c_type_name *t)
> >    return ret;
> >  }
> >
> > +/* Return the result of maxof applied to T, a structure for the type
> > +   name passed to maxof (rather than the type itself).  LOC is the
> > +   location of the original expression.  */
> > +
> > +struct c_expr
> > +c_expr_maxof_type (location_t loc, struct c_type_name *t)
> > +{
> > +  tree type;
> > +  struct c_expr ret;
> > +  tree type_expr = NULL_TREE;
> > +  bool type_expr_const = true;
> > +  type = groktypename (t, &type_expr, &type_expr_const);
> > +  ret.value = c_maxof_type (loc, type);
> > +  c_last_sizeof_arg = type;
> > +  c_last_sizeof_loc = loc;
> > +  ret.original_code = MAXOF_EXPR;
> > +  ret.original_type = NULL;
> > +  ret.m_decimal = 0;
> > +  if (type == error_mark_node)
> > +    {
> > +      ret.value = error_mark_node;
> > +      ret.original_code = ERROR_MARK;
> > +    }
> > +  pop_maybe_used (type != error_mark_node);
> > +  return ret;
> > +}
> > +
> > +/* Return the result of minof applied to T, a structure for the type
> > +   name passed to minof (rather than the type itself).  LOC is the
> > +   location of the original expression.  */
> > +
> > +struct c_expr
> > +c_expr_minof_type (location_t loc, struct c_type_name *t)
> > +{
> > +  tree type;
> > +  struct c_expr ret;
> > +  tree type_expr = NULL_TREE;
> > +  bool type_expr_const = true;
> > +  type = groktypename (t, &type_expr, &type_expr_const);
> > +  ret.value = c_minof_type (loc, type);
> > +  c_last_sizeof_arg = type;
> > +  c_last_sizeof_loc = loc;
> > +  ret.original_code = MAXOF_EXPR;
> > +  ret.original_type = NULL;
> > +  ret.m_decimal = 0;
> > +  if (type == error_mark_node)
> > +    {
> > +      ret.value = error_mark_node;
> > +      ret.original_code = ERROR_MARK;
> > +    }
> > +  pop_maybe_used (type != error_mark_node);
> > +  return ret;
> > +}
> > +
> >  /* Build a function call to function FUNCTION with parameters PARAMS.
> >     The function call is at LOC.
> >     PARAMS is a list--a chain of TREE_LIST nodes--in which the
> > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> > index d58260e295a5..46ee480daf56 100644
> > --- a/gcc/doc/extend.texi
> > +++ b/gcc/doc/extend.texi
> > @@ -13271,6 +13271,7 @@ C and/or C++ standards, while others remain 
> > specific to GNU C.
> >  * Nested Functions::    Nested functions in GNU C.
> >  * Typeof::              @code{typeof}: referring to the type of an 
> > expression.
> >  * _Countof::            Determining the Number of Elements of Arrays
> > +* _Maxof and _Minof::   The maximum and minimum representable values of a 
> > type.
> >  * Offsetof::            Special syntax for @code{offsetof}.
> >  * Alignment::           Determining the alignment of a function, type or 
> > variable.
> >  * Enum Extensions::     Forward declarations and specifying the underlying 
> > type.
> > @@ -13937,6 +13938,24 @@ _Countof (int [7][n++]);  // integer constant 
> > expression
> >  _Countof (int [n++][7]);  // run-time value; n++ is evaluated
> >  @end smallexample
> >
> > +@node _Maxof and _Minof
> > +@subsection The maximum and minimum representable values of a type
> > +@findex _Maxof
> > +@findex _Minof
> > +
> > +The keywords @code{_Maxof} and @code{_Minof} determine
> > +the maximum and minimum representable values of an integer type.
> > +Its syntax is similar to @code{sizeof}.
> > +The operand must be
> > +a parenthesized integer type.
> > +The result of this operator is an integer constant expression.
> > +For example:
> > +
> > +@smallexample
> > +_Maxof (int);    // returns INT_MAX
> > +_Minof (short);  // returns SHRT_MIN
> > +@end smallexample
> > +
> >  @node Offsetof
> >  @subsection Support for @code{offsetof}
> >  @findex __builtin_offsetof
> > diff --git a/gcc/testsuite/gcc.dg/maxof-compat.c 
> > b/gcc/testsuite/gcc.dg/maxof-compat.c
> > new file mode 100644
> > index 000000000000..2c023a3eaf7a
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/maxof-compat.c
> > @@ -0,0 +1,5 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-std=c2y -pedantic-errors -Wc23-c2y-compat" } */
> > +
> > +int a[_Maxof(char)];  /* { dg-warning "ISO C does not support" } */
> > +int b[1 + _Minof(unsigned char)];  /* { dg-warning "ISO C does not 
> > support" } */
> > diff --git a/gcc/testsuite/gcc.dg/maxof-compile.c 
> > b/gcc/testsuite/gcc.dg/maxof-compile.c
> > new file mode 100644
> > index 000000000000..6988452edafa
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/maxof-compile.c
> > @@ -0,0 +1,110 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-std=c2y -pedantic-errors" } */
> > +
> > +#define SCHAR_MAX  __SCHAR_MAX__
> > +#define SCHAR_MIN  (-SCHAR_MAX - 1)
> > +#define UCHAR_MAX  (SCHAR_MAX * 2 + 1)
> > +
> > +#define SHRT_MAX   __SHRT_MAX__
> > +#define SHRT_MIN   (-SHRT_MAX - 1)
> > +#define USHRT_MAX  (SHRT_MAX * 2U + 1)
> > +
> > +#define INT_MAX    __INT_MAX__
> > +#define INT_MIN    (-INT_MAX - 1)
> > +#define UINT_MAX   (INT_MAX * 2U + 1)
> > +
> > +#define LONG_MAX   __LONG_MAX__
> > +#define LONG_MIN   (-LONG_MAX - 1L)
> > +#define ULONG_MAX  (LONG_MAX * 2LU + 1)
> > +
> > +void
> > +integer (void)
> > +{
> > +  _Static_assert(_Maxof (char) == SCHAR_MAX || _Maxof (char) == UCHAR_MAX);
> > +  _Static_assert(_Minof (char) == SCHAR_MIN || _Minof (char) == 0);
> > +
> > +  _Static_assert(_Maxof (signed char) == SCHAR_MAX);
> > +  _Static_assert(_Maxof (short) == SHRT_MAX);
> > +  _Static_assert(_Maxof (int) == INT_MAX);
> > +  _Static_assert(_Maxof (long) == LONG_MAX);
> > +  _Static_assert(_Maxof (long long) >= LONG_MAX);
> > +
> > +  _Static_assert(_Minof (signed char) == SCHAR_MIN);
> > +  _Static_assert(_Minof (short) == SHRT_MIN);
> > +  _Static_assert(_Minof (int) == INT_MIN);
> > +  _Static_assert(_Minof (long) == LONG_MIN);
> > +  _Static_assert(_Minof (long long) <= LONG_MIN);
> > +
> > +  _Static_assert(_Maxof (unsigned char) == UCHAR_MAX);
> > +  _Static_assert(_Maxof (unsigned short) == USHRT_MAX);
> > +  _Static_assert(_Maxof (unsigned int) == UINT_MAX);
> > +  _Static_assert(_Maxof (unsigned long) == ULONG_MAX);
> > +  _Static_assert(_Maxof (unsigned long long) >= ULONG_MAX);
> > +
> > +  _Static_assert(_Minof (unsigned char) == 0);
> > +  _Static_assert(_Minof (unsigned short) == 0);
> > +  _Static_assert(_Minof (unsigned int) == 0);
> > +  _Static_assert(_Minof (unsigned long) == 0);
> > +  _Static_assert(_Minof (unsigned long long) == 0);
> > +}
> > +
> > +void
> > +bitint (void)
> > +{
> > +  _Static_assert(_Maxof (_BitInt(5)) == 15);
> > +  _Static_assert(_Minof (_BitInt(5)) == -16);
> > +  _Static_assert(_Maxof (unsigned _BitInt(5)) == 31);
> > +  _Static_assert(_Minof (unsigned _BitInt(5)) == 0);
> > +}
> > +
> > +void
> > +enums (void)
> > +{
> > +  enum e1 { E1 };
> > +  enum e2 : short { E2 };
> > +
> > +  _Maxof (enum e1);
> > +  _Minof (enum e1);
> > +  _Static_assert(_Maxof (enum e2) == SHRT_MAX);
> > +  _Static_assert(_Minof (enum e2) == SHRT_MIN);
> > +}
> > +
> > +void
> > +expr (void)
> > +{
> > +  int x;
> > +
> > +  _Maxof (x);  /* { dg-error "to something not a type" } */
> > +  _Minof (x);  /* { dg-error "to something not a type" } */
> > +  _Maxof (1);  /* { dg-error "to something not a type" } */
> > +  _Minof (1);  /* { dg-error "to something not a type" } */
> > +  _Maxof 1;  /* { dg-error "expected" } */
> > +  _Minof 1;  /* { dg-error "expected" } */
> > +  _Maxof (int) {1};  /* { dg-error "to a compound literal" } */
> > +  _Minof (int) {1};  /* { dg-error "to a compound literal" } */
> > +}
> > +
> > +void
> > +non_int (void)
> > +{
> > +  struct s {int x;};
> > +  union u {int x;};
> > +
> > +  _Maxof (struct s);  /* { dg-error "to type" } */
> > +  _Minof (struct s);  /* { dg-error "to type" } */
> > +  _Maxof (union u);  /* { dg-error "to type" } */
> > +  _Minof (union u);  /* { dg-error "to type" } */
> > +  _Maxof (bool);  /* { dg-error "to type" } */
> > +  _Minof (bool);  /* { dg-error "to type" } */
> > +  _Maxof (int [1]);  /* { dg-error "to type" } */
> > +  _Minof (int [1]);  /* { dg-error "to type" } */
> > +}
> > +
> > +void
> > +specs (void)
> > +{
> > +  _Maxof (static int);  /* { dg-error "storage class specifier in" } */
> > +  _Minof (static int);  /* { dg-error "storage class specifier in" } */
> > +  _Maxof (alignas(8) int);  /* { dg-error "alignment specified" } */
> > +  _Minof (alignas(8) int);  /* { dg-error "alignment specified" } */
> > +}
> > diff --git a/gcc/testsuite/gcc.dg/maxof-no-compat.c 
> > b/gcc/testsuite/gcc.dg/maxof-no-compat.c
> > new file mode 100644
> > index 000000000000..e0d3fb94d85b
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/maxof-no-compat.c
> > @@ -0,0 +1,5 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-std=c23 -pedantic-errors -Wno-c23-c2y-compat" } */
> > +
> > +int a[_Maxof(char)];
> > +int b[1 + _Minof(unsigned char)];
> > diff --git a/gcc/testsuite/gcc.dg/maxof-pedantic-errors.c 
> > b/gcc/testsuite/gcc.dg/maxof-pedantic-errors.c
> > new file mode 100644
> > index 000000000000..dcb64bb06bb5
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/maxof-pedantic-errors.c
> > @@ -0,0 +1,5 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-std=c23 -pedantic-errors" } */
> > +
> > +int a[_Maxof(char)];  /* { dg-error "ISO C does not support" } */
> > +int b[1 + _Minof(unsigned char)];  /* { dg-error "ISO C does not support" 
> > } */
> > diff --git a/gcc/testsuite/gcc.dg/maxof-pedantic.c 
> > b/gcc/testsuite/gcc.dg/maxof-pedantic.c
> > new file mode 100644
> > index 000000000000..fa2582c2baa5
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/maxof-pedantic.c
> > @@ -0,0 +1,5 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-std=c23 -pedantic" } */
> > +
> > +int a[_Maxof(char)];  /* { dg-warning "ISO C does not support" } */
> > +int b[1 + _Minof(unsigned char)];  /* { dg-warning "ISO C does not 
> > support" } */
> > --
> > 2.51.0
> >

-- 
<https://www.alejandro-colomar.es>
Use port 80 (that is, <...:80/>).

Attachment: signature.asc
Description: PGP signature

Reply via email to