On 07/12/2012 07:06 PM, Jason Merrill wrote:
I notice that your patch changes the behavior of C++98/03 mode as well,
which seems wrong to me; I think this is a big enough change that we
should limit it to C++11 mode.

...except that I can't figure out what the semantics before this DR were really supposed to be; G++, EDG and Clang all handle this stuff differently. After poking at it for a while I think the only sensible thing is to have C++03 work the same as C++11. I've done that, and I'm going to check in the full patch.

The first attachment is the full patch; the second is the changes relative to your earlier patch. I changed tf_error to tf_warning_or_error, went back to treating C++03 and C++11 the same, made the FNDECL_RECHECK_ACCESS_P change I mentioned, and streamlined LOOKUP_SPECULATIVE handling.

The third attachment is to fix another problem with my earlier DR 1402 patch. I'm applying this one to 4.7 as well.

Finally, the fourth attachment is to remove the substitution checking from instantiate_decl, as it seems to be redundant.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 32570a0651e12c51bdc6a976b2f981792ea8e4c8
Author: Jason Merrill <ja...@redhat.com>
Date:   Tue Jul 17 14:10:31 2012 -0400

    	DR 1170
    	PR c++/51213
    	* semantics.c (perform_access_checks): Add complain parm, return bool.
    	(perform_deferred_access_checks): Likewise.
    	(perform_or_defer_access_check): Likewise.
    	(speculative_access_check): Remove.
    	* call.c (enforce_access): Add complain parm, return bool.
    	* decl.c, friend.c, class.c, init.c, parser.c: Adjust callers.
    	* search.c: Adjust callers.
    	* cp-tree.h (TINFO_RECHECK_ACCESS_P): New macro.
    	(FNDECL_RECHECK_ACCESS_P): New macro.
    	* method.c (synthesized_method_walk): Stop deferring access checks.
    	* pt.c (recheck_decl_substitution): New.
    	(instantiate_template_1): Set and check FNDECL_RECHECK_ACCESS_P.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 72394f4..5b3245f 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5515,7 +5515,8 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
       /* If the FN is a member function, make sure that it is
 	 accessible.  */
       if (BASELINK_P (fns))
-	perform_or_defer_access_check (BASELINK_BINFO (fns), fn, fn);
+	perform_or_defer_access_check (BASELINK_BINFO (fns), fn, fn,
+				       complain);
 
       /* Core issue 901: It's ok to new a type with deleted delete.  */
       if (DECL_DELETED_FN (fn) && alloc_fn)
@@ -5573,19 +5574,23 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
    the declaration to use in the error diagnostic.  */
 
 bool
-enforce_access (tree basetype_path, tree decl, tree diag_decl)
+enforce_access (tree basetype_path, tree decl, tree diag_decl,
+		tsubst_flags_t complain)
 {
   gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
 
   if (!accessible_p (basetype_path, decl, true))
     {
-      if (TREE_PRIVATE (decl))
-	error ("%q+#D is private", diag_decl);
-      else if (TREE_PROTECTED (decl))
-	error ("%q+#D is protected", diag_decl);
-      else
-	error ("%q+#D is inaccessible", diag_decl);
-      error ("within this context");
+      if (complain & tf_error)
+	{
+	  if (TREE_PRIVATE (decl))
+	    error ("%q+#D is private", diag_decl);
+	  else if (TREE_PROTECTED (decl))
+	    error ("%q+#D is protected", diag_decl);
+	  else
+	    error ("%q+#D is inaccessible", diag_decl);
+	  error ("within this context");
+	}
       return false;
     }
 
@@ -6510,14 +6515,9 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 	access_fn = DECL_TI_TEMPLATE (fn);
       else
 	access_fn = fn;
-      if (flags & LOOKUP_SPECULATIVE)
-	{
-	  if (!speculative_access_check (cand->access_path, access_fn, fn,
-					 complain & tf_error))
-	    return error_mark_node;
-	}
-      else
-	perform_or_defer_access_check (cand->access_path, access_fn, fn);
+      if (!perform_or_defer_access_check (cand->access_path, access_fn,
+					  fn, complain))
+	return error_mark_node;
     }
 
   /* If we're checking for implicit delete, don't bother with argument
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 82c28fa..96a7420 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1189,7 +1189,8 @@ alter_access (tree t, tree fdecl, tree access)
     }
   else
     {
-      perform_or_defer_access_check (TYPE_BINFO (t), fdecl, fdecl);
+      perform_or_defer_access_check (TYPE_BINFO (t), fdecl, fdecl,
+				     tf_warning_or_error);
       DECL_ACCESS (fdecl) = tree_cons (t, access, DECL_ACCESS (fdecl));
       return 1;
     }
@@ -7147,7 +7148,8 @@ resolve_address_of_overloaded_function (tree target_type,
       && DECL_FUNCTION_MEMBER_P (fn))
     {
       gcc_assert (access_path);
-      perform_or_defer_access_check (access_path, fn, fn);
+      perform_or_defer_access_check (access_path, fn, fn,
+				     tf_warning_or_error);
     }
 
   if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type))
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 59104e7..f1a4b32 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -78,6 +78,7 @@ c-common.h, not after.
       CONVERT_EXPR_VBASE_PATH (in CONVERT_EXPR)
       OVL_ARG_DEPENDENT (in OVERLOAD)
       PACK_EXPANSION_LOCAL_P (in *_PACK_EXPANSION)
+      TINFO_RECHECK_ACCESS_P (in TEMPLATE_INFO)
    1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
       TI_PENDING_TEMPLATE_FLAG.
       TEMPLATE_PARMS_FOR_INLINE.
@@ -725,6 +726,14 @@ typedef struct qualified_typedef_usage_s qualified_typedef_usage_t;
 DEF_VEC_O (qualified_typedef_usage_t);
 DEF_VEC_ALLOC_O (qualified_typedef_usage_t,gc);
 
+/* Non-zero if this template specialization has access violations that
+   should be rechecked when the function is instantiated outside argument
+   deduction.  */
+#define TINFO_RECHECK_ACCESS_P(NODE) \
+  (TREE_LANG_FLAG_0 (TEMPLATE_INFO_CHECK (NODE)))
+#define FNDECL_RECHECK_ACCESS_P(NODE) \
+  (TINFO_RECHECK_ACCESS_P (DECL_TEMPLATE_INFO (NODE)))
+
 struct GTY(()) tree_template_info {
   struct tree_common common;
   VEC(qualified_typedef_usage_t,gc) *typedefs_needing_access_checking;
@@ -4424,9 +4433,7 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
    Used by sythesized_method_walk to determine which functions will
    be called to initialize subobjects, in order to determine exception
    specification and possible implicit delete.
-   This is kind of a hack, but since access control doesn't respect SFINAE
-   we can't just use tf_none to avoid access control errors, we need
-   another mechanism.  Exiting early also avoids problems with trying
+   This is kind of a hack, but exiting early avoids problems with trying
    to perform argument conversions when the class isn't complete yet.  */
 #define LOOKUP_SPECULATIVE (LOOKUP_LIST_ONLY << 1)
 /* Used by calls from defaulted functions to limit the overload set to avoid
@@ -4901,7 +4908,8 @@ extern bool can_convert_arg			(tree, tree, tree, int,
 						 tsubst_flags_t);
 extern bool can_convert_arg_bad			(tree, tree, tree, int,
 						 tsubst_flags_t);
-extern bool enforce_access			(tree, tree, tree);
+extern bool enforce_access			(tree, tree, tree,
+						 tsubst_flags_t);
 extern void push_defarg_context			(tree);
 extern void pop_defarg_context			(void);
 extern tree convert_default_arg			(tree, tree, tree, int,
@@ -5497,10 +5505,11 @@ extern void stop_deferring_access_checks	(void);
 extern void pop_deferring_access_checks		(void);
 extern VEC (deferred_access_check,gc)* get_deferred_access_checks		(void);
 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 bool perform_access_checks (VEC (deferred_access_check,gc)*,
+				   tsubst_flags_t);
+extern bool perform_deferred_access_checks	(tsubst_flags_t);
+extern bool perform_or_defer_access_check	(tree, tree, tree,
+						 tsubst_flags_t);
 extern int stmts_are_full_exprs_p		(void);
 extern void init_cp_semantics			(void);
 extern tree do_poplevel				(tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 8a3163a..605058d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -3306,9 +3306,9 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
 	       context, name, t);
       return error_mark_node;
     }
-  
-  if (complain & tf_error)
-    perform_or_defer_access_check (TYPE_BINFO (context), t, t);
+
+  if (!perform_or_defer_access_check (TYPE_BINFO (context), t, t, complain))
+    return error_mark_node;
 
   /* If we are currently parsing a template and if T is a typedef accessed
      through CONTEXT then we need to remember and check access of T at
@@ -3378,8 +3378,9 @@ make_unbound_class_template (tree context, tree name, tree parm_list,
 	  return error_mark_node;
 	}
 
-      if (complain & tf_error)
-	perform_or_defer_access_check (TYPE_BINFO (context), tmpl, tmpl);
+      if (!perform_or_defer_access_check (TYPE_BINFO (context), tmpl, tmpl,
+					  complain))
+	return error_mark_node;
 
       return tmpl;
     }
@@ -6647,7 +6648,8 @@ register_dtor_fn (tree decl)
       gcc_assert (idx >= 0);
       cleanup = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), idx);
       /* Make sure it is accessible.  */
-      perform_or_defer_access_check (TYPE_BINFO (type), cleanup, cleanup);
+      perform_or_defer_access_check (TYPE_BINFO (type), cleanup, cleanup,
+				     tf_warning_or_error);
     }
   else
     {
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index e68af3d..d0cbaed 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -166,7 +166,8 @@ add_friend (tree type, tree decl, bool complain)
 
   ctx = DECL_CONTEXT (decl);
   if (ctx && CLASS_TYPE_P (ctx) && !uses_template_parms (ctx))
-    perform_or_defer_access_check (TYPE_BINFO (ctx), decl, decl);
+    perform_or_defer_access_check (TYPE_BINFO (ctx), decl, decl,
+				   tf_warning_or_error);
 
   maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1);
 
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 5a81643..a725a0c 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1876,9 +1876,11 @@ build_offset_ref (tree type, tree member, bool address_p)
 	       (or any class derived from that class).  */
 	  if (address_p && DECL_P (t)
 	      && DECL_NONSTATIC_MEMBER_P (t))
