aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/pt.cc
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2022-12-15 15:54:31 -0500
committerPatrick Palka <ppalka@redhat.com>2022-12-15 15:54:31 -0500
commitbe124477b38a71ba8ba0b24d859ae764bb44a4eb (patch)
tree75410ad2cd9d58aa08e91983acef4d5ba11f213c /gcc/cp/pt.cc
parent38304846d18d6bb14b0fd6c627c5c6d43a814d01 (diff)
downloadgcc-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.cc111
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: