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>
>
> gcc/ChangeLog:
>
> * doc/extend.texi (Syntax Extensions): Document _Maxof & _Minof.
>
> gcc/c-family/ChangeLog:
>
> * c-common.cc (c_common_reswords): Add _Maxof & _Minof keywords.
> (c_maxof_type, c_minof_type): New functions.
> * c-common.def (MAXOF_EXPR, MINOF_EXPR): New trees.
> * c-common.h (enum rid): Add RID_MAXOF & RID_MINOF.
> (c_maxof_type, c_minof_type): New prototypes.
>
> gcc/c/ChangeLog:
>
> * c-parser.cc (c_parser_maxof_expression): New function.
> (c_parser_minof_expression): New function.
> (c_parser_maxof_or_minof_expression): New function.
> (c_parser_unary_expression): Add RID_MAXOF & RID_MINOF entries.
> * c-tree.h (c_expr_maxof_type): New prototype.
> (c_expr_minof_type): New prototype.
> * c-typeck.cc (in_maxof, in_minof): New global variables.
>
> Signed-off-by: Alejandro Colomar <[email protected]>
> ---
> gcc/c-family/c-common.cc | 42 +++++++
> gcc/c-family/c-common.def | 6 +
> gcc/c-family/c-common.h | 4 +-
> gcc/c/c-parser.cc | 113 ++++++++++++++++++-
> gcc/c/c-tree.h | 2 +
> gcc/c/c-typeck.cc | 54 +++++++++
> gcc/doc/extend.texi | 19 ++++
> gcc/testsuite/gcc.dg/maxof-compat.c | 5 +
> gcc/testsuite/gcc.dg/maxof-compile.c | 110 ++++++++++++++++++
> gcc/testsuite/gcc.dg/maxof-no-compat.c | 5 +
> gcc/testsuite/gcc.dg/maxof-pedantic-errors.c | 5 +
> gcc/testsuite/gcc.dg/maxof-pedantic.c | 5 +
> 12 files changed, 368 insertions(+), 2 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/maxof-compat.c
> create mode 100644 gcc/testsuite/gcc.dg/maxof-compile.c
> create mode 100644 gcc/testsuite/gcc.dg/maxof-no-compat.c
> create mode 100644 gcc/testsuite/gcc.dg/maxof-pedantic-errors.c
> create mode 100644 gcc/testsuite/gcc.dg/maxof-pedantic.c
>
> 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
> @@ -397,6 +397,8 @@ const struct c_common_resword c_common_reswords[] =
> { "_Alignas", RID_ALIGNAS, D_CONLY },
> { "_Alignof", RID_ALIGNOF, D_CONLY },
> { "_Countof", RID_COUNTOF, D_CONLY },
> + { "_Maxof", RID_MAXOF, D_CONLY },
> + { "_Minof", RID_MINOF, D_CONLY },
> { "_Atomic", RID_ATOMIC, D_CONLY },
> { "_BitInt", RID_BITINT, D_CONLY },
> { "_Bool", RID_BOOL, D_CONLY },
> @@ -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.
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)
> + {
> + error_at (loc, "invalid application of %<_Maxof%> to type %qT", type);
> + return error_mark_node;
> + }
> +
> + return TYPE_MAX_VALUE (type);
> +}
> +
> +/* Implement the _Minof operator:
> + Return the minimum representable value of an integer type. */
> +
> +tree
> +c_minof_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)
See above.
> + {
> + 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.
Thanks,
Andrew Pinski
> 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);
> + 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
>