[PATCH 1/2] c++: Fix push_access_scope and introduce RAII wrapper for it

Jason Merrill jason@redhat.com
Tue Jun 29 18:45:20 GMT 2021


On 6/29/21 1:57 PM, Patrick Palka wrote:
> When push_access_scope is passed a TYPE_DECL for a class type (which
> can happen during e.g. satisfaction), we undesirably push only the
> enclosing context of the class instead of the class itself.  This causes
> us to mishandle e.g. testcase below due to us not entering the scope of
> A before checking its constraints.
> 
> This patch adjusts push_access_scope accordingly, and introduces an
> RAII wrapper for it.  We also make use of this wrapper right away by
> replacing the only use of push_nested_class_guard with this new wrapper,
> which means we can remove this old wrapper (whose functionality is
> basically subsumed by the new wrapper).
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
> gcc/cp/ChangeLog:
> 
> 	* constraint.cc (get_normalized_constraints_from_decl): Use
> 	push_access_scope_guard instead of push_nested_class_guard.
> 	* cp-tree.h (struct push_nested_class_guard): Replace with ...
> 	(struct push_access_scope_guard): ... this.
> 	* pt.c (push_access_scope): When the argument corresponds to
> 	a class type, push the class instead of its context.
> 	(pop_access_scope): Adjust accordingly.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp2a/concepts-access2.C: New test.
> ---
>   gcc/cp/constraint.cc                          |  7 +-----
>   gcc/cp/cp-tree.h                              | 23 +++++++++++--------
>   gcc/cp/pt.c                                   |  9 +++++++-
>   gcc/testsuite/g++.dg/cpp2a/concepts-access2.C | 13 +++++++++++
>   4 files changed, 35 insertions(+), 17 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-access2.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 6df3ca6ce32..99d3ccc6998 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -926,12 +926,7 @@ get_normalized_constraints_from_decl (tree d, bool diag = false)
>     tree norm = NULL_TREE;
>     if (tree ci = get_constraints (decl))
>       {
> -      push_nested_class_guard pncs (DECL_CONTEXT (d));
> -
> -      temp_override<tree> ovr (current_function_decl);
> -      if (TREE_CODE (decl) == FUNCTION_DECL)
> -	current_function_decl = decl;
> -
> +      push_access_scope_guard pas (decl);
>         norm = get_normalized_constraints_from_info (ci, tmpl, diag);
>       }
>   
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 6f713719589..58da7460001 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -8463,21 +8463,24 @@ is_constrained_auto (const_tree t)
>     return is_auto (t) && PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t);
>   }
>   
> -/* RAII class to push/pop class scope T; if T is not a class, do nothing.  */
> +/* RAII class to push/pop the access scope for T.  */
>   
> -struct push_nested_class_guard
> +struct push_access_scope_guard
>   {
> -  bool push;
> -  push_nested_class_guard (tree t)
> -    : push (t && CLASS_TYPE_P (t))
> +  tree decl;
> +  push_access_scope_guard (tree t)
> +    : decl (t)
>     {
> -    if (push)
> -      push_nested_class (t);
> +    if (VAR_OR_FUNCTION_DECL_P (decl)
> +	|| TREE_CODE (decl) == TYPE_DECL)
> +      push_access_scope (decl);
> +    else
> +      decl = NULL_TREE;
>     }
> -  ~push_nested_class_guard ()
> +  ~push_access_scope_guard ()
>     {
> -    if (push)
> -      pop_nested_class ();
> +    if (decl)
> +      pop_access_scope (decl);
>     }
>   };
>   
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index f2039e09cd7..bd8b17ca047 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -224,7 +224,7 @@ static void instantiate_body (tree pattern, tree args, tree d, bool nested);
>   /* Make the current scope suitable for access checking when we are
>      processing T.  T can be FUNCTION_DECL for instantiated function
>      template, VAR_DECL for static member variable, or TYPE_DECL for
> -   alias template (needed by instantiate_decl).  */
> +   for a class or alias template (needed by instantiate_decl).  */
>   
>   void
>   push_access_scope (tree t)
> @@ -234,6 +234,10 @@ push_access_scope (tree t)
>   
>     if (DECL_FRIEND_CONTEXT (t))
>       push_nested_class (DECL_FRIEND_CONTEXT (t));
> +  else if (TREE_CODE (t) == TYPE_DECL
> +	   && CLASS_TYPE_P (TREE_TYPE (t))
> +	   && DECL_ORIGINAL_TYPE (t) == NULL_TREE)

I suspect DECL_IMPLICIT_TYPEDEF_P is a better test for this case.

> +    push_nested_class (TREE_TYPE (t));
>     else if (DECL_CLASS_SCOPE_P (t))
>       push_nested_class (DECL_CONTEXT (t));
>     else if (deduction_guide_p (t) && DECL_ARTIFICIAL (t))
> @@ -260,6 +264,9 @@ pop_access_scope (tree t)
>       current_function_decl = saved_access_scope->pop();
>   
>     if (DECL_FRIEND_CONTEXT (t)
> +      || (TREE_CODE (t) == TYPE_DECL
> +	  && CLASS_TYPE_P (TREE_TYPE (t))
> +	  && DECL_ORIGINAL_TYPE (t) == NULL_TREE)
>         || DECL_CLASS_SCOPE_P (t)
>         || (deduction_guide_p (t) && DECL_ARTIFICIAL (t)))
>       pop_nested_class ();
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-access2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-access2.C
> new file mode 100644
> index 00000000000..8ddcad236e3
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-access2.C
> @@ -0,0 +1,13 @@
> +// { dg-do compile { target concepts } }
> +
> +template<class T> requires T::value struct A { };
> +template<class T> requires T::value struct B { }; // { dg-error "private" }
> +
> +struct S {
> +private:
> +  static constexpr bool value = true;
> +  template<class T> requires T::value friend struct A;
> +};
> +
> +A<S> x;
> +B<S> y; // { dg-error "constraint" }
> 



More information about the Gcc-patches mailing list