Patchwork C++ PATCH to fix incorrect access error with protected constexpr constructor

login
register
mail settings
Submitter Jason Merrill
Date Nov. 4, 2010, 5:04 p.m.
Message ID <4CD2E7BA.1050300@redhat.com>
Download mbox | patch
Permalink /patch/70143/
State New
Headers show

Comments

Jason Merrill - Nov. 4, 2010, 5:04 p.m.
Jonathan asked in private mail whether this testcase should be accepted; 
it should, and this patch fixes it.

Tested x86_64-pc-linux-gnu, applied to trunk.
commit f0a7671df07bfc59c4901dbbcdf0e837a952130c
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Nov 4 11:14:18 2010 -0400

    	* semantics.c (speculative_access_check): New.
    	* cp-tree.h: Declare it.
    	* call.c (build_over_call): Use it.
    	* class.c (type_has_constexpr_default_constructor): Use locate_ctor.
    	* method.c (locate_ctor): Use push/pop_deferring_access_checks.

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 4507f3d..eb7247d 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5823,15 +5823,9 @@  build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 	access_fn = fn;
       if (flags & LOOKUP_SPECULATIVE)
 	{
-	  /* If we're checking for implicit delete, we don't want access
-	     control errors.  */
-	  if (!accessible_p (cand->access_path, access_fn, true))
-	    {
-	      /* Unless we're under maybe_explain_implicit_delete.  */
-	      if (flags & LOOKUP_COMPLAIN)
-		enforce_access (cand->access_path, access_fn, fn);
-	      return error_mark_node;
-	    }
+	  if (!speculative_access_check (cand->access_path, access_fn, fn,
+					 !!(flags & LOOKUP_COMPLAIN)))
+	    return error_mark_node;
 	}
       else
 	perform_or_defer_access_check (cand->access_path, access_fn, fn);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index ded0a03..435fa71 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4349,7 +4349,7 @@  type_has_constexpr_default_constructor (tree t)
     return false;
   if (CLASSTYPE_LAZY_DEFAULT_CTOR (t))
     return synthesized_default_constructor_is_constexpr (t);
-  fns = get_default_ctor (t);
+  fns = locate_ctor (t);
   return (fns && DECL_DECLARED_CONSTEXPR_P (fns));
 }
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index fc4772d..8f52278 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5192,6 +5192,7 @@  extern void pop_to_parent_deferring_access_checks (void);
 extern void perform_access_checks		(VEC (deferred_access_check,gc)*);
 extern void perform_deferred_access_checks	(void);
 extern void perform_or_defer_access_check	(tree, tree, tree);
+extern bool speculative_access_check		(tree, tree, tree, bool);
 extern int stmts_are_full_exprs_p		(void);
 extern void init_cp_semantics			(void);
 extern tree do_poplevel				(tree);
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index ca5964e..c1d30d4 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -849,8 +849,12 @@  get_dtor (tree type)
 tree
 locate_ctor (tree type)
 {
-  tree fn = locate_fn_flags (type, complete_ctor_identifier, NULL_TREE,
-			     LOOKUP_SPECULATIVE, tf_none);
+  tree fn;
+
+  push_deferring_access_checks (dk_no_check);
+  fn = locate_fn_flags (type, complete_ctor_identifier, NULL_TREE,
+			LOOKUP_SPECULATIVE, tf_none);
+  pop_deferring_access_checks ();
   if (fn == error_mark_node)
     return NULL_TREE;
   return fn;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 9061a89..3d62cd1 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -337,6 +337,30 @@  perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl)
   new_access->diag_decl = diag_decl;
 }
 
+/* Used by build_over_call in LOOKUP_SPECULATIVE mode: return whether DECL
+   is accessible in BINFO, and possibly complain if not.  If we're not
+   checking access, everything is accessible.  */
+
+bool
+speculative_access_check (tree binfo, tree decl, tree diag_decl,
+			  bool complain)
+{
+  if (deferred_access_no_check)
+    return true;
+
+  /* If we're checking for implicit delete, we don't want access
+     control errors.  */
+  if (!accessible_p (binfo, decl, true))
+    {
+      /* Unless we're under maybe_explain_implicit_delete.  */
+      if (complain)
+	enforce_access (binfo, decl, diag_decl);
+      return false;
+    }
+
+  return true;
+}
+
 /* Returns nonzero if the current statement is a full expression,
    i.e. temporaries created during that statement should be destroyed
    at the end of the statement.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-access.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-access.C
new file mode 100644
index 0000000..ee5fc98
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-access.C
@@ -0,0 +1,14 @@ 
+// { dg-options -std=c++0x }
+
+class base
+{
+protected:
+  constexpr base() { }
+};
+
+struct A : base { };
+
+int main()
+{
+  A a;
+}