aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2025-08-15 22:34:59 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2025-08-15 22:34:59 +0200
commit4bed19cf6170541ff757ee1b21d9fec9eb0c6541 (patch)
treef3170b998dc66f2f436f619b5b92229db996cae8
parentcdd015c4ddbb1ae71eea1e44654cee5ca29a6c64 (diff)
downloadgcc-4bed19cf6170541ff757ee1b21d9fec9eb0c6541.zip
gcc-4bed19cf6170541ff757ee1b21d9fec9eb0c6541.tar.gz
gcc-4bed19cf6170541ff757ee1b21d9fec9eb0c6541.tar.bz2
c++: Fix default argument parsing in non-comma variadic methods [PR121539]
While the non-comma variadic functions/methods were deprecated in C++26, they are still valid and they are valid without deprecation in C++98 to C++23. We parse default arguments followed by ...) outside of classes or for out of class definitions of methods, but I think since C++11 support in GCC 4.9 or so we consider ... to be a part of a default argument and error on it. I think a default argument can't validly contain a pack expansion that ends the expression with ..., so I think we can simply handle ...) if at depth 0 as not part of the default argument. 2025-08-15 Jakub Jelinek <jakub@redhat.com> PR c++/121539 * parser.cc (cp_parser_cache_defarg): Set done to true for CPP_ELLIPSIS followed by CPP_CLOSE_PAREN in !nsdmi at depth 0. * g++.dg/parse/defarg20.C: New test.
-rw-r--r--gcc/cp/parser.cc6
-rw-r--r--gcc/testsuite/g++.dg/parse/defarg20.C79
2 files changed, 84 insertions, 1 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index d733b72..d66b658 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -37174,7 +37174,11 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi)
case CPP_CLOSE_SQUARE:
if (depth == 0
/* Handle correctly int n = sizeof ... ( p ); */
- && token->type != CPP_ELLIPSIS)
+ && (token->type != CPP_ELLIPSIS
+ /* For int n = 42 ...) handle ... as variadic arguments. */
+ || (!nsdmi
+ && cp_lexer_nth_token_is (parser->lexer, 2,
+ CPP_CLOSE_PAREN))))
done = true;
/* Update DEPTH, if necessary. */
else if (token->type == CPP_CLOSE_PAREN
diff --git a/gcc/testsuite/g++.dg/parse/defarg20.C b/gcc/testsuite/g++.dg/parse/defarg20.C
new file mode 100644
index 0000000..577c093
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/defarg20.C
@@ -0,0 +1,79 @@
+// PR c++/121539
+// { dg-do run }
+
+#include <cstdarg>
+
+#if __cplusplus >= 201103L
+#define I {}
+#else
+#define I 0
+#endif
+
+void foo (int = I...); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
+struct S {
+ void foo (int = I...); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
+ void bar (int...); // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
+};
+
+void
+foo (int a, ...)
+{
+ if (a == 42)
+ {
+ va_list ap;
+ va_start (ap, a);
+ if (va_arg (ap, double) != 15.0)
+ __builtin_abort ();
+ va_end (ap);
+ }
+ else if (a != 0)
+ __builtin_abort ();
+}
+
+void
+S::foo (int a, ...)
+{
+ if (a == 43)
+ {
+ va_list ap;
+ va_start (ap, a);
+ if (va_arg (ap, double) != 16.0)
+ __builtin_abort ();
+ va_end (ap);
+ }
+ else if (a != 0)
+ __builtin_abort ();
+}
+
+void
+S::bar (int a = I...) // { dg-warning "omission of ',' before varargs '...' is deprecated" "" { target c++26 } }
+{
+ if (a == 44)
+ {
+ va_list ap;
+ va_start (ap, a);
+ if (va_arg (ap, double) != 17.0)
+ __builtin_abort ();
+ va_end (ap);
+ }
+ else if (a != 0)
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ S s;
+ foo ();
+ foo (0);
+ foo (42, 15.0);
+ foo (42, 15.0, 128LL);
+ s.foo ();
+ s.foo (0);
+ s.foo (43, 16.0);
+ s.foo (43, 16.0, 129ULL);
+ s.bar ();
+ s.bar (0);
+ s.bar (44, 17.0);
+ s.bar (44, 17.0, 130L);
+}