-	    perform_or_defer_access_check (TYPE_BINFO (type), t, t);
+	    perform_or_defer_access_check (TYPE_BINFO (type), t, t,
+					   tf_warning_or_error);
 	  else
-	    perform_or_defer_access_check (basebinfo, t, t);
+	    perform_or_defer_access_check (basebinfo, t, t,
+					   tf_warning_or_error);
 
 	  if (DECL_STATIC_FUNCTION_P (t))
 	    return t;
@@ -1891,7 +1893,8 @@ build_offset_ref (tree type, tree member, bool address_p)
     /* We need additional test besides the one in
        check_accessibility_of_qualified_id in case it is
        a pointer to non-static member.  */
-    perform_or_defer_access_check (TYPE_BINFO (type), member, member);
+    perform_or_defer_access_check (TYPE_BINFO (type), member, member,
+				   tf_warning_or_error);
 
   if (!address_p)
     {
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 20a6c87..c21ae15 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1225,6 +1225,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 
   ++cp_unevaluated_operand;
   ++c_inhibit_evaluation_warnings;
+  push_deferring_access_checks (dk_no_deferred);
 
   scope = push_scope (ctype);
 
@@ -1342,6 +1343,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 
   pop_scope (scope);
 
+  pop_deferring_access_checks ();
   --cp_unevaluated_operand;
   --c_inhibit_evaluation_warnings;
 }
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index df23299..70d6dac 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -10515,7 +10515,7 @@ cp_parser_simple_declaration (cp_parser* parser,
       if (cp_parser_declares_only_class_p (parser))
 	shadow_tag (&decl_specifiers);
       /* Perform any deferred access checks.  */
-      perform_deferred_access_checks ();
+      perform_deferred_access_checks (tf_warning_or_error);
     }
 
   /* Consume the `;'.  */
@@ -12416,7 +12416,8 @@ cp_parser_template_id (cp_parser *parser,
 	  FOR_EACH_VEC_ELT (deferred_access_check, access_check, i, chk)
 	    perform_or_defer_access_check (chk->binfo,
 					   chk->decl,
-					   chk->diag_decl);
+					   chk->diag_decl,
+					   tf_warning_or_error);
 	}
       /* Return the stored value.  */
       return check_value->value;
