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++: access scope during partial spec matching [PR96204]
Date: Fri, 25 Jun 2021 11:03:52 -0400	[thread overview]
Message-ID: <20210625150352.913072-1-ppalka@redhat.com> (raw)

Here, when determining whether the partial specialization matches the
specialization has_set_attr_method<Child>, we do so from the scope of
where the template-id appears rather than from the scope of the
specialization, and this causes us to select the partial specialization
(since Child::type is accessible from Parent).  When we later
instantiate this partial specialization, we've entered the scope of the
specialization and so substitution into e.g. the DECL_CONTEXT for
'value' yields access errors for Child::type since the friend
declaration no longer applies.

It seems the appropriate access scope from which to perform partial
specialization matching is the specialization itself (similar to how
we check access of base-clauses), which is what this patch implements.

There's implementation divergence however: Clang accepts both testcases
below whereas MSVC and ICC reject both (indicating that Clang performs
partial spec matching from the scope of the specialization and MSVC/ICC
performs it from whatever scope the template-id appears).

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

	PR c++/96204

gcc/cp/ChangeLog:

	* pt.c (instantiate_class_template_1): Enter the scope of the
	type before calling most_specialized_partial_spec.

gcc/testsuite/ChangeLog:

	* g++.dg/template/access40.C: New test.
	* g++.dg/template/access40a.C: New test.
---
 gcc/cp/pt.c                               |  6 ++++-
 gcc/testsuite/g++.dg/template/access40.C  | 30 +++++++++++++++++++++++
 gcc/testsuite/g++.dg/template/access40a.C | 30 +++++++++++++++++++++++
 3 files changed, 65 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/access40.C
 create mode 100644 gcc/testsuite/g++.dg/template/access40a.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f4e0abe5c1e..5107bfbf9d1 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11774,8 +11774,12 @@ instantiate_class_template_1 (tree type)
   deferring_access_check_sentinel acs (dk_no_deferred);
 
   /* Determine what specialization of the original template to
-     instantiate.  */
+     instantiate; do this relative to the scope of the type.  */
+  push_access_scope (TYPE_NAME (type));
+  pushclass (type);
   t = most_specialized_partial_spec (type, tf_warning_or_error);
+  popclass ();
+  pop_access_scope (TYPE_NAME (type));
   if (t == error_mark_node)
     return error_mark_node;
   else if (t)
diff --git a/gcc/testsuite/g++.dg/template/access40.C b/gcc/testsuite/g++.dg/template/access40.C
new file mode 100644
index 00000000000..e0d30779377
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access40.C
@@ -0,0 +1,30 @@
+// PR c++/96204
+
+template<bool> struct bool_constant;
+
+template<class, class = void>
+struct has_type_member {
+  static const bool value = false;
+};
+
+template<class T>
+struct has_type_member<T, typename T::type> {
+  static const bool value = true;
+};
+
+struct Parent;
+
+struct Child {
+private:
+  friend struct Parent;
+  typedef void type;
+};
+
+struct Parent {
+  static void f() {
+    // The partial specialization of has_type_member does not match
+    // despite Child::type being accessible from the current scope.
+    typedef bool_constant<has_type_member<Child>::value> type;
+    typedef bool_constant<false> type;
+  }
+};
diff --git a/gcc/testsuite/g++.dg/template/access40a.C b/gcc/testsuite/g++.dg/template/access40a.C
new file mode 100644
index 00000000000..85138c9e570
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access40a.C
@@ -0,0 +1,30 @@
+// PR c++/96204
+
+template<bool> struct bool_constant;
+
+template<class, class = void>
+struct has_type_member {
+  static const bool value = false;
+};
+
+template<class T>
+struct has_type_member<T, typename T::type> {
+  static const bool value = true;
+};
+
+struct Parent;
+
+struct Child {
+private:
+  friend struct has_type_member<Child>;
+  typedef void type;
+};
+
+struct Parent {
+  static void f() {
+    // The partial specialization matches because Child::type is
+    // accessible from has_type_member<Child>.
+    typedef bool_constant<has_type_member<Child>::value> type;
+    typedef bool_constant<true> type;
+  }
+};
-- 
2.32.0.93.g670b81a890


             reply	other threads:[~2021-06-25 15:03 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-25 15:03 Patrick Palka [this message]
2021-06-25 15:43 ` Patrick Palka
2021-06-25 15:50 ` Jason Merrill
2021-06-25 17:14   ` Patrick Palka
2021-06-25 20:25     ` Jason Merrill

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=20210625150352.913072-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).