c++: deferred parsing of default arguments [PR50479]

Message ID 20260506011912.1371228-1-polacek@redhat.com
State New
Headers
Series c++: deferred parsing of default arguments [PR50479] |

Commit Message

Marek Polacek May 6, 2026, 1:19 a.m. UTC
  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.  Unfortunately,
lambdas complicated this patch somewhat.  _late_parse_one_default_arg
always does start_lambda_scope which here would set lambda_scope.scope
to the parameter which doesn't yet have a DECL_CONTEXT, and we'd crash.
But for the default argument in

  inline void g(int n) {
    int bef(int i = []{ return 1; }());
  }

the scope should be 'g' anyway, not 'bef'.  Thus the adjust_lambda_scope_p
parameter to preserve the existing behavior.

	PR c++/50479
	PR c++/62244

gcc/cp/ChangeLog:

	* parser.cc (defining_nonlambda_class_type_p): New.
	(cp_parser_parameter_declaration_list): Maybe perform deferred
	parsing of default arguments.
	(cp_parser_parameter_declaration): Defer parsing of named
	parameters.
	(cp_parser_noexcept_specification_opt): Use
	defining_nonlambda_class_type_p.
	(cp_parser_late_parse_one_default_arg): New parameter.  Use it to
	avoid the calls to start_/finish_lambda_scope.

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                      | 86 +++++++++++++++++++++------
 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, 173 insertions(+), 22 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


base-commit: 3a9643ffe7fea815aab8afa122a4bf12fbc5b54e
  

Comments

Marek Polacek May 6, 2026, 1:20 p.m. UTC | #1
On Tue, May 05, 2026 at 09:19:12PM -0400, Marek Polacek wrote:
> @@ -37088,11 +37132,13 @@ cp_parser_save_default_args (cp_parser* parser, tree decl)
>  /* DEFAULT_ARG contains the saved tokens for the initializer of DECL,
>     which is either a FIELD_DECL or PARM_DECL.  Parse it and return
>     the result.  For a PARM_DECL, PARMTYPE is the corresponding type
> -   from the parameter-type-list.  */
> +   from the parameter-type-list.  If adjust_lambda_scope_p is true,

This should be "ADJUST_LAMBDA_SCOPE_P", fixed locally.

> +   we do start_/finish_lambda_scope.  */

Marek
  
Jason Merrill May 6, 2026, 8:15 p.m. UTC | #2
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?

