]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Fix push_access_scope and introduce RAII wrapper for it
authorPatrick Palka <ppalka@redhat.com>
Wed, 30 Jun 2021 17:12:36 +0000 (13:12 -0400)
committerPatrick Palka <ppalka@redhat.com>
Wed, 30 Jun 2021 17:12:36 +0000 (13:12 -0400)
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 make use of this wrapper right away by
replacing the only user of push_nested_class_guard with this new
wrapper, which means we can remove push_nested_class_guard (whose
functionality is basically subsumed by the new wrapper).

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
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp2a/concepts-access2.C [new file with mode: 0644]

index 6df3ca6ce323a53b1cd93d204b6a9ac3f021f8bb..99d3ccc69980b0451f31f4c60d10e4fcb6d534f2 100644 (file)
@@ -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);
     }
 
index 6f713719589bc9fda4c814e3ab2e6fd5dace12f7..58da746000159b56f01e51036e256b9d746220be 100644 (file)
@@ -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);
   }
 };
 
index d2936c106ba2563c473b9055c4e8dab6b2be5261..f8f7616bf2a106f275b323602a94bc6eae91a3d6 100644 (file)
@@ -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 (file)
index 0000000..8ddcad2
--- /dev/null
@@ -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" }