public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: access scope during partial spec matching [PR96204]
@ 2021-06-25 15:03 Patrick Palka
  2021-06-25 15:43 ` Patrick Palka
  2021-06-25 15:50 ` Jason Merrill
  0 siblings, 2 replies; 5+ messages in thread
From: Patrick Palka @ 2021-06-25 15:03 UTC (permalink / raw)
  To: gcc-patches

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


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-06-25 20:25 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-25 15:03 [PATCH] c++: access scope during partial spec matching [PR96204] Patrick Palka
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

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