]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: excessive instantiation during CTAD [PR101174]
authorPatrick Palka <ppalka@redhat.com>
Wed, 23 Jun 2021 21:23:39 +0000 (17:23 -0400)
committerPatrick Palka <ppalka@redhat.com>
Wed, 23 Jun 2021 21:23:39 +0000 (17:23 -0400)
We set DECL_CONTEXT on implicitly generated deduction guides so that
their access is consistent with that of the constructor.  But this
apparently leads to excessive instantiation in some cases, ultimately
because instantiation of a deduction guide should be independent of
instantiation of the resulting class specialization, but setting the
DECL_CONTEXT of the former to the latter breaks this independence.

To fix this, this patch makes push_access_scope handle artificial
deduction guides specifically rather than setting their DECL_CONTEXT
in build_deduction_guide.  We could alternatively make the class
befriend the guide via DECL_BEFRIENDING_CLASSES, but that wouldn't
be a complete fix and would break class-deduction-access3.C below
since friendship isn't transitive.

PR c++/101174

gcc/cp/ChangeLog:

* pt.c (push_access_scope): For artificial deduction guides,
set the access scope to that of the constructor.
(pop_access_scope): Likewise.
(build_deduction_guide): Don't set DECL_CONTEXT on the guide.

libstdc++-v3/ChangeLog:

* testsuite/23_containers/multiset/cons/deduction.cc:
Uncomment CTAD example that was rejected by this bug.
* testsuite/23_containers/set/cons/deduction.cc: Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction-access3.C: New test.
* g++.dg/cpp1z/class-deduction91.C: New test.

gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp1z/class-deduction-access3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction91.C [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc
libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc

index 732fb405adf44171ff5c206f3d56e3fca55fdf1e..5c55507203a3fdccb6a8cc971683d7912050f20c 100644 (file)
@@ -236,6 +236,10 @@ push_access_scope (tree t)
     push_nested_class (DECL_FRIEND_CONTEXT (t));
   else if (DECL_CLASS_SCOPE_P (t))
     push_nested_class (DECL_CONTEXT (t));
+  else if (deduction_guide_p (t) && DECL_ARTIFICIAL (t))
+    /* An artificial deduction guide should have the same access as
+       the constructor.  */
+    push_nested_class (TREE_TYPE (TREE_TYPE (t)));
   else
     push_to_top_level ();
 
@@ -255,7 +259,9 @@ pop_access_scope (tree t)
   if (TREE_CODE (t) == FUNCTION_DECL)
     current_function_decl = saved_access_scope->pop();
 
-  if (DECL_FRIEND_CONTEXT (t) || DECL_CLASS_SCOPE_P (t))
+  if (DECL_FRIEND_CONTEXT (t)
+      || DECL_CLASS_SCOPE_P (t)
+      || (deduction_guide_p (t) && DECL_ARTIFICIAL (t)))
     pop_nested_class ();
   else
     pop_from_top_level ();
@@ -28804,9 +28810,6 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com
     DECL_ABSTRACT_ORIGIN (ded_tmpl) = fn_tmpl;
   if (ci)
     set_constraints (ded_tmpl, ci);
-  /* The artificial deduction guide should have same access as the
-     constructor.  */
-  DECL_CONTEXT (ded_fn) = type;
 
   return ded_tmpl;
 }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction-access3.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction-access3.C
new file mode 100644 (file)
index 0000000..9df9480
--- /dev/null
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++17 } }
+
+template<class>
+struct Cont;
+
+template<class T>
+class Base
+{
+  using type = T;
+  friend Cont<T>;
+};
+
+template<class T>
+struct Cont
+{
+  using argument_type = typename Base<T>::type;
+  Cont(T, argument_type);
+};
+
+Cont c(1, 1);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction91.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction91.C
new file mode 100644 (file)
index 0000000..f474c8e
--- /dev/null
@@ -0,0 +1,16 @@
+// PR c++/101174
+// { dg-do compile { target c++17 } }
+
+struct S { using type = int; };
+
+template<class T = int, class U = S>
+struct multiset {
+  using type = typename U::type;
+  multiset(T);
+  multiset(U);
+};
+
+template<class T>
+multiset(T) -> multiset<T>;
+
+multiset c(42);
index a4ccc6fa467a7b2c12b7a8e4a2f6a1de7b0c627b..8b7a16042a4cc75b8801446bf9dd89f6de9a199a 100644 (file)
@@ -19,11 +19,9 @@ static_assert(std::is_same_v<
              decltype(std::multiset{{1, 2, 3}, std::less<int>{}, {}}),
              std::multiset<int>>);
 
-/* FIXME: GCC 12 rejects this due to PR c++/101174
 static_assert(std::is_same_v<
              decltype(std::multiset{{1, 2, 3}, std::less<int>{}}),
              std::multiset<int>>);
-*/
 
 static_assert(std::is_same_v<
              decltype(std::multiset{{1, 2, 3}, SimpleAllocator<int>{}}),
index 0ae4c2a5c5ff7fab7d6dc6df834e2ac326d2a770..14f36b7c05dd2583f5f44668dda0fbbbe34f0948 100644 (file)
@@ -20,12 +20,10 @@ static_assert(std::is_same_v<
                    std::less<int>{}, {}}),
              std::set<int>>);
 
-/* FIXME: GCC 12 rejects this due to PR c++/101174
 static_assert(std::is_same_v<
              decltype(std::set{{1, 2, 3},
                    std::less<int>{}}),
              std::set<int>>);
-*/
 
 static_assert(std::is_same_v<
              decltype(std::set{{1, 2, 3},