diff options
author | Patrick Palka <ppalka@redhat.com> | 2022-12-15 15:54:31 -0500 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2022-12-15 15:54:31 -0500 |
commit | be124477b38a71ba8ba0b24d859ae764bb44a4eb (patch) | |
tree | 75410ad2cd9d58aa08e91983acef4d5ba11f213c /gcc/cp/pt.cc | |
parent | 38304846d18d6bb14b0fd6c627c5c6d43a814d01 (diff) | |
download | gcc-be124477b38a71ba8ba0b24d859ae764bb44a4eb.zip gcc-be124477b38a71ba8ba0b24d859ae764bb44a4eb.tar.gz gcc-be124477b38a71ba8ba0b24d859ae764bb44a4eb.tar.bz2 |
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<t> 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.
Diffstat (limited to 'gcc/cp/pt.cc')
-rw-r--r-- | gcc/cp/pt.cc | 111 |
1 files changed, 69 insertions, 42 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index efd4eaa..38e3a16 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<T>, 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 <class T> struct S; - template <class T, class U> void f(T, U) { S<U> 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<int, double>, - 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 <class T> struct S; + template <class T, class U> void f(T, U) { S<U> su; } - return r; - } + and supposing that we are instantiating f<int, double>, + 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: |