@@ -15751,7 +15752,7 @@ cp_parser_init_declarator (cp_parser* parser,
 
       /* Perform the access control checks for the declarator and the
 	 decl-specifiers.  */
-      perform_deferred_access_checks ();
+      perform_deferred_access_checks (tf_warning_or_error);
 
       /* Restore the saved value.  */
       if (TREE_CODE (decl) == FUNCTION_DECL)
@@ -21009,7 +21010,7 @@ cp_parser_function_definition_from_specifiers_and_declarator
      did not check, check them now.  We must wait until we are in the
      scope of the function to perform the checks, since the function
      might be a friend.  */
-  perform_deferred_access_checks ();
+  perform_deferred_access_checks (tf_warning_or_error);
 
   if (!success_p)
     {
@@ -21303,7 +21304,7 @@ static void
 cp_parser_perform_template_parameter_access_checks (VEC (deferred_access_check,gc)* checks)
 {
   ++processing_template_parmlist;
-  perform_access_checks (checks);
+  perform_access_checks (checks, tf_warning_or_error);
   --processing_template_parmlist;
 }
 
@@ -22752,7 +22753,7 @@ cp_parser_pre_parsed_nested_name_specifier (cp_parser *parser)
       FOR_EACH_VEC_ELT (deferred_access_check, checks, i, chk)
 	perform_or_defer_access_check (chk->binfo,
 				       chk->decl,
-				       chk->diag_decl);
+				       chk->diag_decl, tf_warning_or_error);
     }
   /* Set the scope from the stored value.  */
   parser->scope = check_value->value;
@@ -24010,7 +24011,7 @@ cp_parser_objc_method_definition_list (cp_parser* parser)
 	  if (!(ptk->type == CPP_PLUS || ptk->type == CPP_MINUS 
 		|| ptk->type == CPP_EOF || ptk->keyword == RID_AT_END))
 	    {
-	      perform_deferred_access_checks ();
+	      perform_deferred_access_checks (tf_warning_or_error);
 	      stop_deferring_access_checks ();
 	      meth = cp_parser_function_definition_after_declarator (parser,
 								     false);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 542f57a..65eb2cc 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8370,7 +8370,8 @@ perform_typedefs_access_check (tree tmpl, tree targs)
          of the use of the typedef.  */
       input_location = iter->locus;
       perform_or_defer_access_check (TYPE_BINFO (type_scope),
-				     type_decl, type_decl);
+				     type_decl, type_decl,
+				     tf_warning_or_error);
     }
     input_location = saved_location;
 }
@@ -8877,7 +8878,7 @@ instantiate_class_template_1 (tree type)
      added to the template at parsing time. Let's get those and perform
      the access checks then.  */
   perform_typedefs_access_check (pattern, args);
-  perform_deferred_access_checks ();
+  perform_deferred_access_checks (tf_warning_or_error);
   pop_nested_class ();
   maximum_field_alignment = saved_maximum_field_alignment;
   if (!fn_context)
@@ -14288,6 +14289,23 @@ deduction_tsubst_fntype (tree fn, tree targs, tsubst_flags_t complain)
   return r;
 }
 
+/* We're out of SFINAE context now, so generate diagnostics for the access
+   errors we saw earlier when instantiating D from TMPL and ARGS.  */
+
+static void
+recheck_decl_substitution (tree d, tree tmpl, tree args)
+{
+  tree pattern = DECL_TEMPLATE_RESULT (tmpl);
+  tree type = TREE_TYPE (pattern);
+  location_t loc = input_location;
+
+  push_access_scope (d);
+  input_location = DECL_SOURCE_LOCATION (pattern);
+  tsubst (type, args, tf_warning_or_error, d);
+  input_location = loc;
+  pop_access_scope (d);
+}
+
 /* Instantiate the indicated variable or function template TMPL with
    the template arguments in TARG_PTR.  */
 
@@ -14298,6 +14316,7 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
   tree fndecl;
   tree gen_tmpl;
   tree spec;
+  bool access_ok = true;
 
   if (tmpl == error_mark_node)
     return error_mark_node;
@@ -14345,7 +14364,11 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
 	      || fndecl == NULL_TREE);
 
   if (spec != NULL_TREE)
-    return spec;
+    {
+      if (FNDECL_RECHECK_ACCESS_P (spec) && (complain & tf_error))
+	recheck_decl_substitution (spec, gen_tmpl, targ_ptr);
+      return spec;
+    }
 
   if (check_instantiated_args (gen_tmpl, INNERMOST_TEMPLATE_ARGS (targ_ptr),
 			       complain))
@@ -14375,7 +14398,10 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
   pop_from_top_level ();
 
   if (fndecl == error_mark_node)
-    return error_mark_node;
+    {
+      pop_deferring_access_checks ();
+      return error_mark_node;
+    }
 
   /* The DECL_TI_TEMPLATE should always be the immediate parent
      template, not the most general template.  */
@@ -14384,7 +14410,8 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
   /* Now we know the specialization, compute access previously
      deferred.  */
   push_access_scope (fndecl);
-  perform_deferred_access_checks ();
+  if (!perform_deferred_access_checks (complain))
+    access_ok = false;
   pop_access_scope (fndecl);
   pop_deferring_access_checks ();
 
@@ -14395,6 +14422,16 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
   if (DECL_CHAIN (gen_tmpl) && DECL_CLONED_FUNCTION_P (DECL_CHAIN (gen_tmpl)))
     clone_function_decl (fndecl, /*update_method_vec_p=*/0);
 
