From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1888) id 4F987382CB9E; Thu, 15 Dec 2022 20:54:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4F987382CB9E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1671137682; bh=5jq4mPdK1ieFZjxdfgajXPVW7U2Bg9ajHbSqYqKeFTI=; h=From:To:Subject:Date:From; b=lBYsZuYT9H+L2Xp+vI5ETuAsVsf0hheXRSgpkmE8KvfWM0xq6DhXjrhmu8JOr9yol kwmZHDrcjwzNXAzlu++mjUW1tPpVjg61Vow9hs6sxYDEXMwv9QgU9vw6tY/C5n7z4c vbAeCXKuw7TVPYX2sl/BnlvDqePwzYGX0OcwK47I= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Patrick Palka To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-4729] c++: local alias in typename in lambda [PR105518] X-Act-Checkin: gcc X-Git-Author: Patrick Palka X-Git-Refname: refs/heads/master X-Git-Oldrev: 38304846d18d6bb14b0fd6c627c5c6d43a814d01 X-Git-Newrev: be124477b38a71ba8ba0b24d859ae764bb44a4eb Message-Id: <20221215205442.4F987382CB9E@sourceware.org> Date: Thu, 15 Dec 2022 20:54:42 +0000 (GMT) List-Id: https://gcc.gnu.org/g:be124477b38a71ba8ba0b24d859ae764bb44a4eb commit r13-4729-gbe124477b38a71ba8ba0b24d859ae764bb44a4eb Author: Patrick Palka Date: Thu Dec 15 15:54:31 2022 -0500 c++: local alias in typename in lambda [PR105518] We substitute the qualifying scope of a TYPENAME_TYPE directly using tsubst_aggr_type (so that we can pass entering_scope=true) instead of going through tsubst, which means we don't properly reuse typedefs during this substitution. This ends up causing us to reject the below testcase because we substitute the TYPENAME_TYPE alias::type as if it were written without the A alias, and thus we expect the non-capturing lambda to capture t. This patch fixes this by making tsubst_aggr_type delegate typedefs to tsubst so that get consistently reused, and then adjusting the result appropriately if entering_scope is true. In passing, this refactors tsubst_aggr_type into two functions, one that's intended to be called directly and a more minimal one that's intended to be called only from the RECORD/UNION/ENUMERAL_TYPE cases of tsubst (and contains only the necessary bits for that call site). PR c++/105518 gcc/cp/ChangeLog: * pt.cc (tsubst_aggr_type): Handle typedefs by delegating to tsubst and adjusting the result if entering_scope. Split out the main part of the function into ... (tsubst_aggr_type_1) ... here. (tsubst): Use tsubst_aggr_type_1 instead of tsubst_aggr_type. Handle TYPE_PTRMEMFUNC_P RECORD_TYPEs here instead of in tsubst_aggr_type_1. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/lambda/lambda-alias1.C: New test. Diff: --- gcc/cp/pt.cc | 111 ++++++++++++++-------- gcc/testsuite/g++.dg/cpp0x/lambda/lambda-alias1.C | 23 +++++ 2 files changed, 92 insertions(+), 42 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index efd4eaa9afd..38e3a1672c1 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -185,6 +185,7 @@ static tree tsubst_template_parms (tree, tree, tsubst_flags_t); static void tsubst_each_template_parm_constraints (tree, tree, tsubst_flags_t); tree most_specialized_partial_spec (tree, tsubst_flags_t); static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int); +static tree tsubst_aggr_type_1 (tree, tree, tsubst_flags_t, tree, int); static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree); static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree); static bool check_specialization_scope (void); @@ -13828,57 +13829,80 @@ tsubst_aggr_type (tree t, if (t == NULL_TREE) return NULL_TREE; - /* If T is an alias template specialization, we want to substitute that - rather than strip it, especially if it's dependent_alias_template_spec_p. - It should be OK not to handle entering_scope in this case, since - DECL_CONTEXT will never be an alias template specialization. We only get - here with an alias when tsubst calls us for TYPENAME_TYPE. */ - if (alias_template_specialization_p (t, nt_transparent)) - return tsubst (t, args, complain, in_decl); + /* Handle typedefs via tsubst so that they get consistently reused. */ + if (typedef_variant_p (t)) + { + t = tsubst (t, args, complain, in_decl); + if (t == error_mark_node) + return error_mark_node; + + /* The effect of entering_scope is that for a dependent specialization + A, lookup_template_class prefers to return A's primary template + type instead of the implicit instantiation. So when entering_scope, + we mirror this behavior by inspecting TYPE_CANONICAL appropriately, + taking advantage of the fact that lookup_template_class links the two + types by setting TYPE_CANONICAL of the latter to the former. */ + if (entering_scope + && CLASS_TYPE_P (t) + && dependent_type_p (t) + && TYPE_CANONICAL (t) == TREE_TYPE (TYPE_TI_TEMPLATE (t))) + t = TYPE_CANONICAL (t); + + return t; + } switch (TREE_CODE (t)) { - case RECORD_TYPE: - if (TYPE_PTRMEMFUNC_P (t)) - return tsubst (TYPE_PTRMEMFUNC_FN_TYPE (t), args, complain, in_decl); + case RECORD_TYPE: + case ENUMERAL_TYPE: + case UNION_TYPE: + return tsubst_aggr_type_1 (t, args, complain, in_decl, entering_scope); - /* Fall through. */ - case ENUMERAL_TYPE: - case UNION_TYPE: - if (TYPE_TEMPLATE_INFO (t) && uses_template_parms (t)) - { - tree argvec; - tree r; + default: + return tsubst (t, args, complain, in_decl); + } +} - /* Figure out what arguments are appropriate for the - type we are trying to find. For example, given: +/* The part of tsubst_aggr_type that's shared with the RECORD_, UNION_ + and ENUMERAL_TYPE cases of tsubst. */ + +static tree +tsubst_aggr_type_1 (tree t, + tree args, + tsubst_flags_t complain, + tree in_decl, + int entering_scope) +{ + if (TYPE_TEMPLATE_INFO (t) && uses_template_parms (t)) + { + tree argvec; + tree r; - template struct S; - template void f(T, U) { S su; } + /* Figure out what arguments are appropriate for the + type we are trying to find. For example, given: - and supposing that we are instantiating f, - then our ARGS will be {int, double}, but, when looking up - S we only want {double}. */ - argvec = tsubst_template_args (TYPE_TI_ARGS (t), args, - complain, in_decl); - if (argvec == error_mark_node) - r = error_mark_node; - else - { - r = lookup_template_class (t, argvec, in_decl, NULL_TREE, - entering_scope, complain); - r = cp_build_qualified_type (r, cp_type_quals (t), complain); - } + template struct S; + template void f(T, U) { S su; } - return r; - } + and supposing that we are instantiating f, + then our ARGS will be {int, double}, but, when looking up + S we only want {double}. */ + argvec = tsubst_template_args (TYPE_TI_ARGS (t), args, + complain, in_decl); + if (argvec == error_mark_node) + r = error_mark_node; else - /* This is not a template type, so there's nothing to do. */ - return t; + { + r = lookup_template_class (t, argvec, in_decl, NULL_TREE, + entering_scope, complain); + r = cp_build_qualified_type (r, cp_type_quals (t), complain); + } - default: - return tsubst (t, args, complain, in_decl); + return r; } + else + /* This is not a template type, so there's nothing to do. */ + return t; } /* Map from a FUNCTION_DECL to a vec of default argument instantiations, @@ -15795,10 +15819,13 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) switch (code) { case RECORD_TYPE: + if (TYPE_PTRMEMFUNC_P (t)) + return tsubst (TYPE_PTRMEMFUNC_FN_TYPE (t), args, complain, in_decl); + /* Fall through. */ case UNION_TYPE: case ENUMERAL_TYPE: - return tsubst_aggr_type (t, args, complain, in_decl, - /*entering_scope=*/0); + return tsubst_aggr_type_1 (t, args, complain, in_decl, + /*entering_scope=*/0); case ERROR_MARK: case IDENTIFIER_NODE: diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-alias1.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-alias1.C new file mode 100644 index 00000000000..08c38e6f84c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-alias1.C @@ -0,0 +1,23 @@ +// PR c++/105518 +// { dg-do compile { target c++11 } } + +struct integral_constant { + constexpr operator int() const { return 42; } +}; + +template +struct A { + using type = A; + static constexpr int value = N; +}; + +template +void f(T t) { + using alias = A; + [](int) { + typename alias::type a; // { dg-bogus "'t' is not captured" } + return a.value; + }(0); +} + +template void f(integral_constant);