diff mbox series

C++ PATCH for c++/61806, SFINAE, access control, and partial specialization.

Message ID CADzB+2mHnfJ725hbHC4TUdknxUehpyC4_8Ybxj3cnh-trdKAbA@mail.gmail.com
State New
Headers show
Series C++ PATCH for c++/61806, SFINAE, access control, and partial specialization. | expand

Commit Message

Jason Merrill June 4, 2018, 3:14 p.m. UTC
Here we were missing SFINAE when choosing a partial specialization
because we requested the instantiation from an access-deferred context
and didn't push into checking context until too late.

Tested x86_64-pc-linux-gnu, applying to trunk.
diff mbox series

Patch

commit 77b60d23c71206b7ac3c9d9817db3787383ea2fd
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 4 16:51:15 2018 +0200

            PR c++/61806 - missed SFINAE with partial specialization.
    
            * cp-tree.h (deferring_access_check_sentinel): Add deferring_kind
            parameter to constructor.
            * pt.c (instantiate_class_template_1): Enable access checking
            before call to most_specialized_partial_spec.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6a97abbe4e3..f2016f173bd 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6807,9 +6807,9 @@  extern bool perform_or_defer_access_check	(tree, tree, tree,
 
 struct deferring_access_check_sentinel
 {
-  deferring_access_check_sentinel ()
+  deferring_access_check_sentinel (enum deferring_kind kind = dk_deferred)
   {
-    push_deferring_access_checks (dk_deferred);
+    push_deferring_access_checks (kind);
   }
   ~deferring_access_check_sentinel ()
   {
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d3915ddcddf..aad68a32643 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10850,6 +10850,10 @@  instantiate_class_template_1 (tree type)
   /* Mark the type as in the process of being defined.  */
   TYPE_BEING_DEFINED (type) = 1;
 
+  /* We may be in the middle of deferred access check.  Disable
+     it now.  */
+  deferring_access_check_sentinel acs (dk_no_deferred);
+
   /* Determine what specialization of the original template to
      instantiate.  */
   t = most_specialized_partial_spec (type, tf_warning_or_error);
@@ -10889,10 +10893,6 @@  instantiate_class_template_1 (tree type)
   if (! push_tinst_level (type))
     return type;
 
-  /* We may be in the middle of deferred access check.  Disable
-     it now.  */
-  push_deferring_access_checks (dk_no_deferred);
-
   int saved_unevaluated_operand = cp_unevaluated_operand;
   int saved_inhibit_evaluation_warnings = c_inhibit_evaluation_warnings;
 
@@ -11373,7 +11373,6 @@  instantiate_class_template_1 (tree type)
   maximum_field_alignment = saved_maximum_field_alignment;
   if (!fn_context)
     pop_from_top_level ();
-  pop_deferring_access_checks ();
   pop_tinst_level ();
 
   /* The vtable for a template class can be emitted in any translation
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae63.C b/gcc/testsuite/g++.dg/cpp0x/sfinae63.C
new file mode 100644
index 00000000000..7ad38497c0b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae63.C
@@ -0,0 +1,39 @@ 
+// PR c++/61806
+// { dg-do compile { target c++11 } }
+
+struct true_type 
+{
+  static const bool value = true;
+};
+
+struct false_type 
+{
+  static const bool value = false;
+};
+
+template<class T>
+T&& declval();
+
+template<typename> struct check { typedef void type; };
+
+template<typename T, typename Enable = void>
+struct has_public_f : false_type {};
+
+template<typename T>
+struct has_public_f<
+    T,
+    typename check<
+        decltype(
+            declval<T&>().f()
+        )
+    >::type
+> : true_type {};
+
+
+struct Spub  { public: void f(); };
+struct Spriv { private: void f(); };
+
+static_assert( has_public_f<Spub>::value, "Ouch");
+static_assert(!has_public_f<Spriv>::value, "Ouch");
+
+int main() {}