https://gcc.gnu.org/g:4bed19cf6170541ff757ee1b21d9fec9eb0c6541

commit r16-3224-g4bed19cf6170541ff757ee1b21d9fec9eb0c6541
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Fri Aug 15 22:34:59 2025 +0200

    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  <ja...@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.

Diff:
---
 gcc/cp/parser.cc                      |  6 ++-
 gcc/testsuite/g++.dg/parse/defarg20.C | 79 +++++++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index d733b724ce59..d66b658b748f 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 000000000000..577c093fb97a
--- /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);
+}

Reply via email to