public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Patrick Palka <ppalka@redhat.com>
To: gcc-patches@gcc.gnu.org
Subject: [PATCH] c++: Fix access checking of scoped non-static member [PR98515]
Date: Wed,  6 Jan 2021 13:19:32 -0500	[thread overview]
Message-ID: <20210106181932.1393432-1-ppalka@redhat.com> (raw)

In the first testcase below, we incorrectly reject the use of the
protected non-static member A::var0 from C<int>::g() because
check_accessibility_of_qualified_id, at template parse time, determines
that the access doesn't go through 'this'.  (This happens because the
dependent base B<T> of C<T> doesn't have a binfo object, so it appears
to DERIVED_FROM_P that A is not an indirect base of C<T>.)  From there
we create the corresponding deferred access check, which we then
perform at instantiation time and which (unsurprisingly) fails.

The problem ultimately seems to be that we can't, in general, know
whether a use of a scoped non-static member goes through 'this' until
instantiation time, as the second testcase below demonstrates.  So this
patch makes check_accessibility_of_qualified_id punt in this situation.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK to
commit?

gcc/cp/ChangeLog:

	PR c++/98515
	* semantics.c (check_accessibility_of_qualified_id): Punt if
	we're checking the access of a scoped non-static member at
	class template parse time.

gcc/testsuite/ChangeLog:

	PR c++/98515
	* g++.dg/template/access32.C: New test.
	* g++.dg/template/access33.C: New test.
---
 gcc/cp/semantics.c                       | 20 +++++++++++++++-----
 gcc/testsuite/g++.dg/template/access32.C |  8 ++++++++
 gcc/testsuite/g++.dg/template/access33.C |  9 +++++++++
 3 files changed, 32 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/access32.C
 create mode 100644 gcc/testsuite/g++.dg/template/access33.C

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index b448efe024a..f52b2e4d1e7 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2107,14 +2107,24 @@ check_accessibility_of_qualified_id (tree decl,
       /* If the reference is to a non-static member of the
 	 current class, treat it as if it were referenced through
 	 `this'.  */
-      tree ct;
       if (DECL_NONSTATIC_MEMBER_P (decl)
-	  && current_class_ptr
-	  && DERIVED_FROM_P (scope, ct = current_nonlambda_class_type ()))
-	qualifying_type = ct;
+	  && current_class_ptr)
+	{
+	  if (dependent_type_p (TREE_TYPE (current_class_ptr)))
+	  /* In general we can't know whether this access goes through `this'
+	     until instantiation of the current class.  Punt now, or else
+	     we might create a deferred access check that's relative to the
+	     wrong class.  We'll check this access again after substitution,
+	     e.g. from tsubst_qualified_id.  */
+	    return true;
+
+	  if (tree current = current_nonlambda_class_type ())
+	    if (DERIVED_FROM_P (scope, current))
+	      qualifying_type = current;
+	}
       /* Otherwise, use the type indicated by the
 	 nested-name-specifier.  */
-      else
+      if (!qualifying_type)
 	qualifying_type = nested_name_specifier;
     }
   else
diff --git a/gcc/testsuite/g++.dg/template/access32.C b/gcc/testsuite/g++.dg/template/access32.C
new file mode 100644
index 00000000000..08faa9f0f97
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access32.C
@@ -0,0 +1,8 @@
+// PR c++/98515
+// { dg-do compile }
+
+struct A { protected: int var0; };
+template <class> struct B : public A { };
+template <class T> struct C : public B<T> { void g(); };
+template <class T> void C<T>::g() { A::var0++; }
+template class C<int>;
diff --git a/gcc/testsuite/g++.dg/template/access33.C b/gcc/testsuite/g++.dg/template/access33.C
new file mode 100644
index 00000000000..9fb9b9a1236
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access33.C
@@ -0,0 +1,9 @@
+// PR c++/98515
+// { dg-do compile }
+
+struct A { protected: int var0; };
+template <class> struct B : public A { };
+template <class T> struct C : public B<T> { void g(); };
+template <class T> void C<T>::g() { A::var0++; } // { dg-error "protected|invalid" }
+template <> struct B<char> { };
+template class C<char>;
-- 
2.30.0


             reply	other threads:[~2021-01-06 18:19 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-06 18:19 Patrick Palka [this message]
2021-01-07 21:37 ` Jason Merrill
2021-01-07 22:47   ` Patrick Palka
2021-01-08  1:12     ` Jason Merrill
2021-01-08 15:39       ` Patrick Palka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210106181932.1393432-1-ppalka@redhat.com \
    --to=ppalka@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).