aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/pt.cc35
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C42
2 files changed, 60 insertions, 17 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 72b17fd..310e5df 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -9326,7 +9326,9 @@ coerce_template_parms (tree parms,
{
/* There must be a default arg in this case. */
arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,
- complain, in_decl);
+ complain | (processing_template_decl
+ ? tf_partial : tf_none),
+ in_decl);
/* The position of the first default template argument,
is also the number of non-defaulted arguments in NEW_INNER_ARGS.
Record that. */
@@ -13569,6 +13571,9 @@ build_extra_args (tree pattern, tree args, tsubst_flags_t complain)
/* Make a copy of the extra arguments so that they won't get changed
out from under us. */
tree extra = preserve_args (copy_template_args (args), /*cow_p=*/false);
+ if (complain & tf_partial)
+ /* Remember whether this is a partial substitution. */
+ TREE_STATIC (extra) = true;
if (local_specializations)
if (tree locals = extract_local_specs (pattern, complain))
extra = tree_cons (NULL_TREE, extra, locals);
@@ -13581,7 +13586,10 @@ build_extra_args (tree pattern, tree args, tsubst_flags_t complain)
tree
add_extra_args (tree extra, tree args, tsubst_flags_t complain, tree in_decl)
{
- if (extra && TREE_CODE (extra) == TREE_LIST)
+ if (!extra)
+ return args;
+
+ if (TREE_CODE (extra) == TREE_LIST)
{
for (tree elt = TREE_CHAIN (extra); elt; elt = TREE_CHAIN (elt))
{
@@ -13599,13 +13607,13 @@ add_extra_args (tree extra, tree args, tsubst_flags_t complain, tree in_decl)
gcc_assert (!TREE_PURPOSE (extra));
extra = TREE_VALUE (extra);
}
- if (uses_template_parms (extra))
- {
- /* This can happen after dependent substitution into a
- requires-expr or a lambda that uses constexpr if. */
- extra = tsubst_template_args (extra, args, complain, in_decl);
- args = add_outermost_template_args (args, extra);
- }
+ gcc_checking_assert (TREE_STATIC (extra) == uses_template_parms (extra));
+ if (TREE_STATIC (extra))
+ /* This is a partial substitution into e.g. a requires-expr or lambda-expr
+ inside a default template argument; we expect 'extra' to be a full set
+ of template arguments for the template context, so it suffices to just
+ substitute into them. */
+ args = tsubst_template_args (extra, args, complain, in_decl);
else
args = add_to_template_args (extra, args);
return args;
@@ -19704,7 +19712,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
args = add_extra_args (LAMBDA_EXPR_EXTRA_ARGS (t), args, complain, in_decl);
if (processing_template_decl
- && (!in_template_context || any_dependent_template_arguments_p (args)))
+ && (!in_template_context || (complain & tf_partial)))
{
/* Defer templated substitution into a lambda-expr if we lost the
necessary template context. This may happen for a lambda-expr
@@ -21825,13 +21833,6 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
case LAMBDA_EXPR:
{
- if (complain & tf_partial)
- {
- /* We don't have a full set of template arguments yet; don't touch
- the lambda at all. */
- gcc_assert (processing_template_decl);
- return t;
- }
tree r = tsubst_lambda_expr (t, args, complain, in_decl);
RETURN (build_lambda_object (r));
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C b/gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C
new file mode 100644
index 0000000..97b42d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C
@@ -0,0 +1,42 @@
+// PR c++/116567
+// { dg-do compile { target c++20 } }
+
+struct X { int n; };
+
+template<auto N, auto F = []{ return N; }>
+auto v1 = F;
+
+template<auto N, auto F = [](auto y){ return decltype(N){N.n + y}; }>
+auto v1g = F;
+
+template<class T>
+struct A {
+ template<auto N, auto F = []{ return N; }>
+ static inline auto v2 = F;
+
+ template<auto N, auto F = [](auto y){ return decltype(N){N.n + y}; }>
+ static inline auto v2g = F;
+
+ template<class U>
+ struct B {
+ template<auto N, auto F = []{ return N; }>
+ static inline auto v3 = F;
+
+ template<auto N, auto F = [](auto y){ return decltype(N){N.n + y}; }>
+ static inline auto v3g = F;
+
+ template<class V>
+ static void f() {
+ static_assert(v1<X{1}>().n == 1);
+ static_assert(v1g<X{1}>(42).n == 1 + 42);
+ static_assert(v2<X{2}>().n == 2);
+ static_assert(v2g<X{2}>(42).n == 2 + 42);
+ static_assert(v3<X{3}>().n == 3);
+ static_assert(v3g<X{3}>(42).n == 3 + 42);
+ }
+ };
+};
+
+int main() {
+ A<int>::B<int>::f<int>();
+}