+  if (!access_ok)
+    {
+      if (!(complain & tf_error))
+	{
+	  /* Remember to reinstantiate when we're out of SFINAE so the user
+	     can see the errors.  */
+	  FNDECL_RECHECK_ACCESS_P (fndecl) = true;
+	}
+      return error_mark_node;
+    }
   return fndecl;
 }
 
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index d112c05..048fdf3 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -1254,8 +1254,10 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type,
       && !really_overloaded_fn (rval))
     {
       tree decl = is_overloaded_fn (rval) ? get_first_fn (rval) : rval;
-      if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
-	perform_or_defer_access_check (basetype_path, decl, decl);
+      if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
+	  && !perform_or_defer_access_check (basetype_path, decl, decl,
+					     complain))
+	rval = error_mark_node;
     }
 
   if (errstr && protect)
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 8110295..6381949 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -223,7 +223,7 @@ pop_to_parent_deferring_access_checks (void)
       if (ptr->deferring_access_checks_kind == dk_no_deferred)
 	{
 	  /* Check access.  */
-	  perform_access_checks (checks);
+	  perform_access_checks (checks, tf_warning_or_error);
 	}
       else
 	{
@@ -252,25 +252,30 @@ pop_to_parent_deferring_access_checks (void)
 
 /* Perform the access checks in CHECKS.  The TREE_PURPOSE of each node
    is the BINFO indicating the qualifying scope used to access the
-   DECL node stored in the TREE_VALUE of the node.  */
+   DECL node stored in the TREE_VALUE of the node.  If CHECKS is empty
+   or we aren't in SFINAE context or all the checks succeed return TRUE,
+   otherwise FALSE.  */
 
-void
-perform_access_checks (VEC (deferred_access_check,gc)* checks)
+bool
+perform_access_checks (VEC (deferred_access_check,gc)* checks,
+		       tsubst_flags_t complain)
 {
   int i;
   deferred_access_check *chk;
   location_t loc = input_location;
+  bool ok = true;
 
   if (!checks)
-    return;
+    return true;
 
   FOR_EACH_VEC_ELT (deferred_access_check, checks, i, chk)
     {
       input_location = chk->loc;
-      enforce_access (chk->binfo, chk->decl, chk->diag_decl);
+      ok &= enforce_access (chk->binfo, chk->decl, chk->diag_decl, complain);
     }
 
   input_location = loc;
+  return (complain & tf_error) ? true : ok;
 }
 
 /* Perform the deferred access checks.
@@ -287,19 +292,21 @@ perform_access_checks (VEC (deferred_access_check,gc)* checks)
      A::X A::a, x;	// No error for `A::a', error for `x'
 
    We have to perform deferred access of `A::X', first with `A::a',
-   next with `x'.  */
+   next with `x'.  Return value like perform_access_checks above.  */
 
-void
-perform_deferred_access_checks (void)
+bool
+perform_deferred_access_checks (tsubst_flags_t complain)
 {
-  perform_access_checks (get_deferred_access_checks ());
+  return perform_access_checks (get_deferred_access_checks (), complain);
 }
 
 /* Defer checking the accessibility of DECL, when looked up in
-   BINFO. DIAG_DECL is the declaration to use to print diagnostics.  */
+   BINFO. DIAG_DECL is the declaration to use to print diagnostics.
+   Return value like perform_access_checks above.  */
 
-void
-perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl)
+bool
+perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl,
+			       tsubst_flags_t complain)
 {
   int i;
   deferred_access *ptr;
@@ -310,7 +317,7 @@ perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl)
   /* Exit if we are in a context that no access checking is performed.
      */
   if (deferred_access_no_check)
-    return;
+    return true;
 
   gcc_assert (TREE_CODE (binfo) == TREE_BINFO);
 
@@ -319,8 +326,8 @@ perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl)
   /* If we are not supposed to defer access checks, just check now.  */
   if (ptr->deferring_access_checks_kind == dk_no_deferred)
     {
-      enforce_access (binfo, decl, diag_decl);
-      return;
+      bool ok = enforce_access (binfo, decl, diag_decl, complain);
+      return (complain & tf_error) ? true : ok;
     }
 
   /* See if we are already going to perform this check.  */
@@ -330,7 +337,7 @@ perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl)
       if (chk->decl == decl && chk->binfo == binfo &&
 	  chk->diag_decl == diag_decl)
 	{
-	  return;
+	  return true;
 	}
     }
   /* If not, record the check.  */
@@ -341,28 +348,6 @@ perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl)
   new_access->decl = decl;
   new_access->diag_decl = diag_decl;
   new_access->loc = input_location;
-}
-
-/* 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;
 }
@@ -1611,7 +1596,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
       tree access_type = TREE_TYPE (object);
 
       perform_or_defer_access_check (TYPE_BINFO (access_type), decl,
-				     decl);
+				     decl, tf_warning_or_error);
 
       /* If the data member was named `C::M', convert `*this' to `C'
 	 first.  */
@@ -1733,7 +1718,7 @@ check_accessibility_of_qualified_id (tree decl,
       && CLASS_TYPE_P (qualifying_type)
       && !dependent_type_p (qualifying_type))
     perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
-				   decl);
+				   decl, tf_warning_or_error);
 }
 
 /* EXPR is the result of a qualified-id.  The QUALIFYING_CLASS was the
@@ -3336,7 +3321,8 @@ finish_id_expression (tree id_expression,
 		{
 		  tree path = currently_open_derived_class (context);
 		  perform_or_defer_access_check (TYPE_BINFO (path),
-						 decl, decl);
+						 decl, decl,
+						 tf_warning_or_error);
 		}
 	    }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae37.C b/gcc/testsuite/g++.dg/cpp0x/sfinae37.C
new file mode 100644
index 0000000..071923e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae37.C
@@ -0,0 +1,22 @@
+// PR c++/51213
+// { dg-do compile { target c++11 } }
+
+class C {
+  typedef int type;
+};
+
+template<class T, class = typename T::type>
+auto f(int) -> char;
+
+template<class>
+auto f(...) -> char (&)[2];
+
+static_assert(sizeof(f<C>(0)) == 2, "Ouch");
+
+template<class T>
+auto g(int) -> decltype(typename T::type(), char());
+
+template<class>
+auto g(...) -> char (&)[2];
+
+static_assert(sizeof(g<C>(0)) == 2, "Ouch");
diff --git a/gcc/testsuite/g++.dg/template/access23.C b/gcc/testsuite/g++.dg/template/access23.C
new file mode 100644
index 0000000..054cf92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access23.C
@@ -0,0 +1,16 @@
+template <class T>
+class A
+{
+  typedef T I;
+};
+
+template <class T>
+void f(typename T::I);
+
+template <class T>
+void f(int);
+
+int main()
+{
+  f<A<float> > (1);
+}
diff --git a/gcc/testsuite/g++.dg/template/access7.C b/gcc/testsuite/g++.dg/template/access7.C
index bd38e4e..7d18127 100644
--- a/gcc/testsuite/g++.dg/template/access7.C
+++ b/gcc/testsuite/g++.dg/template/access7.C
@@ -14,5 +14,5 @@ typename A::T* f (A) {			// { dg-error "this context" }
 }
 
 void g () {
-  f (S<int> ());			// { dg-message "required" }
+  f (S<int> ());			// { dg-message "required|no match" }
 }
diff --git a/gcc/testsuite/g++.dg/template/sfinae10.C b/gcc/testsuite/g++.dg/template/sfinae10.C
index 3b1d26b..574fedd 100644
--- a/gcc/testsuite/g++.dg/template/sfinae10.C
+++ b/gcc/testsuite/g++.dg/template/sfinae10.C
@@ -81,19 +81,19 @@ struct Y { };
 
 struct Z {
 private:
-  Z operator+(); // { dg-error "is private" }
-  Z operator-(); // { dg-error "is private" }
-  int operator*(); // { dg-error "is private" }
-  Z operator~(); // { dg-error "is private" } 
-  bool operator!(); // { dg-error "is private" }  
-  Z& operator++(); // { dg-error "is private" }  
-  Z& operator--(); // { dg-error "is private" }  
-  Z& operator++(int); // { dg-error "is private" }  
-  Z& operator--(int); // { dg-error "is private" }  
+  Z operator+();
+  Z operator-();
+  int operator*();
+  Z operator~();
+  bool operator!();
+  Z& operator++();
+  Z& operator--();
+  Z& operator++(int);
+  Z& operator--(int);
 };
 
 // has_unary_plus
-DEFINE_PREFIX_UNARY_TRAIT(has_unary_plus, +); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(has_unary_plus, +);
 STATIC_ASSERT((has_unary_plus<int>::value));
 STATIC_ASSERT((!has_unary_plus<int X::*>::value));
 STATIC_ASSERT((has_unary_plus<W>::value));
@@ -101,7 +101,7 @@ STATIC_ASSERT((has_unary_plus<X>::value));
 STATIC_ASSERT((!has_unary_plus<Y>::value));
 
 // is_negatable
-DEFINE_PREFIX_UNARY_TRAIT(is_negatable, -); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(is_negatable, -);
 STATIC_ASSERT((is_negatable<int>::value));
 STATIC_ASSERT((!is_negatable<int X::*>::value));
 STATIC_ASSERT((is_negatable<W>::value));
@@ -109,7 +109,7 @@ STATIC_ASSERT((is_negatable<X>::value));
 STATIC_ASSERT((!is_negatable<Y>::value));
 
 // is_dereferenceable
-DEFINE_PREFIX_UNARY_TRAIT(is_dereferenceable, *); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(is_dereferenceable, *);
 STATIC_ASSERT((!is_dereferenceable<int>::value));
 STATIC_ASSERT((is_dereferenceable<int*>::value));
 STATIC_ASSERT((is_dereferenceable<W>::value));
@@ -117,7 +117,7 @@ STATIC_ASSERT((is_dereferenceable<X>::value));
 STATIC_ASSERT((!is_dereferenceable<Y>::value));
 
 // has_bitwise_not
-DEFINE_PREFIX_UNARY_TRAIT(has_bitwise_not, ~); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(has_bitwise_not, ~);
 STATIC_ASSERT((has_bitwise_not<int>::value));
 STATIC_ASSERT((!has_bitwise_not<int*>::value));
 STATIC_ASSERT((has_bitwise_not<W>::value));
@@ -125,7 +125,7 @@ STATIC_ASSERT((has_bitwise_not<X>::value));
 STATIC_ASSERT((!has_bitwise_not<Y>::value));
 
 // has_truth_not
-DEFINE_PREFIX_UNARY_TRAIT(has_truth_not, !); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(has_truth_not, !);
 STATIC_ASSERT((has_truth_not<int>::value));
 STATIC_ASSERT((has_truth_not<int*>::value));
 STATIC_ASSERT((has_truth_not<W>::value));
@@ -133,7 +133,7 @@ STATIC_ASSERT((has_truth_not<X>::value));
 STATIC_ASSERT((!has_truth_not<Y>::value));
 
 // has_preincrement
-DEFINE_PREFIX_UNARY_TRAIT(has_preincrement, ++); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(has_preincrement, ++);
 STATIC_ASSERT((has_preincrement<int>::value));
 STATIC_ASSERT((has_preincrement<int*>::value));
 STATIC_ASSERT((!has_preincrement<int X::*>::value));
@@ -142,7 +142,7 @@ STATIC_ASSERT((has_preincrement<X>::value));
 STATIC_ASSERT((!has_preincrement<Y>::value));
 
 // has_predecrement
-DEFINE_PREFIX_UNARY_TRAIT(has_predecrement, --); // { dg-error "within this context" }
+DEFINE_PREFIX_UNARY_TRAIT(has_predecrement, --);
 STATIC_ASSERT((has_predecrement<int>::value));
 STATIC_ASSERT((has_predecrement<int*>::value));
 STATIC_ASSERT((!has_predecrement<int X::*>::value));
@@ -151,7 +151,7 @@ STATIC_ASSERT((has_predecrement<X>::value));
 STATIC_ASSERT((!has_predecrement<Y>::value));
 
 // has_postincrement
-DEFINE_POSTFIX_UNARY_TRAIT(has_postincrement, ++); // { dg-error "within this context" }
+DEFINE_POSTFIX_UNARY_TRAIT(has_postincrement, ++);
 STATIC_ASSERT((has_postincrement<int>::value));
 STATIC_ASSERT((has_postincrement<int*>::value));
 STATIC_ASSERT((!has_postincrement<int X::*>::value));
@@ -160,7 +160,7 @@ STATIC_ASSERT((has_postincrement<X>::value));
 STATIC_ASSERT((!has_postincrement<Y>::value));
 
 // has_postdecrement
-DEFINE_POSTFIX_UNARY_TRAIT(has_postdecrement, --); // { dg-error "within this context" }
+DEFINE_POSTFIX_UNARY_TRAIT(has_postdecrement, --);
 STATIC_ASSERT((has_postdecrement<int>::value));
 STATIC_ASSERT((has_postdecrement<int*>::value));
 STATIC_ASSERT((!has_postdecrement<int X::*>::value));
@@ -169,13 +169,12 @@ STATIC_ASSERT((has_postdecrement<X>::value));
 STATIC_ASSERT((!has_postdecrement<Y>::value));
 
 // Check for private members
-STATIC_ASSERT((has_unary_plus<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((is_negatable<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((is_dereferenceable<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((has_bitwise_not<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((has_truth_not<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((has_preincrement<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((has_predecrement<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((has_postincrement<Z>::value)); // { dg-message "required from here" }
-STATIC_ASSERT((has_postdecrement<Z>::value)); // { dg-message "required from here" }
-
+STATIC_ASSERT((!has_unary_plus<Z>::value));
+STATIC_ASSERT((!is_negatable<Z>::value));
+STATIC_ASSERT((!is_dereferenceable<Z>::value));
+STATIC_ASSERT((!has_bitwise_not<Z>::value));
+STATIC_ASSERT((!has_truth_not<Z>::value));
+STATIC_ASSERT((!has_preincrement<Z>::value));
+STATIC_ASSERT((!has_predecrement<Z>::value));
+STATIC_ASSERT((!has_postincrement<Z>::value));
+STATIC_ASSERT((!has_postdecrement<Z>::value));
diff --git a/gcc/testsuite/g++.dg/template/sfinae6_neg.C b/gcc/testsuite/g++.dg/template/sfinae6_neg.C
index 28adf73..6ed3d22 100644
--- a/gcc/testsuite/g++.dg/template/sfinae6_neg.C
+++ b/gcc/testsuite/g++.dg/template/sfinae6_neg.C
@@ -14,7 +14,7 @@ template<typename T> struct enable_if<false, T> { };
 template<typename F, typename T1, typename T2>
   typename enable_if<sizeof(create_a<F>()(create_a<T1>(), create_a<T2>()), 1),
 		     yes_type>::type
-  check_is_callable2(type<F>, type<T1>, type<T2>); // { dg-error "within this context" }
+  check_is_callable2(type<F>, type<T1>, type<T2>);
 
 no_type check_is_callable2(...);
 
@@ -52,7 +52,7 @@ struct F {
   void operator()(A, A);
 
 private:
-  void operator()(B, B); // { dg-error "is private" }
+  void operator()(B, B);
 };
 
-STATIC_ASSERT((is_callable2<F, B, B>::value));
+STATIC_ASSERT((!is_callable2<F, B, B>::value));
diff --git a/libstdc++-v3/testsuite/20_util/pair/noncopyable.cc b/libstdc++-v3/testsuite/20_util/pair/noncopyable.cc
new file mode 100644
index 0000000..731e7ee
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/pair/noncopyable.cc
@@ -0,0 +1,39 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++11" }
+
+// Copyright (C) 2012 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <utility>
+
+// PR c++/51213
+class Uncopyable
+{
+  Uncopyable(const Uncopyable&);
+ public:
+  Uncopyable() = default;
+};
+
+struct ContainsUncopyable
+{
+  std::pair<Uncopyable, int> pv;
+};
+
+void foo()
+{
+  ContainsUncopyable c;
+}
commit 1e81dada2d956ef98865385dcc75186baf6accdd
Author: Jason Merrill <ja...@redhat.com>
Date:   Tue Jul 17 14:32:35 2012 -0400

    	* semantics.c (perform_access_checks): Add complain parm, return bool.
    	(perform_deferred_access_checks): Likewise.
    	(perform_or_defer_access_check): Likewise.
    	(speculative_access_check): Remove.
    	* call.c (enforce_access): Add complain parm, return bool.
    	* decl.c, friend.c, class.c, init.c, parser.c: Adjust callers.
    	* search.c: Adjust callers.
    	* cp-tree.h (TINFO_RECHECK_ACCESS_P): New macro.
    	(FNDECL_RECHECK_ACCESS_P): New macro.
    	* method.c (synthesized_method_walk): Stop deferring access checks.
    	* pt.c (recheck_decl_substitution): New.
    	(instantiate_template_1): Set and check FNDECL_RECHECK_ACCESS_P.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 4be5424..5b3245f 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5581,7 +5581,7 @@ enforce_access (tree basetype_path, tree decl, tree diag_decl,
 
   if (!accessible_p (basetype_path, decl, true))
     {
-      if (cxx_dialect < cxx0x || complain & tf_error)
+      if (complain & tf_error)
 	{
 	  if (TREE_PRIVATE (decl))
 	    error ("%q+#D is private", diag_decl);
@@ -6515,14 +6515,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 	access_fn = DECL_TI_TEMPLATE (fn);
       else
 	access_fn = fn;
-      if (flags & LOOKUP_SPECULATIVE)
-	{
-	  if (!speculative_access_check (cand->access_path, access_fn, fn,
-					 complain))
-	    return error_mark_node;
-	}
-      else if (!perform_or_defer_access_check (cand->access_path, access_fn,
-					       fn, complain))
+      if (!perform_or_defer_access_check (cand->access_path, access_fn,
+					  fn, complain))
 	return error_mark_node;
     }
 
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 16a5b4b..96a7420 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1189,7 +1189,8 @@ alter_access (tree t, tree fdecl, tree access)
     }
   else
     {
-      perform_or_defer_access_check (TYPE_BINFO (t), fdecl, fdecl, tf_error);
+      perform_or_defer_access_check (TYPE_BINFO (t), fdecl, fdecl,
+				     tf_warning_or_error);
       DECL_ACCESS (fdecl) = tree_cons (t, access, DECL_ACCESS (fdecl));
       return 1;
     }
@@ -7147,7 +7148,8 @@ resolve_address_of_overloaded_function (tree target_type,
       && DECL_FUNCTION_MEMBER_P (fn))
     {
       gcc_assert (access_path);
-      perform_or_defer_access_check (access_path, fn, fn, tf_error);
+      perform_or_defer_access_check (access_path, fn, fn,
+				     tf_warning_or_error);
     }
 
   if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type))
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5a5bec7..f1a4b32 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4433,9 +4433,7 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
    Used by sythesized_method_walk to determine which functions will
    be called to initialize subobjects, in order to determine exception
    specification and possible implicit delete.
-   This is kind of a hack, but since access control doesn't respect SFINAE
-   we can't just use tf_none to avoid access control errors, we need
-   another mechanism.  Exiting early also avoids problems with trying
+   This is kind of a hack, but exiting early avoids problems with trying
    to perform argument conversions when the class isn't complete yet.  */
 #define LOOKUP_SPECULATIVE (LOOKUP_LIST_ONLY << 1)
 /* Used by calls from defaulted functions to limit the overload set to avoid
@@ -5512,8 +5510,6 @@ extern bool perform_access_checks (VEC (deferred_access_check,gc)*,
 extern bool perform_deferred_access_checks	(tsubst_flags_t);
 extern bool perform_or_defer_access_check	(tree, tree, tree,
 						 tsubst_flags_t);
-extern bool speculative_access_check		(tree, tree, tree,
-						 tsubst_flags_t);
 extern int stmts_are_full_exprs_p		(void);
 extern void init_cp_semantics			(void);
 extern tree do_poplevel				(tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 32f64ab..605058d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -3307,8 +3307,7 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
       return error_mark_node;
     }
 
-  if ((cxx_dialect >= cxx0x || complain & tf_error)
-      && !perform_or_defer_access_check (TYPE_BINFO (context), t, t, complain))
+  if (!perform_or_defer_access_check (TYPE_BINFO (context), t, t, complain))
     return error_mark_node;
 
   /* If we are currently parsing a template and if T is a typedef accessed
@@ -3379,9 +3378,8 @@ make_unbound_class_template (tree context, tree name, tree parm_list,
 	  return error_mark_node;
 	}
 
-      if ((cxx_dialect >= cxx0x || complain & tf_error)
-	  && !perform_or_defer_access_check (TYPE_BINFO (context), tmpl, tmpl,
-					     complain))
+      if (!perform_or_defer_access_check (TYPE_BINFO (context), tmpl, tmpl,
+					  complain))
 	return error_mark_node;
 
       return tmpl;
@@ -6651,7 +6649,7 @@ register_dtor_fn (tree decl)
       cleanup = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), idx);
       /* Make sure it is accessible.  */
       perform_or_defer_access_check (TYPE_BINFO (type), cleanup, cleanup,
-				     tf_error);
+				     tf_warning_or_error);
     }
   else
     {
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 9f20e6e..d0cbaed 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -166,7 +166,8 @@ add_friend (tree type, tree decl, bool complain)
 
   ctx = DECL_CONTEXT (decl);
   if (ctx && CLASS_TYPE_P (ctx) && !uses_template_parms (ctx))
-    perform_or_defer_access_check (TYPE_BINFO (ctx), decl, decl, tf_error);
+    perform_or_defer_access_check (TYPE_BINFO (ctx), decl, decl,
+				   tf_warning_or_error);
 
   maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1);
 
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index aadbea8..a725a0c 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1876,9 +1876,11 @@ build_offset_ref (tree type, tree member, bool address_p)
 	       (or any class derived from that class).  */
 	  if (address_p && DECL_P (t)
 	      && DECL_NONSTATIC_MEMBER_P (t))
-	    perform_or_defer_access_check (TYPE_BINFO (type), t, t, tf_error);
+	    perform_or_defer_access_check (TYPE_BINFO (type), t, t,
+					   tf_warning_or_error);
 	  else
-	    perform_or_defer_access_check (basebinfo, t, t, tf_error);
+	    perform_or_defer_access_check (basebinfo, t, t,
+					   tf_warning_or_error);
 
 	  if (DECL_STATIC_FUNCTION_P (t))
 	    return t;
@@ -1891,7 +1893,8 @@ build_offset_ref (tree type, tree member, bool address_p)
     /* We need additional test besides the one in
        check_accessibility_of_qualified_id in case it is
        a pointer to non-static member.  */
-    perform_or_defer_access_check (TYPE_BINFO (type), member, member, tf_error);
+    perform_or_defer_access_check (TYPE_BINFO (type), member, member,
+				   tf_warning_or_error);
 
   if (!address_p)
     {
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 20a6c87..c21ae15 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1225,6 +1225,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 
   ++cp_unevaluated_operand;
   ++c_inhibit_evaluation_warnings;
+  push_deferring_access_checks (dk_no_deferred);
 
   scope = push_scope (ctype);
 
@@ -1342,6 +1343,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 
   pop_scope (scope);
 
+  pop_deferring_access_checks ();
   --cp_unevaluated_operand;
   --c_inhibit_evaluation_warnings;
 }
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 010d7fc..70d6dac 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -10515,7 +10515,7 @@ cp_parser_simple_declaration (cp_parser* parser,
       if (cp_parser_declares_only_class_p (parser))
 	shadow_tag (&decl_specifiers);
       /* Perform any deferred access checks.  */
-      perform_deferred_access_checks (tf_error);
+      perform_deferred_access_checks (tf_warning_or_error);
     }
 
   /* Consume the `;'.  */
@@ -12416,7 +12416,8 @@ cp_parser_template_id (cp_parser *parser,
 	  FOR_EACH_VEC_ELT (deferred_access_check, access_check, i, chk)
 	    perform_or_defer_access_check (chk->binfo,
 					   chk->decl,
-					   chk->diag_decl, tf_error);
+					   chk->diag_decl,
+					   tf_warning_or_error);
 	}
       /* Return the stored value.  */
       return check_value->value;
