[PATCH] c++: excessive instantiation during CTAD [PR101174]
Jason Merrill
jason@redhat.com
Wed Jun 23 19:55:34 GMT 2021
On 6/23/21 2:18 PM, Patrick Palka wrote:
> 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 instead of setting their DECL_CONTEXT
> in build_deduction_guide. We could alternatively make the class
> befriend the guide via DECL_BEFRIENDING_CLASSES, but that'd break
> class-deduction-access3.C below since friendship isn't transitive.
>
> Bootstrapped and regtested on x86_64-pc-linxu-gnu, does this look OK for
> trunk?
>
> 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.
>
> 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 | 11 ++++++----
> .../g++.dg/cpp1z/class-deduction-access3.C | 22 +++++++++++++++++++
> .../g++.dg/cpp1z/class-deduction91.C | 16 ++++++++++++++
> .../23_containers/multiset/cons/deduction.cc | 2 --
> .../23_containers/set/cons/deduction.cc | 2 --
> 5 files changed, 45 insertions(+), 8 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction-access3.C
> create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction91.C
>
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 732fb405adf..5c55507203a 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -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)));
Let's be more specific and actually push into the access scope of the
constructor (DECL_ABSTRACT_ORIGIN) if set.
> 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
> index 00000000000..44b4b5c455f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction-access3.C
> @@ -0,0 +1,22 @@
> +// { dg-do compile { target c++17 } }
> +
> +template<typename T>
> +struct Cont;
> +
> +template<typename T>
> +struct Base
> +{
> +private:
> + using type = T;
> + friend Cont<T>;
> +};
> +
> +template<typename 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
> index 00000000000..f474c8e35ec
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction91.C
> @@ -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);
> diff --git a/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc
> index a4ccc6fa467..8b7a16042a4 100644
> --- a/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc
> +++ b/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc
> @@ -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>{}}),
> diff --git a/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc
> index 0ae4c2a5c5f..14f36b7c05d 100644
> --- a/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc
> +++ b/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc
> @@ -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},
>
More information about the Gcc-patches
mailing list