diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 52d53589e51..1dbb577a38d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1538,6 +1538,10 @@ enum cp_lambda_default_capture_mode_type { #define LAMBDA_EXPR_REGEN_INFO(NODE) \ (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regen_info) +/* Like PACK_EXPANSION_EXTRA_ARGS, for lambda-expressions. */ +#define LAMBDA_EXPR_EXTRA_ARGS(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->extra_args) + /* The closure type of the lambda, which is also the type of the LAMBDA_EXPR. */ #define LAMBDA_EXPR_CLOSURE(NODE) \ @@ -1550,6 +1554,7 @@ struct GTY (()) tree_lambda_expr tree this_capture; tree extra_scope; tree regen_info; + tree extra_args; vec *pending_proxies; location_t locus; enum cp_lambda_default_capture_mode_type default_capture_mode : 2; diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 4e91fa6e052..ad1b6bf5ca4 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -6312,6 +6312,7 @@ trees_out::core_vals (tree t) WT (((lang_tree_node *)t)->lambda_expression.this_capture); WT (((lang_tree_node *)t)->lambda_expression.extra_scope); WT (((lang_tree_node *)t)->lambda_expression.regen_info); + WT (((lang_tree_node *)t)->lambda_expression.extra_args); /* pending_proxies is a parse-time thing. */ gcc_assert (!((lang_tree_node *)t)->lambda_expression.pending_proxies); if (state) @@ -6814,6 +6815,7 @@ trees_in::core_vals (tree t) RT (((lang_tree_node *)t)->lambda_expression.this_capture); RT (((lang_tree_node *)t)->lambda_expression.extra_scope); RT (((lang_tree_node *)t)->lambda_expression.regen_info); + RT (((lang_tree_node *)t)->lambda_expression.extra_args); /* lambda_expression.pending_proxies is NULL */ ((lang_tree_node *)t)->lambda_expression.locus = state->read_location (*this); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 7c91c6959aa..ec259ee0fbf 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -3855,7 +3855,8 @@ has_extra_args_mechanism_p (const_tree t) return (PACK_EXPANSION_P (t) /* PACK_EXPANSION_EXTRA_ARGS */ || TREE_CODE (t) == REQUIRES_EXPR /* REQUIRES_EXPR_EXTRA_ARGS */ || (TREE_CODE (t) == IF_STMT - && IF_STMT_CONSTEXPR_P (t))); /* IF_STMT_EXTRA_ARGS */ + && IF_STMT_CONSTEXPR_P (t)) /* IF_STMT_EXTRA_ARGS */ + || TREE_CODE (t) == LAMBDA_EXPR); /* LAMBDA_EXPR_EXTRA_ARGS */ } /* Return *_EXTRA_ARGS of the given supported tree T. */ @@ -3872,6 +3873,8 @@ tree_extra_args (tree t) else if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEXPR_P (t)) return IF_STMT_EXTRA_ARGS (t); + else if (TREE_CODE (t) == LAMBDA_EXPR) + return LAMBDA_EXPR_EXTRA_ARGS (t); gcc_unreachable (); } @@ -19618,6 +19621,18 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) tree oldfn = lambda_function (t); in_decl = oldfn; + args = add_extra_args (LAMBDA_EXPR_EXTRA_ARGS (t), args, complain, in_decl); + if (processing_template_decl && !in_template_context) + { + /* Defer templated substitution into a lambda-expr if we lost the + necessary template context. This may happen for a lambda-expr + used as a default template argument. */ + t = copy_node (t); + LAMBDA_EXPR_EXTRA_ARGS (t) = NULL_TREE; + LAMBDA_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, complain); + return t; + } + tree r = build_lambda_expr (); LAMBDA_EXPR_LOCATION (r) @@ -19709,7 +19724,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) tree type = begin_lambda_type (r); if (type == error_mark_node) - return error_mark_node; + { + gcc_checking_assert (!(complain & tf_error) || seen_error ()); + return error_mark_node; + } if (LAMBDA_EXPR_EXTRA_SCOPE (t)) record_lambda_scope (r); diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ2.C b/gcc/testsuite/g++.dg/cpp2a/lambda-targ2.C new file mode 100644 index 00000000000..41b8d8749f2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ2.C @@ -0,0 +1,19 @@ +// PR c++/114393 +// { dg-do compile { target c++20 } } + +template struct c1 {}; + +template +inline constexpr auto b_v = t; + +template +using c1_t = c1>; + +template +constexpr auto g(_Data __data) { + return c1_t<_Data>{}; +} + +void f() { + auto &&b = g(0); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ3.C b/gcc/testsuite/g++.dg/cpp2a/lambda-targ3.C new file mode 100644 index 00000000000..31d08add277 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ3.C @@ -0,0 +1,12 @@ +// PR c++/107457 +// { dg-do compile { target c++20 } } + +template +using lambda = decltype([]() {}); + +template> +void test() { } + +int main() { + test(); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ4.C b/gcc/testsuite/g++.dg/cpp2a/lambda-targ4.C new file mode 100644 index 00000000000..341a1aa5bb1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ4.C @@ -0,0 +1,12 @@ +// PR c++/93595 +// { dg-do compile { target c++20 } } + +template +struct bad { + template + static void f(T) { } +}; + +int main() { + bad<0>::f(0); +}