@@ -15751,7 +15752,7 @@ cp_parser_init_declarator (cp_parser* parser,
 
       /* Perform the access control checks for the declarator and the
 	 decl-specifiers.  */
-      perform_deferred_access_checks (true);
+      perform_deferred_access_checks (tf_warning_or_error);
 
       /* Restore the saved value.  */
       if (TREE_CODE (decl) == FUNCTION_DECL)
@@ -21009,7 +21010,7 @@ cp_parser_function_definition_from_specifiers_and_declarator
      did not check, check them now.  We must wait until we are in the
      scope of the function to perform the checks, since the function
      might be a friend.  */
-  perform_deferred_access_checks (tf_error);
+  perform_deferred_access_checks (tf_warning_or_error);
 
   if (!success_p)
     {
@@ -21303,7 +21304,7 @@ static void
 cp_parser_perform_template_parameter_access_checks (VEC (deferred_access_check,gc)* checks)
 {
   ++processing_template_parmlist;
-  perform_access_checks (checks, tf_error);
+  perform_access_checks (checks, tf_warning_or_error);
   --processing_template_parmlist;
 }
 
@@ -22752,7 +22753,7 @@ cp_parser_pre_parsed_nested_name_specifier (cp_parser *parser)
       FOR_EACH_VEC_ELT (deferred_access_check, checks, i, chk)
 	perform_or_defer_access_check (chk->binfo,
 				       chk->decl,
-				       chk->diag_decl, tf_error);
+				       chk->diag_decl, tf_warning_or_error);
     }
   /* Set the scope from the stored value.  */
   parser->scope = check_value->value;
