Hi,
Here's a second attempt at implementing these two operators.
They're implemented as proposed in n3628, but differ slightly in that
they reject _Bool (the first commit message details a bit more about
this).
I tested the feature while developing it, and those tests all passed.
However, when I've tried to do it formally, I'm now getting some issues
that don't make any sense. I think something in the build system is not
working properly, or I have broken something in a way that I don't
understand. I'll paste here what I see:
alx@devuan:~/src/gnu/gcc/maxof$ git log --oneline gnu/master^..maxof2
4b6f1d46fb2d (HEAD -> maxof, tag: maxof2) c: Reduce excess errors of
_Maxof and _Minof
29ee24eabe18 c: Add _Maxof and _Minof operators
1161fc635450 (gnu/trunk, gnu/master, gnu/HEAD) Handle shift-pairs in
ext-dce for targets without zero/sign extension insns
alx@devuan:~/src/gnu/gcc/maxof$ git reset gnu/master --h
HEAD is now at 1161fc635450 Handle shift-pairs in ext-dce for targets
without zero/sign extension insns
alx@devuan:~/src/gnu/gcc/maxof$ mkdir ../maxof2
alx@devuan:~/src/gnu/gcc/maxof$ cd ../maxof2/
alx@devuan:~/src/gnu/gcc/maxof2$ set -o pipefail
alx@devuan:~/src/gnu/gcc/maxof2$ ../maxof/configure --disable-multilib
--prefix=/opt/local/gnu/gcc/maxof2 |& ts -s | tail -n1; echo $?;
00:00:02 config.status: creating Makefile
0
alx@devuan:~/src/gnu/gcc/maxof2$ make -j24 bootstrap |& ts -s | tail
-n1; echo $?;
00:22:11 make[1]: Leaving directory '/srv/alx/src/gnu/gcc/maxof2'
0
alx@devuan:~/src/gnu/gcc/maxof2$ make -j24 check |& ts -s | tail -n1;
echo $?;
00:34:55 make[1]: Leaving directory '/srv/alx/src/gnu/gcc/maxof2'
0
alx@devuan:~/src/gnu/gcc/maxof2$ cd ../maxof
alx@devuan:~/src/gnu/gcc/maxof$ git merge --ff-only maxof2
Updating 1161fc635450..4b6f1d46fb2d
Fast-forward
gcc/c-family/c-common.cc | 32 ++++
gcc/c-family/c-common.def | 6 +
gcc/c-family/c-common.h | 4 +-
gcc/c/c-parser.cc | 66 +++++++-
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 | 159 +++++++++++++++++++
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, 360 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
alx@devuan:~/src/gnu/gcc/maxof$ cd ../
alx@devuan:~/src/gnu/gcc$ mv maxof2
maxof2/
alx@devuan:~/src/gnu/gcc$ mv maxof2/ maxof2_b4
alx@devuan:~/src/gnu/gcc$ mkdir maxof2
alx@devuan:~/src/gnu/gcc$ cd maxof2
alx@devuan:~/src/gnu/gcc/maxof2$ ../maxof/configure --disable-multilib
--prefix=/opt/local/gnu/gcc/maxof2 |& ts -s | tail -n1; echo $?;
00:00:01 config.status: creating Makefile
0
alx@devuan:~/src/gnu/gcc/maxof2$ make -j24 bootstrap |& ts -s | tail
-n1; echo $?;
00:22:20 make[1]: Leaving directory '/srv/alx/src/gnu/gcc/maxof2'
0
alx@devuan:~/src/gnu/gcc/maxof2$ make -j24 check |& ts -s | tail -n1;
echo $?;
00:34:40 make[1]: Leaving directory '/srv/alx/src/gnu/gcc/maxof2'
0
alx@devuan:~/src/gnu/gcc/maxof2$ find -type f | grep '\.sum$' | while
read f; do diff -u "../maxof2_b4/$f" "$f"; done
--- ../maxof2_b4/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum
2025-11-14 02:04:25.583049614 +0100
+++ ./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum 2025-11-14
15:44:37.179161371 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Fri Nov 14 02:04:23 2025
+Test run by alx on Fri Nov 14 15:44:34 2025
Native configuration is x86_64-pc-linux-gnu
=== libitm tests ===
---
../maxof2_b4/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum2025-11-14
02:04:24.552495874 +0100
+++ ./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum
2025-11-14 15:44:36.094622398 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Fri Nov 14 02:04:23 2025
+Test run by alx on Fri Nov 14 15:44:34 2025
Native configuration is x86_64-pc-linux-gnu
=== libatomic tests ===
--- ../maxof2_b4/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum
2025-11-14 02:06:46.440704161 +0100
+++ ./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum 2025-11-14
15:46:46.943307275 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Fri Nov 14 02:04:23 2025
+Test run by alx on Fri Nov 14 15:44:34 2025
Native configuration is x86_64-pc-linux-gnu
=== libgomp tests ===
---
../maxof2_b4/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum
2025-11-14 02:39:17.560769098 +0100
+++ ./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum
2025-11-14 16:19:13.738775165 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Fri Nov 14 02:04:24 2025
+Test run by alx on Fri Nov 14 15:44:35 2025
Native configuration is x86_64-pc-linux-gnu
=== libstdc++ tests ===
--- ../maxof2_b4/./gcc/testsuite/objc/objc.sum 2025-11-14
02:05:29.243579430 +0100
+++ ./gcc/testsuite/objc/objc.sum 2025-11-14 15:45:23.840405398
+0100
@@ -1,4 +1,4 @@
-Test run by alx on Fri Nov 14 02:04:23 2025
+Test run by alx on Fri Nov 14 15:44:35 2025
Native configuration is x86_64-pc-linux-gnu
=== objc tests ===
--- ../maxof2_b4/./gcc/testsuite/g++/g++.sum 2025-11-14
02:16:21.259781844 +0100
+++ ./gcc/testsuite/g++/g++.sum 2025-11-14 15:58:33.707331276 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Fri Nov 14 02:04:23 2025
+Test run by alx on Fri Nov 14 15:44:35 2025
Native configuration is x86_64-pc-linux-gnu
=== g++ tests ===
--- ../maxof2_b4/./gcc/testsuite/gcc/gcc.sum 2025-11-14
02:22:42.112260276 +0100
+++ ./gcc/testsuite/gcc/gcc.sum 2025-11-14 16:02:01.933356817 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Fri Nov 14 02:04:23 2025
+Test run by alx on Fri Nov 14 15:44:35 2025
Native configuration is x86_64-pc-linux-gnu
=== gcc tests ===
@@ -71738,6 +71738,7 @@
PASS: c-c++-common/zero-scratch-regs-leafy-1.c -Wc++-compat (test
for excess errors)
PASS: c-c++-common/zero-scratch-regs-leafy-1.c -Wc++-compat
execution test
PASS: c-c++-common/zero-scratch-regs-leafy-2.c -Wc++-compat (test
for excess errors)
+ERROR: couldn't compile regular expression pattern: parentheses () not
balanced
UNSUPPORTED: fatal-error-html.py pytest python3 is missing
UNSUPPORTED: fatal-error-sarif.py pytest python3 is missing
PASS: gcc.dg/20000108-1.c (test for excess errors)
@@ -94161,18 +94162,10 @@
[...]
@@ -221107,11 +206857,11 @@
=== gcc Summary ===
-# of expected passes 215035
+# of expected passes 201711
# of unexpected failures 529
-# of unexpected successes 6
-# of expected failures 1485
-# of unresolved testcases 1
-# of unsupported tests 3859
+# of unexpected successes 7
+# of expected failures 1448
+# of unresolved testcases 2
+# of unsupported tests 2965
/srv/alx/src/gnu/gcc/maxof2/gcc/xgcc version 16.0.0 20251113
(experimental) (GCC)
--- ../maxof2_b4/./gcc/testsuite/gfortran/gfortran.sum 2025-11-14
02:15:47.295817457 +0100
+++ ./gcc/testsuite/gfortran/gfortran.sum 2025-11-14
15:57:02.256911162 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Fri Nov 14 02:04:23 2025
+Test run by alx on Fri Nov 14 15:44:35 2025
Native configuration is x86_64-pc-linux-gnu
=== gfortran tests ===
alx@devuan:~/src/gnu/gcc/maxof2$ find -type f | grep '\.sum$' | while
read f; do diff -u "../maxof2_b4/$f" "$f"; done | grep 'gcc.dg/maxof'
+PASS: gcc.dg/maxof-compat.c (test for warnings, line 4)
+PASS: gcc.dg/maxof-compat.c (test for warnings, line 5)
+PASS: gcc.dg/maxof-compat.c (test for excess errors)
+PASS: gcc.dg/maxof-compile.c (test for errors, line 77)
It doesn't make any sense, as there should be many more test results
matching 'gcc.dg/maxof' (and I've seen them in previous testing).
BTW, I suppose you'll prefer the two commits squashed. I kept them
separate just to show the difference in errors during review, but I can
squash them if you want me to.
Have a lovely night!
Alex
Alejandro Colomar (2):
c: Add _Maxof and _Minof operators
c: Reduce excess errors of _Maxof and _Minof
gcc/c-family/c-common.cc | 32 ++++
gcc/c-family/c-common.def | 6 +
gcc/c-family/c-common.h | 4 +-
gcc/c/c-parser.cc | 66 +++++++-
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 | 159 +++++++++++++++++++
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, 360 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
Range-diff against v1:
2: 11d4b9b554d5 ! 1: 29ee24eabe18 c: Add _Maxof and _Minof operators
@@ Commit message
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3628.txt>
+ This implementation differs from n3628 in that _Bool is not accepted by
+ these operators in this implementation. It was an oversight to allow
+ _Bool in n3628, and I will publish a revision of that paper with that
+ amended, prior to the next meeting of the C Committee.
+
+ These operators generalize the existing XXX_MAX and XXX_MIN macros.
+ Those macros don't exist for _Bool, as it wouldn't be useful.
+ Similarly, these new operators wouldn't be useful for use with _Bool,
+ even if mathematically it could make sense to accept them as input.
+
+ To be cautious, let's constrain that, with the option to revisit that
in
+ the future, if a reason for accepting _Bool were discovered.
+
gcc/ChangeLog:
* doc/extend.texi (Syntax Extensions): Document _Maxof &
_Minof.
@@ Commit message
* 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-common.h (enum rid): Add RID_MAXOF & RID_MINOF constants.
(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-parser.cc (c_parser_maxof_or_minof_expression): New func.
+ (c_parser_unary_expression): Add RID_MAXOF & RID_MINOF cases.
* 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.
+ * c-typeck.cc (c_expr_maxof_type): New function.
+ (c_expr_minof_type): New function.
+
+ gcc/testsuite/ChangeLog:
+
+ * gcc.dg/maxof-compat.c: New test.
+ * gcc.dg/maxof-compile.c: New test.
+ * gcc.dg/maxof-no-compat.c: New test.
+ * gcc.dg/maxof-pedantic-errors.c: New test.
+ * gcc.dg/maxof-pedantic.c: New test.
Signed-off-by: Alejandro Colomar <[email protected]>
@@ gcc/c-family/c-common.cc: const struct c_common_resword
c_common_reswords[] =
{ "_BitInt", RID_BITINT, D_CONLY },
{ "_Bool", RID_BOOL, D_CONLY },
@@ gcc/c-family/c-common.cc: c_countof_type (location_t loc, tree type)
- return array_type_nelts_top (type);
+ return value;
}
+/* Implement the _Maxof operator:
@@ gcc/c-family/c-common.cc: c_countof_type (location_t loc, tree 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)
++ 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;
@@ gcc/c-family/c-common.cc: c_countof_type (location_t loc, tree 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)
++ if (!INTEGRAL_TYPE_P (type) || TREE_CODE (type) == BOOLEAN_TYPE)
+ {
+ error_at (loc, "invalid application of %<_Minof%> to type %qT",
type);
+ return error_mark_node;
@@ gcc/c-family/c-common.h: extern void c_apply_type_quals_to_decl (int,
tree);
extern void binary_op_error (rich_location *, enum tree_code, tree, tree);
## gcc/c/c-parser.cc ##
-@@ gcc/c/c-parser.cc: static inline struct c_expr
c_parser_countof_expression (c_parser *);
+@@ gcc/c/c-parser.cc: static struct c_expr c_parser_unary_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 *,
@@ gcc/c/c-parser.cc: c_parser_cast_expression (c_parser *parser, struct
c_expr *af
_Countof ( type-name )
sizeof unary-expression
sizeof ( type-name )
-+ _Maxof unary-expression
+ _Maxof ( type-name )
-+ _Minof unary-expression
+ _Minof ( type-name )
+ static-assert-declaration-no-semi
-- (_Countof is new in C2y.)
-+ (_Countof, _Maxof, and _Minof are new in C2y.)
+- (_Countof and the use of static assertions in expressions are new in
C2y.)
++ (_Countof, _Maxof, _Minof, and the use of static assertions in
++ expressions are new in C2y.)
unary-operator: one of
& * + - ~ !
@@ gcc/c/c-parser.cc: 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);
- case RID_BUILTIN_HAS_ATTRIBUTE:
- return c_parser_has_attribute_expression (parser);
- case RID_EXTENSION:
+ return c_parser_sizeof_or_countof_expression (parser, rid);
+ case RID_ALIGNOF:
+ return c_parser_alignof_expression (parser);
++ case RID_MAXOF:
++ case RID_MINOF:
++ return c_parser_maxof_or_minof_expression (parser, rid);
+ case RID_BUILTIN_HAS_ATTRIBUTE:
+ return c_parser_has_attribute_expression (parser);
+ case RID_EXTENSION:
@@ gcc/c/c-parser.cc: 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;
++ struct c_type_name *type_name;
++ matching_parens parens;
+ gcc_assert (c_parser_next_token_is_keyword (parser, rid));
+
+ location_t start;
@@ gcc/c/c-parser.cc: c_parser_alignof_expression (c_parser *parser)
+
+ 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)))
++ if (!c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
-+ /* 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);
++ c_parser_error (parser, "expected %<(%>");
++ goto fail;
+ }
++ parens.consume_open (parser);
++ expr_loc = c_parser_peek_token (parser)->location;
++ if (!c_token_starts_typename (c_parser_peek_token (parser)))
++ {
++ error_at (expr_loc, "invalid application of %qs to something not a
type", op_name);
++ goto fail;
++ }
++ type_name = c_parser_type_name (parser, true);
++ // Can return NULL? Why?
++ parens.skip_until_found_close (parser);
++ finish = parser->tokens_buf[0].location;
++ 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
-+ {
-+ 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;
-+ }
++ result = c_expr_minof_type (expr_loc, type_name);
++ set_c_expr_source_range (&result, start, finish);
++ return result;
++fail:
++ c_inhibit_evaluation_warnings--;
++ result.set_error ();
++ result.original_code = ERROR_MARK;
++ result.original_type = NULL;
+ return result;
+}
+
@@ gcc/doc/extend.texi
@@ gcc/doc/extend.texi: 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
+ * _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.
@@ gcc/testsuite/gcc.dg/maxof-compile.c (new)
+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 (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 (_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 (_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 (_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);
++ _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);
++ _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
@@ gcc/testsuite/gcc.dg/maxof-compile.c (new)
+
+ _Maxof (enum e1);
+ _Minof (enum e1);
-+ _Static_assert(_Maxof (enum e2) == SHRT_MAX);
-+ _Static_assert(_Minof (enum e2) == SHRT_MIN);
++ _Static_assert (_Maxof (enum e2) == SHRT_MAX);
++ _Static_assert (_Minof (enum e2) == SHRT_MIN);
+}
+
+void
@@ gcc/testsuite/gcc.dg/maxof-compile.c (new)
+ int x;
+
+ _Maxof (x); /* { dg-error "to something not a type" } */
++ /* { dg-error "expected ';'" "syntax error" { target *-*-* } .-1 } */
++ /* { dg-error "expected statement" "syntax error 2" { target *-*-* }
.-2 } */
+ _Minof (x); /* { dg-error "to something not a type" } */
++ /* { dg-error "expected ';'" "syntax error" { target *-*-* } .-1 } */
++ /* { dg-error "expected statement" "syntax error 2" { target *-*-* }
.-2 } */
+ _Maxof (1); /* { dg-error "to something not a type" } */
++ /* { dg-error "expected ';'" "syntax error" { target *-*-* } .-1 } */
++ /* { dg-error "expected statement" "syntax error 2" { target *-*-* }
.-2 } */
+ _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" } */
++ /* { dg-error "expected ';'" "syntax error" { target *-*-* } .-1 } */
++ /* { dg-error "expected statement" "syntax error 2" { target *-*-* }
.-2 } */
++ _Maxof 1; /* { dg-error "expected '('" } */
++ _Minof 1; /* { dg-error "expected '('" } */
++ _Maxof (int) {1}; /* { dg-error "expected ';'" } */
++ _Minof (int) {1}; /* { dg-error "expected ';'" } */
+}
+
+void
@@ gcc/testsuite/gcc.dg/maxof-compile.c (new)
+void
+specs (void)
+{
-+ _Maxof (static int); /* { dg-error "storage class specifier in" } */
-+ _Minof (static int); /* { dg-error "storage class specifier in" } */
++ _Maxof (static int); /* { dg-error "to something not a type" } */
++ /* { dg-error "expected ';'" "syntax error" { target *-*-* } .-1 } */
++ /* { dg-error "expected statement" "syntax error 2" { target *-*-* }
.-2 } */
++ _Minof (static int); /* { dg-error "to something not a type" } */
++ /* { dg-error "expected ';'" "syntax error" { target *-*-* } .-1 } */
++ /* { dg-error "expected statement" "syntax error 2" { target *-*-* }
.-2 } */
+ _Maxof (alignas(8) int); /* { dg-error "alignment specified" } */
+ _Minof (alignas(8) int); /* { dg-error "alignment specified" } */
++}
++
++void
++bogus (void)
++{
++ _Maxof (int x); /* { dg-error "expected ')'" } */
++ _Minof (int x); /* { dg-error "expected ')'" } */
++}
++
++void
++type (void)
++{
++ _Generic (_Maxof (char), char: 0);
++ _Generic (_Minof (char), char: 0);
++
++ _Generic (_Maxof (signed char), signed char: 0);
++ _Generic (_Maxof (short), short: 0);
++ _Generic (_Maxof (int), int: 0);
++ _Generic (_Maxof (long), long: 0);
++ _Generic (_Maxof (long long), long long: 0);
++
++ _Generic (_Minof (signed char), signed char: 0);
++ _Generic (_Minof (short), short: 0);
++ _Generic (_Minof (int), int: 0);
++ _Generic (_Minof (long), long: 0);
++ _Generic (_Minof (long long), long long: 0);
++
++ _Generic (_Maxof (unsigned char), unsigned char: 0);
++ _Generic (_Maxof (unsigned short), unsigned short: 0);
++ _Generic (_Maxof (unsigned int), unsigned int: 0);
++ _Generic (_Maxof (unsigned long), unsigned long: 0);
++ _Generic (_Maxof (unsigned long long), unsigned long long: 0);
++
++ _Generic (_Minof (unsigned char), unsigned char: 0);
++ _Generic (_Minof (unsigned short), unsigned short: 0);
++ _Generic (_Minof (unsigned int), unsigned int: 0);
++ _Generic (_Minof (unsigned long), unsigned long: 0);
++ _Generic (_Minof (unsigned long long), unsigned long long: 0);
++
++ _Generic (_Maxof (_BitInt (5)), _BitInt (5): 0);
++ _Generic (_Minof (_BitInt (5)), _BitInt (5): 0);
++ _Generic (_Maxof (unsigned _BitInt (5)), unsigned _BitInt (5): 0);
++ _Generic (_Minof (unsigned _BitInt (5)), unsigned _BitInt (5): 0);
+}
## gcc/testsuite/gcc.dg/maxof-no-compat.c (new) ##
1: a54651f69765 ! 2: 4b6f1d46fb2d doc: Move _Countof under 'Other Extensions
to C Syntax'
@@ Metadata
Author: Alejandro Colomar <[email protected]>
## Commit message ##
- doc: Move _Countof under 'Other Extensions to C Syntax'
+ c: Reduce excess errors of _Maxof and _Minof
- gcc/ChangeLog:
+ gcc/c/ChangeLog:
- * doc/extend.texi: Move _Countof under 'Syntax Extensions'.
+ * c-parser.cc (c_parser_maxof_or_minof_expression): After '('
+ has been parsed, if there's a syntax error, skip until ')', to
+ minimize excess errors.
+
+ gcc/testsuite/ChangeLog:
+
+ * gcc.dg/maxof-compile.c (expr, specs): Update test.
Signed-off-by: Alejandro Colomar <[email protected]>
- ## gcc/doc/extend.texi ##
-@@ gcc/doc/extend.texi: extensions, accepted by GCC in C90 mode and in C++.
- * Thread-Local:: Per-thread variables.
- * OpenMP:: Multiprocessing extensions.
- * OpenACC:: Extensions for offloading code to accelerator
devices.
--* _Countof:: The number of elements of arrays.
- * Inline:: Defining inline functions (as fast as macros).
- * Volatiles:: What constitutes an access to a volatile object.
- * Using Assembly Language with C:: Instructions and extensions for
interfacing C with assembler.
-@@ gcc/doc/extend.texi: library.
- @xref{OpenMP and OpenACC Options}, for additional options useful with
- @option{-fopenacc}.
+ ## gcc/c/c-parser.cc ##
+@@ gcc/c/c-parser.cc: c_parser_maxof_or_minof_expression (c_parser
*parser, enum rid rid)
+ if (!c_token_starts_typename (c_parser_peek_token (parser)))
+ {
+ error_at (expr_loc, "invalid application of %qs to something not a
type", op_name);
++ parens.skip_until_found_close (parser);
+ goto fail;
+ }
+ type_name = c_parser_type_name (parser, true);
+
+ ## gcc/testsuite/gcc.dg/maxof-compile.c ##
+@@ gcc/testsuite/gcc.dg/maxof-compile.c: expr (void)
+ int x;
--@node _Countof
--@section Determining the Number of Elements of Arrays
--@cindex _Countof
--@cindex number of elements
--
--The keyword @code{_Countof} determines
--the number of elements of an array operand.
--Its syntax is similar to @code{sizeof}.
--The operand must be
--a parenthesized complete array type name
--or an expression of such a type.
--For example:
--
--@smallexample
--int a[n];
--_Countof (a); // returns n
--_Countof (int [7][3]); // returns 7
--@end smallexample
--
--The result of this operator is an integer constant expression,
--unless the array has a variable number of elements.
--The operand is only evaluated
--if the array has a variable number of elements.
--For example:
--
--@smallexample
--_Countof (int [7][n++]); // integer constant expression
--_Countof (int [n++][7]); // run-time value; n++ is evaluated
--@end smallexample
--
- @node Inline
- @section An Inline Function is As Fast As a Macro
- @cindex inline functions
-@@ gcc/doc/extend.texi: C and/or C++ standards, while others remain
specific to GNU C.
- * Labels as Values:: Getting pointers to labels, and computed gotos.
- * 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
- * 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.
-@@ gcc/doc/extend.texi: evaluated only once when using @code{__auto_type},
but twice if
- @code{typeof} is used.
- @end itemize
-
-+@node _Countof
-+@subsection Determining the Number of Elements of Arrays
-+@findex _Countof
-+@findex number of elements
-+
-+The keyword @code{_Countof} determines
-+the number of elements of an array operand.
-+Its syntax is similar to @code{sizeof}.
-+The operand must be
-+a parenthesized complete array type name
-+or an expression of such a type.
-+For example:
-+
-+@smallexample
-+int a[n];
-+_Countof (a); // returns n
-+_Countof (int [7][3]); // returns 7
-+@end smallexample
-+
-+The result of this operator is an integer constant expression,
-+unless the array has a variable number of elements.
-+The operand is only evaluated
-+if the array has a variable number of elements.
-+For example:
-+
-+@smallexample
-+_Countof (int [7][n++]); // integer constant expression
-+_Countof (int [n++][7]); // run-time value; n++ is evaluated
-+@end smallexample
-+
- @node Offsetof
- @subsection Support for @code{offsetof}
- @findex __builtin_offsetof
+ _Maxof (x); /* { dg-error "to something not a type" } */
+- /* { dg-error "expected ';'" "syntax error" { target *-*-* } .-1 } */
+- /* { dg-error "expected statement" "syntax error 2" { target *-*-* }
.-2 } */
++ /* { dg-error "expected ')'" "syntax error" { target *-*-* } .-1 } */
+ _Minof (x); /* { dg-error "to something not a type" } */
+- /* { dg-error "expected ';'" "syntax error" { target *-*-* } .-1 } */
+- /* { dg-error "expected statement" "syntax error 2" { target *-*-* }
.-2 } */
++ /* { dg-error "expected ')'" "syntax error" { target *-*-* } .-1 } */
+ _Maxof (1); /* { dg-error "to something not a type" } */
+- /* { dg-error "expected ';'" "syntax error" { target *-*-* } .-1 } */
+- /* { dg-error "expected statement" "syntax error 2" { target *-*-* }
.-2 } */
++ /* { dg-error "expected ')'" "syntax error" { target *-*-* } .-1 } */
+ _Minof (1); /* { dg-error "to something not a type" } */
+- /* { dg-error "expected ';'" "syntax error" { target *-*-* } .-1 } */
+- /* { dg-error "expected statement" "syntax error 2" { target *-*-* }
.-2 } */
++ /* { dg-error "expected ')'" "syntax error" { target *-*-* } .-1 } */
+ _Maxof 1; /* { dg-error "expected '('" } */
+ _Minof 1; /* { dg-error "expected '('" } */
+ _Maxof (int) {1}; /* { dg-error "expected ';'" } */
+@@ gcc/testsuite/gcc.dg/maxof-compile.c: void
+ specs (void)
+ {
+ _Maxof (static int); /* { dg-error "to something not a type" } */
+- /* { dg-error "expected ';'" "syntax error" { target *-*-* } .-1 } */
+- /* { dg-error "expected statement" "syntax error 2" { target *-*-* }
.-2 } */
++ /* { dg-error "expected ')'" "syntax error" { target *-*-* } .-1 } */
+ _Minof (static int); /* { dg-error "to something not a type" } */
+- /* { dg-error "expected ';'" "syntax error" { target *-*-* } .-1 } */
+- /* { dg-error "expected statement" "syntax error 2" { target *-*-* }
.-2 } */
++ /* { dg-error "expected ')'" "syntax error" { target *-*-* } .-1 } */
+ _Maxof (alignas(8) int); /* { dg-error "alignment specified" } */
+ _Minof (alignas(8) int); /* { dg-error "alignment specified" } */
+ }
--
2.51.0