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,
-                                &parameter->decl_specifiers,
-                                PARM,
-                                parameter->default_argument != NULL_TREE,
-                                &parameter->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

Reply via email to