@@ -24010,7 +24011,7 @@ cp_parser_objc_method_definition_list (cp_parser* parser)
 	  if (!(ptk->type == CPP_PLUS || ptk->type == CPP_MINUS 
 		|| ptk->type == CPP_EOF || ptk->keyword == RID_AT_END))
 	    {
-	      perform_deferred_access_checks (tf_error);
+	      perform_deferred_access_checks (tf_warning_or_error);
 	      stop_deferring_access_checks ();
 	      meth = cp_parser_function_definition_after_declarator (parser,
 								     false);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 26e3be2..776f5e6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8370,7 +8370,8 @@ perform_typedefs_access_check (tree tmpl, tree targs)
          of the use of the typedef.  */
       input_location = iter->locus;
       perform_or_defer_access_check (TYPE_BINFO (type_scope),
-				     type_decl, type_decl, tf_error);
+				     type_decl, type_decl,
+				     tf_warning_or_error);
     }
     input_location = saved_location;
 }
@@ -8877,7 +8878,7 @@ instantiate_class_template_1 (tree type)
      added to the template at parsing time. Let's get those and perform
      the access checks then.  */
   perform_typedefs_access_check (pattern, args);
-  perform_deferred_access_checks (tf_error);
+  perform_deferred_access_checks (tf_warning_or_error);
   pop_nested_class ();
   maximum_field_alignment = saved_maximum_field_alignment;
   if (!fn_context)
