c++: deferred parsing of default arguments [PR50479]
Commit Message
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
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
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
@@ -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);
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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 ();
+}
new file mode 100644
@@ -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" }
+}
new file mode 100644
@@ -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 ();
+}
+
new file mode 100644
@@ -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();
+}
@@ -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)