> Unfortunately,
> lambdas complicated this patch somewhat.  _late_parse_one_default_arg
> always does start_lambda_scope which here would set lambda_scope.scope
> to the parameter which doesn't yet have a DECL_CONTEXT, and we'd crash.
> But for the default argument in
> 
>    inline void g(int n) {
>      int bef(int i = []{ return 1; }());
>    }
> 
> the scope should be 'g' anyway, not 'bef'.  Thus the adjust_lambda_scope_p
> parameter to preserve the existing behavior.
> 
> 	PR c++/50479
> 	PR c++/62244
> 
> gcc/cp/ChangeLog:
> 
> 	* parser.cc (defining_nonlambda_class_type_p): New.
> 	(cp_parser_parameter_declaration_list): Maybe perform deferred
> 	parsing of default arguments.
> 	(cp_parser_parameter_declaration): Defer parsing of named
> 	parameters.
> 	(cp_parser_noexcept_specification_opt): Use
> 	defining_nonlambda_class_type_p.
> 	(cp_parser_late_parse_one_default_arg): New parameter.  Use it to
> 	avoid the calls to start_/finish_lambda_scope.
> 
> 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                      | 86 +++++++++++++++++++++------
>   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, 173 insertions(+), 22 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..9c8cd7bdc90 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -3104,7 +3104,7 @@ static void cp_parser_save_default_args
>   static void cp_parser_late_parsing_for_member
>     (cp_parser *, tree);
>   static tree cp_parser_late_parse_one_default_arg
> -  (cp_parser *, tree, tree, tree);
> +  (cp_parser *, tree, tree, tree, bool = true);
>   static void cp_parser_late_parsing_nsdmi
>     (cp_parser *, tree);
>   static void cp_parser_late_parsing_default_args
> @@ -28126,6 +28126,17 @@ function_being_declared_is_template_p (cp_parser* parser)
>   	  (current_class_type));
>   }
>   
> +/* Return true if we are defining a class which is not a lambda closure
> +   type.  */
> +
> +static bool
> +defining_nonlambda_class_type_p ()
> +{
> +  return (at_class_scope_p ()
> +	  && TYPE_BEING_DEFINED (current_class_type)
> +	  && !LAMBDA_TYPE_P (current_class_type));
> +}
> +
>   /* Parse a parameter-declaration-clause.
>   
>      parameter-declaration-clause:
> @@ -28370,6 +28381,32 @@ cp_parser_parameter_declaration_list (cp_parser* parser,
>   	  retrofit_lang_decl (decl);
>   	  DECL_PARM_INDEX (decl) = ++index;
>   	  DECL_PARM_LEVEL (decl) = function_parm_depth ();
> +
> +	  if (tree &def = parameter->default_argument)
> +	    if (TREE_CODE (def) == DEFERRED_PARSE
> +		/* If we're defining a class, let _class_specifier
> +		   -> _late_parsing_default_args re-parse the default
> +		   argument.  */
> +		&& !defining_nonlambda_class_type_p ())
> +	      {
> +		auto lvf
> +		  = make_temp_override (parser->local_variables_forbidden_p);
> +		parser->local_variables_forbidden_p
> +		  = LOCAL_VARS_AND_THIS_FORBIDDEN;
> +		push_unparsed_function_queues (parser);
> +		/* We used to not defer parsing for default arguments outside
> +		   classes, and just called _default_argument.  In order to
> +		   preserve mangling of lambdas (see e.g. in lambda-mangle.C),
> +		   we tell this function to omit the call to start_lambda_scope
> +		   otherwise the lambda scope would be the current PARM_DECL
> +		   which doesn't have a context yet.  Even if it had a context,
> +		   it would be wrong for block-extern function declarations
> +		   where the context should be the enclosing function body.  */
> +		def = cp_parser_late_parse_one_default_arg (parser, decl, def,
> +							    TREE_TYPE (decl),
> +							    /*lscope=*/false);
> +		pop_unparsed_function_queues (parser);
> +	      }
>   	}
>   
>         /* Add the new parameter to the list.  */
> @@ -28710,21 +28747,30 @@ cp_parser_parameter_declaration (cp_parser *parser,
>         eq_token = token;
>         if (declarator)
>   	declarator->init_loc = token->location;
> -      /* If we are defining a class, then the tokens that make up the
> -	 default argument must be saved and processed later.  */
> -      if (!template_parm_p && at_class_scope_p ()
> -	  && TYPE_BEING_DEFINED (current_class_type)
> -	  && !LAMBDA_TYPE_P (current_class_type))
> -	default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false);
> -
>         /* A constrained-type-specifier may declare a type
>   	 template-parameter.  */
> -      else if (declares_constrained_type_template_parameter (type))
> +      if (declares_constrained_type_template_parameter (type))
>           default_argument
>             = cp_parser_default_type_template_argument (parser);
> -
> -      /* Outside of a class definition, we can just parse the
> -	 assignment-expression.  */
> +      /* If we are defining a class, then the tokens that make up the
> +	 default argument must be saved and processed later.  We also
> +	 have to defer parsing for named parameters to correctly handle
> +	   void fn (int i = sizeof (i));
> +	 which is OK.  */
> +      else if (!template_parm_p
> +	       && (defining_nonlambda_class_type_p ()
> +		   || (get_id_declarator (declarator)
> +		       /* Optimization only: if we see "int i = 42",
> +			  we don't have to defer parsing.  */
> +		       && !((cp_lexer_nth_token_is (parser->lexer, 2,
> +						    CPP_NUMBER)
> +			     || cp_lexer_nth_token_is (parser->lexer, 2,
> +						       CPP_KEYWORD))
> +			    && (cp_lexer_nth_token_is (parser->lexer, 3,
> +						       CPP_CLOSE_PAREN)
> +				|| cp_lexer_nth_token_is (parser->lexer, 3,
> +							  CPP_COMMA))))))
> +	default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false);
>         else
>   	default_argument
>   	  = cp_parser_default_argument (parser, template_parm_p);
> @@ -32177,9 +32223,7 @@ cp_parser_noexcept_specification_opt (cp_parser* parser,
>   	  && !((cp_lexer_nth_token_is (parser->lexer, 3, CPP_NUMBER)
>   		|| cp_lexer_nth_token_is (parser->lexer, 3, CPP_KEYWORD))
>   	       && cp_lexer_nth_token_is (parser->lexer, 4, CPP_CLOSE_PAREN))
> -	  && at_class_scope_p ()
> -	  && TYPE_BEING_DEFINED (current_class_type)
> -	  && !LAMBDA_TYPE_P (current_class_type))
> +	  && defining_nonlambda_class_type_p ())
>   	return cp_parser_save_noexcept (parser);
>   
>         cp_lexer_consume_token (parser->lexer);
> @@ -37088,11 +37132,13 @@ cp_parser_save_default_args (cp_parser* parser, tree decl)
>   /* DEFAULT_ARG contains the saved tokens for the initializer of DECL,
>      which is either a FIELD_DECL or PARM_DECL.  Parse it and return
>      the result.  For a PARM_DECL, PARMTYPE is the corresponding type
> -   from the parameter-type-list.  */
> +   from the parameter-type-list.  If adjust_lambda_scope_p is true,
> +   we do start_/finish_lambda_scope.  */
>   
>   static tree
>   cp_parser_late_parse_one_default_arg (cp_parser *parser, tree decl,
> -				      tree default_arg, tree parmtype)
> +				      tree default_arg, tree parmtype,
> +				      bool adjust_lambda_scope_p/*=true*/)
>   {
>     cp_token_cache *tokens;
>     tree parsed_arg;
> @@ -37105,14 +37151,16 @@ cp_parser_late_parse_one_default_arg (cp_parser *parser, tree decl,
>     tokens = DEFPARSE_TOKENS (default_arg);
>     cp_parser_push_lexer_for_tokens (parser, tokens);
>   
> -  start_lambda_scope (decl);
> +  if (adjust_lambda_scope_p)
> +    start_lambda_scope (decl);
>   
>     /* Parse the default argument.  */
>     parsed_arg = cp_parser_initializer (parser);
>     if (BRACE_ENCLOSED_INITIALIZER_P (parsed_arg))
>       maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
>   
> -  finish_lambda_scope ();
> +  if (adjust_lambda_scope_p)
> +    finish_lambda_scope ();
>   
>     if (parsed_arg == error_mark_node)
>       cp_parser_skip_to_end_of_statement (parser);
> 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: 3a9643ffe7fea815aab8afa122a4bf12fbc5b54e
  

Patch

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index d128de771b5..9c8cd7bdc90 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -3104,7 +3104,7 @@  static void cp_parser_save_default_args
 static void cp_parser_late_parsing_for_member
   (cp_parser *, tree);
 static tree cp_parser_late_parse_one_default_arg
-  (cp_parser *, tree, tree, tree);
+  (cp_parser *, tree, tree, tree, bool = true);
 static void cp_parser_late_parsing_nsdmi
   (cp_parser *, tree);
 static void cp_parser_late_parsing_default_args
@@ -28126,6 +28126,17 @@  function_being_declared_is_template_p (cp_parser* parser)
 	  (current_class_type));
 }
 