@@ -9870,13 +9871,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	    hash = hash_tmpl_and_args (gen_tmpl, argvec);
 	    spec = retrieve_specialization (gen_tmpl, argvec, hash);
 
-	    r = spec;
 	    if (spec)
 	      {
-		if (FNDECL_RECHECK_ACCESS_P (spec) && (complain & tf_error))
-		  /* Reinstantiate to get access errors.  */;
-		else
-		  break;
+		r = spec;
+		break;
 	      }
 
 	    /* We can see more levels of arguments than parameters if
@@ -9952,13 +9950,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	if (type == error_mark_node)
 	  RETURN (error_mark_node);
 
-	if (r)
-	  {
-	    /* We're done reinstantiating for access errors.  */
-	    gcc_assert (FNDECL_RECHECK_ACCESS_P (r));
-	    break;
-	  }
-
 	/* We do NOT check for matching decls pushed separately at this
 	   point, as they may not represent instantiations of this
 	   template, and in any case are considered separate under the
@@ -14298,6 +14289,23 @@ deduction_tsubst_fntype (tree fn, tree targs, tsubst_flags_t complain)
   return r;
 }
 
+/* We're out of SFINAE context now, so generate diagnostics for the access
+   errors we saw earlier when instantiating D from TMPL and ARGS.  */
+
+static void
+recheck_decl_substitution (tree d, tree tmpl, tree args)
+{
+  tree pattern = DECL_TEMPLATE_RESULT (tmpl);
+  tree type = TREE_TYPE (pattern);
+  location_t loc = input_location;
+
+  push_access_scope (d);
+  input_location = DECL_SOURCE_LOCATION (pattern);
+  tsubst (type, args, tf_warning_or_error, d);
+  input_location = loc;
+  pop_access_scope (d);
+}
+
 /* Instantiate the indicated variable or function template TMPL with
    the template arguments in TARG_PTR.  */
 
