On Tue, 29 Jun 2021, Jason Merrill wrote:

> 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.

That works nicely.  How does the following look?  Bootstrapped and
regtested on x86_64-pc-linux-gnu.

-- >8 --

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                                   |  7 +++++-
 gcc/testsuite/g++.dg/cpp2a/concepts-access2.C | 13 +++++++++++
 4 files changed, 33 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 d2936c106ba..f8f7616bf2a 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,9 @@ push_access_scope (tree t)
 
   if (DECL_FRIEND_CONTEXT (t))
     push_nested_class (DECL_FRIEND_CONTEXT (t));
+  else if (DECL_IMPLICIT_TYPEDEF_P (t)
+          && CLASS_TYPE_P (TREE_TYPE (t)))
+    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 +263,8 @@ pop_access_scope (tree t)
     current_function_decl = saved_access_scope->pop();
 
   if (DECL_FRIEND_CONTEXT (t)
+      || (DECL_IMPLICIT_TYPEDEF_P (t)
+         && CLASS_TYPE_P (TREE_TYPE (t)))
       || 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" }
-- 
2.32.0.93.g670b81a890

Reply via email to