diff options
author | Jakub Jelinek <jakub@redhat.com> | 2025-08-15 22:34:59 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2025-08-15 22:34:59 +0200 |
commit | 4bed19cf6170541ff757ee1b21d9fec9eb0c6541 (patch) | |
tree | f3170b998dc66f2f436f619b5b92229db996cae8 | |
parent | cdd015c4ddbb1ae71eea1e44654cee5ca29a6c64 (diff) | |
download | gcc-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.cc | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/parse/defarg20.C | 79 |
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); +} |