On Wed, May 06, 2026 at 04:15:03PM -0400, Jason Merrill wrote:
> On 5/5/26 9:19 PM, Marek Polacek wrote:
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> >
> > Additionally tested with the "Optimization only" checks disabled
> > to see if it isn't hiding any errors.
> >
> > -- >8 --
> > In
> >
> > void fn (int i = sizeof (i)) {}
> >
> > the i in sizeof should refer to the parameter ([basic.scope.pdecl]) and
> > since the second i is not evaluated, the code is valid per
> > [dcl.fct.default]/9: A parameter shall not appear as a potentially
> > evaluated expression in a default argument.
> >
> > To make this work, we have to defer parsing of the default argument
> > until we've done grokdeclarator + pushdecl on i.
>
> How about doing that by moving grokdeclarator/pushdecl into
> cp_parser_parameter_declaration rather than mess with DEFERRED_PARSE?
Looks like I actually can do that. I just have to pass the decl back
to _parameter_declaration_list, otherwise the pending_decls handling
could become ugly. But it seems better than the DEFERRED_PARSE
approach.
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
-- >8 --
In
void fn (int i = sizeof (i)) {}
the i in sizeof should refer to the parameter ([basic.scope.pdecl]) and
since the second i is not evaluated, the code is valid per
[dcl.fct.default]/9: A parameter shall not appear as a potentially
evaluated expression in a default argument.
This patch fixes this by moving the grokdeclarator call from
_parameter_declaration_list to _parameter_declaration and maybe calling
pushdecl before parsing the default argument.
PR c++/50479
PR c++/62244
gcc/cp/ChangeLog:
* parser.cc (cp_parser_parameter_declaration_list): Move the
grokdeclarator call and setting DECL_SOURCE_LOCATION to...
(cp_parser_parameter_declaration): ...here. New tree parameter.
Set it. Call pushdecl for a named decl with a default argument.
gcc/testsuite/ChangeLog:
* g++.dg/reflect/parm1.C: Uncomment code.
* g++.dg/parse/defarg22.C: New test.
* g++.dg/parse/defarg23.C: New test.
* g++.dg/parse/defarg24.C: New test.
* g++.dg/parse/defarg25.C: New test.
* g++.dg/parse/defarg26.C: New test.
---
gcc/cp/parser.cc | 63 +++++++++++++++++----------
gcc/testsuite/g++.dg/parse/defarg22.C | 16 +++++++
gcc/testsuite/g++.dg/parse/defarg23.C | 36 +++++++++++++++
gcc/testsuite/g++.dg/parse/defarg24.C | 12 +++++
gcc/testsuite/g++.dg/parse/defarg25.C | 22 ++++++++++
gcc/testsuite/g++.dg/parse/defarg26.C | 18 ++++++++
gcc/testsuite/g++.dg/reflect/parm1.C | 5 +--
7 files changed, 146 insertions(+), 26 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/parse/defarg22.C
create mode 100644 gcc/testsuite/g++.dg/parse/defarg23.C
create mode 100644 gcc/testsuite/g++.dg/parse/defarg24.C
create mode 100644 gcc/testsuite/g++.dg/parse/defarg25.C
create mode 100644 gcc/testsuite/g++.dg/parse/defarg26.C
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index d128de771b5..66126115e61 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -2785,7 +2785,7 @@ static tree cp_parser_parameter_declaration_clause
static tree cp_parser_parameter_declaration_list
(cp_parser *, cp_parser_flags, auto_vec<tree> *);
static cp_parameter_declarator *cp_parser_parameter_declaration
- (cp_parser *, cp_parser_flags, bool, bool *);
+ (cp_parser *, cp_parser_flags, bool, bool *, tree * = nullptr);
static tree cp_parser_default_argument
(cp_parser *, bool);
static void cp_parser_function_body
@@ -28301,24 +28301,7 @@ cp_parser_parameter_declaration_list (cp_parser*
parser,
parameter
= cp_parser_parameter_declaration (parser, flags,
/*template_parm_p=*/false,
- &parenthesized_p);
-
- /* We don't know yet if the enclosing context is unavailable or
deprecated,
- so wait and deal with it in grokparms if appropriate. */
- deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS;
-
- if (parameter && !cp_parser_error_occurred (parser))
- {
- decl = grokdeclarator (parameter->declarator,
- ¶meter->decl_specifiers,
- PARM,
- parameter->default_argument != NULL_TREE,
- ¶meter->decl_specifiers.attributes);
- if (decl != error_mark_node && parameter->loc != UNKNOWN_LOCATION)
- DECL_SOURCE_LOCATION (decl) = parameter->loc;
- }
-
- deprecated_state = DEPRECATED_NORMAL;
+ &parenthesized_p, &decl);
/* If a parse error occurred parsing the parameter declaration,
then the entire parameter-declaration-list is erroneous. */
@@ -28361,7 +28344,10 @@ cp_parser_parameter_declaration_list (cp_parser*
parser,
return false;
}())
pending_decls->safe_push (decl);
- else
+ /* If we saw a default argument, we've already pushed this decl.
+ (An ill-formed default argument should have been parsed to
+ error_mark_node.) */
+ else if (!parameter->default_argument)
decl = pushdecl (decl);
}
@@ -28474,6 +28460,9 @@ cp_parser_parameter_declaration_list (cp_parser* parser,
token encountered during the parsing of the assignment-expression
is not interpreted as a greater-than operator.)
+ If DECL is non-null, we are called from cp_parser_parameter_declaration_list
+ and will perform grokdeclarator here; DECL will be set to the result.
+
Returns a representation of the parameter, or NULL if an error
occurs. If PARENTHESIZED_P is non-NULL, *PARENTHESIZED_P is set to
true iff the declarator is of the form "(p)". */
@@ -28482,7 +28471,8 @@ static cp_parameter_declarator *
cp_parser_parameter_declaration (cp_parser *parser,
cp_parser_flags flags,
bool template_parm_p,
- bool *parenthesized_p)
+ bool *parenthesized_p,
+ tree *decl/*=nullptr*/)
{
int declares_class_or_enum;
cp_decl_specifier_seq decl_specifiers;
@@ -28697,13 +28687,37 @@ cp_parser_parameter_declaration (cp_parser *parser,
decl_specifiers.locations[ds_this] = 0;
}
+ const bool has_defarg_p = cp_lexer_next_token_is (parser->lexer, CPP_EQ);
+
+ /* We don't know yet if the enclosing context is unavailable or deprecated,
+ so wait and deal with it in grokparms if appropriate. */
+ deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS;
+
+ /* We are processing a parameter-declaration-list and need to do this
+ early so that we have a DECL for the pushdecl below. */
+ if (decl && !cp_parser_error_occurred (parser))
+ *decl = grokdeclarator (declarator,
+ &decl_specifiers,
+ PARM,
+ has_defarg_p,
+ &decl_specifiers.attributes);
+
+ deprecated_state = DEPRECATED_NORMAL;
+
/* The restriction on defining new types applies only to the type
of the parameter, not to the default argument. */
parser->type_definition_forbidden_message = saved_message;
- cp_token *eq_token = NULL;
+ cp_token *eq_token = nullptr;
/* If the next token is `=', then process a default argument. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
+ if (has_defarg_p)
{
+ /* And if we have a default argument, we must be dealing with a function
+ declaration, so we can push now to correctly handle
+ void fn (int i = sizeof (i));
+ which is valid. */
+ if (decl && *decl != error_mark_node && DECL_NAME (*decl))
+ *decl = pushdecl (*decl);
+
tree type = decl_specifiers.type;
token = cp_lexer_peek_token (parser->lexer);
/* Used for diagnostics with an xobj parameter. */
@@ -28812,6 +28826,9 @@ cp_parser_parameter_declaration (cp_parser *parser,
decl_spec_token_start->location,
input_location);
+ if (decl && *decl != error_mark_node && param_loc != UNKNOWN_LOCATION)
+ DECL_SOURCE_LOCATION (*decl) = param_loc;
+
return make_parameter_declarator (&decl_specifiers,
declarator,
default_argument,
diff --git a/gcc/testsuite/g++.dg/parse/defarg22.C
b/gcc/testsuite/g++.dg/parse/defarg22.C
new file mode 100644
index 00000000000..f393b95a591
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/defarg22.C
@@ -0,0 +1,16 @@
+// PR c++/50479
+// { dg-do compile }
+
+void fn1 (int i = sizeof (i)) {}
+void fn2 (int i, int = sizeof (i)) {}
+
+void
+g ()
+{
+ void fn4 (int i = sizeof (i));
+ void fn5 (int i, int = sizeof (i));
+ fn1 ();
+ fn2 (42);
+ fn4 ();
+ fn5 (42);
+}
diff --git a/gcc/testsuite/g++.dg/parse/defarg23.C
b/gcc/testsuite/g++.dg/parse/defarg23.C
new file mode 100644
index 00000000000..0aeb1b33394
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/defarg23.C
@@ -0,0 +1,36 @@
+// PR c++/50479
+// { dg-do compile { target c++14 } }
+
+inline void
+fn1 ()
+{
+ int f (int i = []{ return 1; }());
+}
+
+auto l = [](int i = sizeof (i)) { };
+void fn2 (int i = []{ return 1; }()) {}
+void fn3 (int x = []{ decltype(x) y{}; return y; }()) {}
+void fn6 (int i = sizeof (i), decltype (i) = sizeof (i)) {}
+
+struct S {
+ int mfn1 (int i = sizeof (i)) { return i; }
+ int mfn2 (int i, int = sizeof (i)) { return i; }
+ int lm = [](int i6 = sizeof (i6)) { return i6; }();
+ int mfn3 (int i = []{ return 1; }()) { return i; }
+ int i = mfn1 () + mfn2 (42) + mfn3 () + lm;
+};
+
+void
+g ()
+{
+ auto ll = [](int i5 = sizeof (i5)) { };
+ void fn4 (int i = []{ return 1; }());
+ void fn5 (int x = []{ decltype(x) y{}; return y; }());
+ fn1 ();
+ fn2 ();
+ fn3 ();
+ fn4 ();
+ fn5 ();
+ fn6 ();
+ l ();
+}
diff --git a/gcc/testsuite/g++.dg/parse/defarg24.C
b/gcc/testsuite/g++.dg/parse/defarg24.C
new file mode 100644
index 00000000000..48b6f1f2a1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/defarg24.C
@@ -0,0 +1,12 @@
+// PR c++/50479
+// { dg-do compile { target c++11 } }
+
+void fn1 (int x = []{ return x; }()) {} // { dg-error "use of
parameter outside function body" }
+void fn2 (int x, int = []{ return x; }()) {} // { dg-error "use of parameter
outside function body" }
+
+void
+g ()
+{
+ void fn3 (int z = []{ return z; }()); // { dg-error "use of
parameter outside function body" }
+ void fn4 (int z, int = []{ return z; }()); // { dg-error "use of parameter
outside function body" }
+}
diff --git a/gcc/testsuite/g++.dg/parse/defarg25.C
b/gcc/testsuite/g++.dg/parse/defarg25.C
new file mode 100644
index 00000000000..95989885dfa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/defarg25.C
@@ -0,0 +1,22 @@
+// PR c++/62244
+// { dg-do compile { target c++11 } }
+
+int a;
+void f (int a = a); // { dg-error "parameter .a. may not appear in this
context" }
+
+int foo(int x = (decltype(x)(42))) { return 0; }
+
+static int value;
+
+int
+bar (int &value = value) // { dg-error "parameter .value. may not appear in
this context" }
+{
+ return value;
+}
+
+void
+g ()
+{
+ bar ();
+}
+
diff --git a/gcc/testsuite/g++.dg/parse/defarg26.C
b/gcc/testsuite/g++.dg/parse/defarg26.C
new file mode 100644
index 00000000000..170f7f5c0ec
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/defarg26.C
@@ -0,0 +1,18 @@
+// PR c++/50479
+// { dg-do compile { target c++11 } }
+
+template<class>
+struct A;
+
+template<>
+struct A<long> {
+ static const int value = 1;
+};
+
+long foo;
+
+void bar(char foo = A<decltype(foo)>::value) {} // { dg-error "incomplete
type" }
+
+int main() {
+ bar();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/parm1.C
b/gcc/testsuite/g++.dg/reflect/parm1.C
index 8416be5b0db..c844c1dff3f 100644
--- a/gcc/testsuite/g++.dg/reflect/parm1.C
+++ b/gcc/testsuite/g++.dg/reflect/parm1.C
@@ -4,9 +4,8 @@
#include <meta>
-// FIXME PR62244
-//consteval int fn(decltype(^^::) x = ^^x) { return 0; }
-//constexpr int x = fn ();
+consteval int fn(decltype(^^::) x = ^^x) { return 0; }
+constexpr int x = fn ();
consteval auto
ref (std::meta::info r)
base-commit: 03894dd6c6ec8bcfab6c9058c22f88691a2e7711
--
2.54.0