]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: access for hidden friend of nested class template [PR100502]
authorPatrick Palka <ppalka@redhat.com>
Wed, 26 May 2021 20:02:33 +0000 (16:02 -0400)
committerPatrick Palka <ppalka@redhat.com>
Fri, 28 May 2021 13:46:49 +0000 (09:46 -0400)
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)

gcc/cp/typeck.c
gcc/testsuite/g++.dg/template/access37.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/access37a.C [new file with mode: 0644]

index 50d0f1e6a62aa402c5f16626ec435073c753b009..cce26b89cdec839f7bc17a5f0404a1c9f6ef0625 100644 (file)
@@ -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 (file)
index 0000000..5be532c
--- /dev/null
@@ -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 (file)
index 0000000..4ce1b27
--- /dev/null
@@ -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"