+/* Return true if we are defining a class which is not a lambda closure
+   type.  */
+
+static bool
+defining_nonlambda_class_type_p ()
+{
+  return (at_class_scope_p ()
+	  && TYPE_BEING_DEFINED (current_class_type)
+	  && !LAMBDA_TYPE_P (current_class_type));
+}
+
 /* Parse a parameter-declaration-clause.
 
    parameter-declaration-clause:
@@ -28370,6 +28381,32 @@  cp_parser_parameter_declaration_list (cp_parser* parser,
 	  retrofit_lang_decl (decl);
 	  DECL_PARM_INDEX (decl) = ++index;
 	  DECL_PARM_LEVEL (decl) = function_parm_depth ();
+
+	  if (tree &def = parameter->default_argument)
+	    if (TREE_CODE (def) == DEFERRED_PARSE
+		/* If we're defining a class, let _class_specifier
+		   -> _late_parsing_default_args re-parse the default
+		   argument.  */
+		&& !defining_nonlambda_class_type_p ())
+	      {
+		auto lvf
+		  = make_temp_override (parser->local_variables_forbidden_p);
+		parser->local_variables_forbidden_p
+		  = LOCAL_VARS_AND_THIS_FORBIDDEN;
+		push_unparsed_function_queues (parser);
+		/* We used to not defer parsing for default arguments outside
+		   classes, and just called _default_argument.  In order to
+		   preserve mangling of lambdas (see e.g. in lambda-mangle.C),
+		   we tell this function to omit the call to start_lambda_scope
+		   otherwise the lambda scope would be the current PARM_DECL
+		   which doesn't have a context yet.  Even if it had a context,
+		   it would be wrong for block-extern function declarations
+		   where the context should be the enclosing function body.  */
+		def = cp_parser_late_parse_one_default_arg (parser, decl, def,
+							    TREE_TYPE (decl),
+							    /*lscope=*/false);
+		pop_unparsed_function_queues (parser);
+	      }
 	}
 
       /* Add the new parameter to the list.  */
