public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-4729] c++: local alias in typename in lambda [PR105518]
@ 2022-12-15 20:54 Patrick Palka
0 siblings, 0 replies; only message in thread
From: Patrick Palka @ 2022-12-15 20:54 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:be124477b38a71ba8ba0b24d859ae764bb44a4eb
commit r13-4729-gbe124477b38a71ba8ba0b24d859ae764bb44a4eb
Author: Patrick Palka <ppalka@redhat.com>
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<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.
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<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:
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<int N>
+struct A {
+ using type = A;
+ static constexpr int value = N;
+};
+
+template<class T>
+void f(T t) {
+ using alias = A<t>;
+ [](int) {
+ typename alias::type a; // { dg-bogus "'t' is not captured" }
+ return a.value;
+ }(0);
+}
+
+template void f(integral_constant);
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-12-15 20:54 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-15 20:54 [gcc r13-4729] c++: local alias in typename in lambda [PR105518] Patrick Palka
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).