c++: excessive instantiation during CTAD [PR101174]
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.
This commit is contained in:
parent
f72f71c52e
commit
7da4eae3dc
11
gcc/cp/pt.c
11
gcc/cp/pt.c
|
@ -236,6 +236,10 @@ push_access_scope (tree t)
|
||||||
push_nested_class (DECL_FRIEND_CONTEXT (t));
|
push_nested_class (DECL_FRIEND_CONTEXT (t));
|
||||||
else if (DECL_CLASS_SCOPE_P (t))
|
else if (DECL_CLASS_SCOPE_P (t))
|
||||||
push_nested_class (DECL_CONTEXT (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
|
else
|
||||||
push_to_top_level ();
|
push_to_top_level ();
|
||||||
|
|
||||||
|
@ -255,7 +259,9 @@ pop_access_scope (tree t)
|
||||||
if (TREE_CODE (t) == FUNCTION_DECL)
|
if (TREE_CODE (t) == FUNCTION_DECL)
|
||||||
current_function_decl = saved_access_scope->pop();
|
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 ();
|
pop_nested_class ();
|
||||||
else
|
else
|
||||||
pop_from_top_level ();
|
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;
|
DECL_ABSTRACT_ORIGIN (ded_tmpl) = fn_tmpl;
|
||||||
if (ci)
|
if (ci)
|
||||||
set_constraints (ded_tmpl, 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;
|
return ded_tmpl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
@ -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);
|
|
@ -19,11 +19,9 @@ static_assert(std::is_same_v<
|
||||||
decltype(std::multiset{{1, 2, 3}, std::less<int>{}, {}}),
|
decltype(std::multiset{{1, 2, 3}, std::less<int>{}, {}}),
|
||||||
std::multiset<int>>);
|
std::multiset<int>>);
|
||||||
|
|
||||||
/* FIXME: GCC 12 rejects this due to PR c++/101174
|
|
||||||
static_assert(std::is_same_v<
|
static_assert(std::is_same_v<
|
||||||
decltype(std::multiset{{1, 2, 3}, std::less<int>{}}),
|
decltype(std::multiset{{1, 2, 3}, std::less<int>{}}),
|
||||||
std::multiset<int>>);
|
std::multiset<int>>);
|
||||||
*/
|
|
||||||
|
|
||||||
static_assert(std::is_same_v<
|
static_assert(std::is_same_v<
|
||||||
decltype(std::multiset{{1, 2, 3}, SimpleAllocator<int>{}}),
|
decltype(std::multiset{{1, 2, 3}, SimpleAllocator<int>{}}),
|
||||||
|
|
|
@ -20,12 +20,10 @@ static_assert(std::is_same_v<
|
||||||
std::less<int>{}, {}}),
|
std::less<int>{}, {}}),
|
||||||
std::set<int>>);
|
std::set<int>>);
|
||||||
|
|
||||||
/* FIXME: GCC 12 rejects this due to PR c++/101174
|
|
||||||
static_assert(std::is_same_v<
|
static_assert(std::is_same_v<
|
||||||
decltype(std::set{{1, 2, 3},
|
decltype(std::set{{1, 2, 3},
|
||||||
std::less<int>{}}),
|
std::less<int>{}}),
|
||||||
std::set<int>>);
|
std::set<int>>);
|
||||||
*/
|
|
||||||
|
|
||||||
static_assert(std::is_same_v<
|
static_assert(std::is_same_v<
|
||||||
decltype(std::set{{1, 2, 3},
|
decltype(std::set{{1, 2, 3},
|
||||||
|
|
Loading…
Reference in New Issue