diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/pt.cc | 35 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C | 42 |
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>(); +} |