[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