aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2023-06-11 11:09:16 -0400
committerPatrick Palka <ppalka@redhat.com>2023-07-19 15:07:18 -0400
commit33a84d438883b5d6616048636a5fc47f6dd4ed28 (patch)
tree717678c698dd3a30ca3a8d1a1e362d9bd333ed96
parentf76f411f2cdb62122322e709d503edd2f8e8a530 (diff)
downloadgcc-33a84d438883b5d6616048636a5fc47f6dd4ed28.zip
gcc-33a84d438883b5d6616048636a5fc47f6dd4ed28.tar.gz
gcc-33a84d438883b5d6616048636a5fc47f6dd4ed28.tar.bz2
c++: extend lookup_template_class shortcut [PR110122]
Here when substituting the injected class name A during regeneration of the lambda, we find ourselves in lookup_template_class for A<V> with V=_ZTAXtl3BarEE (i.e. the template parameter object for Foo{}). The call to coerce_template_parms within then undesirably tries to make a copy of this class NTTP argument, which fails because Foo is not copyable. But it seems clear that this testcase shouldn't require copyability of Foo. lookup_template_class has a shortcut for looking up the current class scope, which would avoid the problematic coerce_template_parms call, but the shortcut doesn't trigger because it only considers the innermost class scope which in this case in the lambda type. So this patch fixes this by extending the lookup_template_class shortcut to consider outer class scopes too (and skipping over lambda types since they are never specialized from lookup_template_class). We also need to avoid calling coerce_template_parms when specializing a templated non-template nested class for the first time (such as A::B in the testcase). Coercion should be unnecessary there because the innermost arguments belong to the context and so should have already been coerced. PR c++/110122 gcc/cp/ChangeLog: * pt.cc (lookup_template_class): Extend shortcut for looking up the current class scope to consider outer class scopes too, and use current_nonlambda_class_type instead of current_class_type. Only call coerce_template_parms when specializing a primary template. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/nontype-class57.C: New test. * g++.dg/cpp2a/nontype-class58.C: New test. (cherry picked from commit 682d401a6ba723b2bf98779d056efc8ff2640178)
-rw-r--r--gcc/cp/pt.cc19
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/nontype-class57.C25
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/nontype-class58.C20
3 files changed, 60 insertions, 4 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 9128f15..fa9c29d 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -9926,16 +9926,27 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
template. */
/* Shortcut looking up the current class scope again. */
- if (current_class_type)
- if (tree ti = CLASSTYPE_TEMPLATE_INFO (current_class_type))
+ for (tree cur = current_nonlambda_class_type ();
+ cur != NULL_TREE;
+ cur = get_containing_scope (cur))
+ {
+ if (!CLASS_TYPE_P (cur))
+ continue;
+
+ tree ti = CLASSTYPE_TEMPLATE_INFO (cur);
+ if (!ti || arg_depth > TMPL_ARGS_DEPTH (TI_ARGS (ti)))
+ break;
+
if (gen_tmpl == most_general_template (TI_TEMPLATE (ti))
&& comp_template_args (arglist, TI_ARGS (ti)))
- return current_class_type;
+ return cur;
+ }
/* Calculate the BOUND_ARGS. These will be the args that are
actually tsubst'd into the definition to create the
instantiation. */
- arglist = coerce_template_parms (parmlist, arglist, gen_tmpl, complain);
+ if (PRIMARY_TEMPLATE_P (gen_tmpl))
+ arglist = coerce_template_parms (parmlist, arglist, gen_tmpl, complain);
if (arglist == error_mark_node)
/* We were unable to bind the arguments. */
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class57.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class57.C
new file mode 100644
index 0000000..1520fc5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class57.C
@@ -0,0 +1,25 @@
+// PR c++/110122
+// { dg-do compile { target c++20 } }
+
+struct Foo {
+ Foo() = default;
+ Foo(const Foo&) = delete;
+};
+
+template<Foo V>
+struct A {
+ A() {
+ [] { A a; }();
+ [this] { this; }();
+ }
+
+ struct B {
+ B() {
+ [] { A a; }();
+ [this] { this; }();
+ }
+ };
+};
+
+A<Foo{}> a;
+A<Foo{}>::B b;
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C
new file mode 100644
index 0000000..5bb335c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C
@@ -0,0 +1,20 @@
+// PR c++/110122
+// { dg-do compile { target c++20 } }
+
+struct Foo {
+ Foo() = default;
+ constexpr Foo(const Foo&) { }
+};
+
+struct Bar {
+ Foo _;
+};
+
+template<Bar V>
+struct A {
+ A() {
+ [](auto){ A<V> d; }(0); // { dg-bogus "used before its definition" }
+ };
+};
+
+A<Bar{}> a;