[PATCH] c++: access scope during partial spec matching [PR96204]

Patrick Palka ppalka@redhat.com
Fri Jun 25 15:03:52 GMT 2021


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



More information about the Gcc-patches mailing list