@@ -14357,11 +14365,9 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
 
   if (spec != NULL_TREE)
     {
-      if (FNDECL_RECHECK_ACCESS_P (spec)
-	  && (complain & tf_error))
-	/* Do the instantiation again, we're out of SFINAE context.  */;
-      else
-	return spec;
+      if (FNDECL_RECHECK_ACCESS_P (spec) && (complain & tf_error))
+	recheck_decl_substitution (spec, gen_tmpl, targ_ptr);
+      return spec;
     }
 
   if (check_instantiated_args (gen_tmpl, INNERMOST_TEMPLATE_ARGS (targ_ptr),
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 612b054..6381949 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -223,7 +223,7 @@ pop_to_parent_deferring_access_checks (void)
       if (ptr->deferring_access_checks_kind == dk_no_deferred)
 	{
 	  /* Check access.  */
-	  perform_access_checks (checks, tf_error);
+	  perform_access_checks (checks, tf_warning_or_error);
 	}
       else
 	{
@@ -352,30 +352,6 @@ perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl,
   return true;
 }
 
-/* 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,
-			  tsubst_flags_t 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 & tf_error)
-	enforce_access (binfo, decl, diag_decl, tf_error);
-      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.  */
@@ -1620,7 +1596,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
       tree access_type = TREE_TYPE (object);
 
       perform_or_defer_access_check (TYPE_BINFO (access_type), decl,
-				     decl, tf_error);
+				     decl, tf_warning_or_error);
 
       /* If the data member was named `C::M', convert `*this' to `C'
 	 first.  */
@@ -1742,7 +1718,7 @@ check_accessibility_of_qualified_id (tree decl,
       && CLASS_TYPE_P (qualifying_type)
       && !dependent_type_p (qualifying_type))
     perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
-				   decl, tf_error);
+				   decl, tf_warning_or_error);
 }
 
 /* EXPR is the result of a qualified-id.  The QUALIFYING_CLASS was the
@@ -3345,7 +3321,8 @@ finish_id_expression (tree id_expression,
 		{
 		  tree path = currently_open_derived_class (context);
 		  perform_or_defer_access_check (TYPE_BINFO (path),
-						 decl, decl, tf_error);
+						 decl, decl,
+						 tf_warning_or_error);
 		}
 	    }
 
diff --git a/gcc/testsuite/g++.dg/template/access23.C b/gcc/testsuite/g++.dg/template/access23.C
new file mode 100644
index 0000000..054cf92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access23.C
@@ -0,0 +1,16 @@
+template <class T>
+class A
+{
+  typedef T I;
+};
+
+template <class T>
+void f(typename T::I);
+
+template <class T>
+void f(int);
+
+int main()
+{
+  f<A<float> > (1);
+}
commit ea9415a98877ad49f9443910f4b44e732aed0ac8
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed Jul 18 17:39:21 2012 -0400

    	* method.c (process_subob_fn): Make sure no_implicit_p is non-null
    	before trying to store through it.

diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index b0e9ece..20a6c87 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -949,7 +949,7 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
 
   /* Core 1402: A non-trivial copy op suppresses the implicit
      declaration of the move ctor/op=.  */
-  if (move_p && !move_fn_p (fn) && !trivial_fn_p (fn))
+  if (no_implicit_p && move_p && !move_fn_p (fn) && !trivial_fn_p (fn))
     *no_implicit_p = true;
 
   if (constexpr_p && !DECL_DECLARED_CONSTEXPR_P (fn))
commit c871e18c31fd94e9ee7ee983bedf50047dedfe60
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed Jul 18 18:37:17 2012 -0400

    	* pt.c (instantiate_decl): Don't recheck substitutions.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 65eb2cc..0d25398 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -18248,35 +18248,6 @@ instantiate_decl (tree d, int defer_ok,
   if (TREE_CODE (d) == FUNCTION_DECL)
     maybe_instantiate_noexcept (d);
 
-  /* Recheck the substitutions to obtain any warning messages
-     about ignoring cv qualifiers.  Don't do this for artificial decls,
-     as it breaks the context-sensitive substitution for lambda op(). */
-  if (!defer_ok && !DECL_ARTIFICIAL (d))
-    {
-      tree gen = DECL_TEMPLATE_RESULT (gen_tmpl);
-      tree type = TREE_TYPE (gen);
-
-      /* Make sure that we can see identifiers, and compute access
-	 correctly.  D is already the target FUNCTION_DECL with the
-	 right context.  */
-      push_access_scope (d);
-
-      if (TREE_CODE (gen) == FUNCTION_DECL)
-	{
-	  tsubst (DECL_ARGUMENTS (gen), gen_args, tf_warning_or_error, d);
-          tsubst_exception_specification (type, gen_args, tf_warning_or_error,
-                                          d, /*defer_ok*/true);
-	  /* Don't simply tsubst the function type, as that will give
-	     duplicate warnings about poor parameter qualifications.
-	     The function arguments are the same as the decl_arguments
-	     without the top level cv qualifiers.  */
-	  type = TREE_TYPE (type);
-	}
-      tsubst (type, gen_args, tf_warning_or_error, d);
-
-      pop_access_scope (d);
-    }
-
   /* Defer all other templates, unless we have been explicitly
      forbidden from doing so.  */
   if (/* If there is no definition, we cannot instantiate the

Reply via email to