aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2021-05-26 16:02:33 -0400
committerPatrick Palka <ppalka@redhat.com>2021-05-26 16:02:33 -0400
commitabe8787a8492013145b275b858f70943522d7226 (patch)
tree80d38eeb8404bab663d93960aff4c75be5711640 /gcc
parenta42220f0164eeb11b5e1ab87ce5b8f448141ba60 (diff)
downloadgcc-abe8787a8492013145b275b858f70943522d7226.zip
gcc-abe8787a8492013145b275b858f70943522d7226.tar.gz
gcc-abe8787a8492013145b275b858f70943522d7226.tar.bz2
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/typeck.c10
-rw-r--r--gcc/testsuite/g++.dg/template/access37.C26
-rw-r--r--gcc/testsuite/g++.dg/template/access37a.C6
3 files changed, 42 insertions, 0 deletions
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 703ddd3..3df4117 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 0000000..5be532c
--- /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 0000000..4ce1b27
--- /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"