public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r11-8475] c++: access for hidden friend of nested class template [PR100502]
@ 2021-05-28 14:21 Patrick Palka
  0 siblings, 0 replies; only message in thread
From: Patrick Palka @ 2021-05-28 14:21 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:365deb8399262033ac766b924c35d31db3d621ca

commit r11-8475-g365deb8399262033ac766b924c35d31db3d621ca
Author: Patrick Palka <ppalka@redhat.com>
Date:   Wed May 26 16:02:33 2021 -0400

    c++: access for hidden friend of nested class template [PR100502]
    
    Here, during ahead of time access checking for the private member
    EnumeratorRange<T>::end_reached_ in the hidden friend f, we're triggering
    the assert in enforce_access that verifies we're not trying to add a
    access check for a dependent decl onto TI_DEFERRED_ACCESS_CHECKS.
    
    The special thing about this class member access expression is that
    the overall expression is non-dependent (so finish_class_member_access_expr
    doesn't exit early at parse time), and then accessible_p rejects the
    access (so we don't exit early from enforce access either, and end up
    triggering the assert b/c the member itself is dependent).  I think
    we're correct to reject the access because a hidden friend is not a
    member function, so [class.access.nest] doesn't apply, and also a hidden
    friend of a nested class is not a friend of the enclosing class.
    
    To fix this ICE, this patch disables ahead of time access checking
    during the member lookup in finish_class_member_access_expr.  This
    avoids potentially pushing an access check for a dependent member onto
    TI_DEFERRED_ACCESS_CHECKS, and it's safe because we're going to redo the
    same lookup at instantiation time anyway.
    
            PR c++/100502
    
    gcc/cp/ChangeLog:
    
            * typeck.c (finish_class_member_access_expr): Disable ahead
            of time access checking during the member lookup.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/template/access37.C: New test.
            * g++.dg/template/access37a.C: New test.
    
    (cherry picked from commit abe8787a8492013145b275b858f70943522d7226)

Diff:
---
 gcc/cp/typeck.c                           | 10 ++++++++++
 gcc/testsuite/g++.dg/template/access37.C  | 26 ++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/template/access37a.C |  6 ++++++
 3 files changed, 42 insertions(+)

diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 50d0f1e6a62..cce26b89cde 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -3201,9 +3201,19 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
 	{
 	  /* Look up the member.  */
 	  access_failure_info afi;
+	  if (processing_template_decl)
+	    /* Even though this class member access expression is at this
+	       point not dependent, the member itself may be dependent, and
+	       we must not potentially push a access check for a dependent
+	       member onto TI_DEFERRED_ACCESS_CHECKS.  So don't check access
+	       ahead of time here; we're going to redo this member lookup at
+	       instantiation time anyway.  */
+	    push_deferring_access_checks (dk_no_check);
 	  member = lookup_member (access_path, name, /*protect=*/1,
 				  /*want_type=*/false, complain,
 				  &afi);
+	  if (processing_template_decl)
+	    pop_deferring_access_checks ();
 	  afi.maybe_suggest_accessor (TYPE_READONLY (object_type));
 	  if (member == NULL_TREE)
 	    {
diff --git a/gcc/testsuite/g++.dg/template/access37.C b/gcc/testsuite/g++.dg/template/access37.C
new file mode 100644
index 00000000000..5be532c75b0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access37.C
@@ -0,0 +1,26 @@
+// PR c++/100502
+
+template <class T>
+struct EnumeratorRange {
+  struct Iterator {
+    EnumeratorRange range_;
+
+    friend void f(Iterator i) {
+      i.range_.end_reached_; // { dg-error "private" }
+      i.range_.EnumeratorRange::end_reached_; // { dg-error "private" }
+      &i.range_.end_reached_; // { dg-error "private" }
+      &i.range_.EnumeratorRange::end_reached_; // { dg-error "private" }
+    }
+  };
+
+ private:
+  bool end_reached_;
+#if DECLARE_FRIEND
+  friend void f(Iterator);
+#endif
+};
+
+int main() {
+  EnumeratorRange<int>::Iterator i;
+  f(i);
+}
diff --git a/gcc/testsuite/g++.dg/template/access37a.C b/gcc/testsuite/g++.dg/template/access37a.C
new file mode 100644
index 00000000000..4ce1b2718a0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access37a.C
@@ -0,0 +1,6 @@
+// PR c++/100502
+// { dg-additional-options "-DDECLARE_FRIEND -Wno-non-template-friend" }
+
+// Verify that access37.C is accepted if the appropriate friend relation
+// is declared (controlled by the macro DECLARE_FRIEND).
+#include "access37.C"


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-05-28 14:21 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-28 14:21 [gcc r11-8475] c++: access for hidden friend of nested class template [PR100502] Patrick Palka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).