@@ -28710,21 +28747,30 @@  cp_parser_parameter_declaration (cp_parser *parser,
       eq_token = token;
       if (declarator)
 	declarator->init_loc = token->location;
-      /* If we are defining a class, then the tokens that make up the
-	 default argument must be saved and processed later.  */
-      if (!template_parm_p && at_class_scope_p ()
-	  && TYPE_BEING_DEFINED (current_class_type)
-	  && !LAMBDA_TYPE_P (current_class_type))
-	default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false);
-
       /* A constrained-type-specifier may declare a type
 	 template-parameter.  */
-      else if (declares_constrained_type_template_parameter (type))
+      if (declares_constrained_type_template_parameter (type))
         default_argument
           = cp_parser_default_type_template_argument (parser);
-
-      /* Outside of a class definition, we can just parse the
-	 assignment-expression.  */
+      /* If we are defining a class, then the tokens that make up the
+	 default argument must be saved and processed later.  We also
+	 have to defer parsing for named parameters to correctly handle
+	   void fn (int i = sizeof (i));
+	 which is OK.  */
+      else if (!template_parm_p
+	       && (defining_nonlambda_class_type_p ()
+		   || (get_id_declarator (declarator)
+		       /* Optimization only: if we see "int i = 42",
+			  we don't have to defer parsing.  */
+		       && !((cp_lexer_nth_token_is (parser->lexer, 2,
+						    CPP_NUMBER)
+			     || cp_lexer_nth_token_is (parser->lexer, 2,
+						       CPP_KEYWORD))
+			    && (cp_lexer_nth_token_is (parser->lexer, 3,
+						       CPP_CLOSE_PAREN)
+				|| cp_lexer_nth_token_is (parser->lexer, 3,
+							  CPP_COMMA))))))
+	default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false);
       else
 	default_argument
 	  = cp_parser_default_argument (parser, template_parm_p);
@@ -32177,9 +32223,7 @@  cp_parser_noexcept_specification_opt (cp_parser* parser,
 	  && !((cp_lexer_nth_token_is (parser->lexer, 3, CPP_NUMBER)
 		|| cp_lexer_nth_token_is (parser->lexer, 3, CPP_KEYWORD))
 	       && cp_lexer_nth_token_is (parser->lexer, 4, CPP_CLOSE_PAREN))
-	  && at_class_scope_p ()
-	  && TYPE_BEING_DEFINED (current_class_type)
-	  && !LAMBDA_TYPE_P (current_class_type))
+	  && defining_nonlambda_class_type_p ())
 	return cp_parser_save_noexcept (parser);
 
       cp_lexer_consume_token (parser->lexer);
@@ -37088,11 +37132,13 @@  cp_parser_save_default_args (cp_parser* parser, tree decl)
 /* DEFAULT_ARG contains the saved tokens for the initializer of DECL,
    which is either a FIELD_DECL or PARM_DECL.  Parse it and return
    the result.  For a PARM_DECL, PARMTYPE is the corresponding type
-   from the parameter-type-list.  */
+   from the parameter-type-list.  If adjust_lambda_scope_p is true,
+   we do start_/finish_lambda_scope.  */
 
 static tree
 cp_parser_late_parse_one_default_arg (cp_parser *parser, tree decl,
-				      tree default_arg, tree parmtype)
+				      tree default_arg, tree parmtype,
+				      bool adjust_lambda_scope_p/*=true*/)
 {
   cp_token_cache *tokens;
   tree parsed_arg;
@@ -37105,14 +37151,16 @@  cp_parser_late_parse_one_default_arg (cp_parser *parser, tree decl,
   tokens = DEFPARSE_TOKENS (default_arg);
   cp_parser_push_lexer_for_tokens (parser, tokens);
 
-  start_lambda_scope (decl);
+  if (adjust_lambda_scope_p)
+    start_lambda_scope (decl);
 
   /* Parse the default argument.  */
   parsed_arg = cp_parser_initializer (parser);
   if (BRACE_ENCLOSED_INITIALIZER_P (parsed_arg))
     maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
 
-  finish_lambda_scope ();
+  if (adjust_lambda_scope_p)
+    finish_lambda_scope ();
 
   if (parsed_arg == error_mark_node)
     cp_parser_skip_to_end_of_statement (parser);
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)