From patchwork Tue Jul 17 12:45:42 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [C++,RFC,/] PR 51213 ("access control under SFINAE") Date: Tue, 17 Jul 2012 02:45:42 -0000 From: Paolo Carlini X-Patchwork-Id: 171414 Message-Id: <50055E76.8030500@oracle.com> To: Jason Merrill Cc: "gcc-patches@gcc.gnu.org" , Dodji Seketeli Hi, On 07/16/2012 07:39 PM, Jason Merrill wrote: > On 07/14/2012 05:54 AM, Paolo Carlini wrote: >> The above change of yours appear to imply that, at variance with what I >> had in my first draft, perform_typedefs_access_check shouldn't really >> gain a tsubst_flags_t argument, because now it's called by >> instantiate_decl and instantiate_class_template_1 (from which I was >> passing a true / tf_error). Makes sense? > That makes sense to me. Excellent. Then the below (which incorporates your access7 patch) bootstraps and regtests fine on x86_64-linux. As you can see, I'm consistently using tsubst_flags_t parameters and, in enforce_access, I make sure that in C++98 mode we emit hard errors even in SFINAE contexts. Let me know how you want proceed, if you want now a ChangeLog entry for my bits or whatelse... Thanks! Paolo. /////////////////////////// Index: libstdc++-v3/testsuite/20_util/pair/noncopyable.cc =================================================================== --- libstdc++-v3/testsuite/20_util/pair/noncopyable.cc (revision 0) +++ libstdc++-v3/testsuite/20_util/pair/noncopyable.cc (revision 0) @@ -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 +// . + +#include + +// PR c++/51213 +class Uncopyable +{ + Uncopyable(const Uncopyable&); + public: + Uncopyable() = default; +}; + +struct ContainsUncopyable +{ + std::pair pv; +}; + +void foo() +{ + ContainsUncopyable c; +} Index: gcc/testsuite/g++.dg/cpp0x/sfinae37.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/sfinae37.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/sfinae37.C (revision 0) @@ -0,0 +1,22 @@ +// PR c++/51213 +// { dg-do compile { target c++11 } } + +class C { + typedef int type; +}; + +template +auto f(int) -> char; + +template +auto f(...) -> char (&)[2]; + +static_assert(sizeof(f(0)) == 2, "Ouch"); + +template +auto g(int) -> decltype(typename T::type(), char()); + +template +auto g(...) -> char (&)[2]; + +static_assert(sizeof(g(0)) == 2, "Ouch"); Index: gcc/testsuite/g++.dg/template/access7.C =================================================================== --- gcc/testsuite/g++.dg/template/access7.C (revision 189572) +++ gcc/testsuite/g++.dg/template/access7.C (working copy) @@ -14,5 +14,5 @@ typename A::T* f (A) { // { dg-error "this conte } void g () { - f (S ()); // { dg-message "required" } + f (S ()); // { dg-message "required|no match" } } Index: gcc/testsuite/g++.dg/template/sfinae10.C =================================================================== --- gcc/testsuite/g++.dg/template/sfinae10.C (revision 189572) +++ gcc/testsuite/g++.dg/template/sfinae10.C (working copy) @@ -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+(); // { dg-error "is private" "" { target c++98 } } + Z operator-(); // { dg-error "is private" "" { target c++98 } } + int operator*(); // { dg-error "is private" "" { target c++98 } } + Z operator~(); // { dg-error "is private" "" { target c++98 } } + bool operator!(); // { dg-error "is private" "" { target c++98 } } + Z& operator++(); // { dg-error "is private" "" { target c++98 } } + Z& operator--(); // { dg-error "is private" "" { target c++98 } } + Z& operator++(int); // { dg-error "is private" "" { target c++98 } } + Z& operator--(int); // { dg-error "is private" "" { target c++98 } } }; // has_unary_plus -DEFINE_PREFIX_UNARY_TRAIT(has_unary_plus, +); // { dg-error "within this context" } +DEFINE_PREFIX_UNARY_TRAIT(has_unary_plus, +); // { dg-error "within this context" "" { target c++98 } } STATIC_ASSERT((has_unary_plus::value)); STATIC_ASSERT((!has_unary_plus::value)); STATIC_ASSERT((has_unary_plus::value)); @@ -101,7 +101,7 @@ STATIC_ASSERT((has_unary_plus::value)); STATIC_ASSERT((!has_unary_plus::value)); // is_negatable -DEFINE_PREFIX_UNARY_TRAIT(is_negatable, -); // { dg-error "within this context" } +DEFINE_PREFIX_UNARY_TRAIT(is_negatable, -); // { dg-error "within this context" "" { target c++98 } } STATIC_ASSERT((is_negatable::value)); STATIC_ASSERT((!is_negatable::value)); STATIC_ASSERT((is_negatable::value)); @@ -109,7 +109,7 @@ STATIC_ASSERT((is_negatable::value)); STATIC_ASSERT((!is_negatable::value)); // is_dereferenceable -DEFINE_PREFIX_UNARY_TRAIT(is_dereferenceable, *); // { dg-error "within this context" } +DEFINE_PREFIX_UNARY_TRAIT(is_dereferenceable, *); // { dg-error "within this context" "" { target c++98 } } STATIC_ASSERT((!is_dereferenceable::value)); STATIC_ASSERT((is_dereferenceable::value)); STATIC_ASSERT((is_dereferenceable::value)); @@ -117,7 +117,7 @@ STATIC_ASSERT((is_dereferenceable::value)); STATIC_ASSERT((!is_dereferenceable::value)); // has_bitwise_not -DEFINE_PREFIX_UNARY_TRAIT(has_bitwise_not, ~); // { dg-error "within this context" } +DEFINE_PREFIX_UNARY_TRAIT(has_bitwise_not, ~); // { dg-error "within this context" "" { target c++98 } } STATIC_ASSERT((has_bitwise_not::value)); STATIC_ASSERT((!has_bitwise_not::value)); STATIC_ASSERT((has_bitwise_not::value)); @@ -125,7 +125,7 @@ STATIC_ASSERT((has_bitwise_not::value)); STATIC_ASSERT((!has_bitwise_not::value)); // has_truth_not -DEFINE_PREFIX_UNARY_TRAIT(has_truth_not, !); // { dg-error "within this context" } +DEFINE_PREFIX_UNARY_TRAIT(has_truth_not, !); // { dg-error "within this context" "" { target c++98 } } STATIC_ASSERT((has_truth_not::value)); STATIC_ASSERT((has_truth_not::value)); STATIC_ASSERT((has_truth_not::value)); @@ -133,7 +133,7 @@ STATIC_ASSERT((has_truth_not::value)); STATIC_ASSERT((!has_truth_not::value)); // has_preincrement -DEFINE_PREFIX_UNARY_TRAIT(has_preincrement, ++); // { dg-error "within this context" } +DEFINE_PREFIX_UNARY_TRAIT(has_preincrement, ++); // { dg-error "within this context" "" { target c++98 } } STATIC_ASSERT((has_preincrement::value)); STATIC_ASSERT((has_preincrement::value)); STATIC_ASSERT((!has_preincrement::value)); @@ -142,7 +142,7 @@ STATIC_ASSERT((has_preincrement::value)); STATIC_ASSERT((!has_preincrement::value)); // has_predecrement -DEFINE_PREFIX_UNARY_TRAIT(has_predecrement, --); // { dg-error "within this context" } +DEFINE_PREFIX_UNARY_TRAIT(has_predecrement, --); // { dg-error "within this context" "" { target c++98 } } STATIC_ASSERT((has_predecrement::value)); STATIC_ASSERT((has_predecrement::value)); STATIC_ASSERT((!has_predecrement::value)); @@ -151,7 +151,7 @@ STATIC_ASSERT((has_predecrement::value)); STATIC_ASSERT((!has_predecrement::value)); // has_postincrement -DEFINE_POSTFIX_UNARY_TRAIT(has_postincrement, ++); // { dg-error "within this context" } +DEFINE_POSTFIX_UNARY_TRAIT(has_postincrement, ++); // { dg-error "within this context" "" { target c++98 } } STATIC_ASSERT((has_postincrement::value)); STATIC_ASSERT((has_postincrement::value)); STATIC_ASSERT((!has_postincrement::value)); @@ -160,7 +160,7 @@ STATIC_ASSERT((has_postincrement::value)); STATIC_ASSERT((!has_postincrement::value)); // has_postdecrement -DEFINE_POSTFIX_UNARY_TRAIT(has_postdecrement, --); // { dg-error "within this context" } +DEFINE_POSTFIX_UNARY_TRAIT(has_postdecrement, --); // { dg-error "within this context" "" { target c++98 } } STATIC_ASSERT((has_postdecrement::value)); STATIC_ASSERT((has_postdecrement::value)); STATIC_ASSERT((!has_postdecrement::value)); @@ -169,13 +169,12 @@ STATIC_ASSERT((has_postdecrement::value)); STATIC_ASSERT((!has_postdecrement::value)); // Check for private members -STATIC_ASSERT((has_unary_plus::value)); // { dg-message "required from here" } -STATIC_ASSERT((is_negatable::value)); // { dg-message "required from here" } -STATIC_ASSERT((is_dereferenceable::value)); // { dg-message "required from here" } -STATIC_ASSERT((has_bitwise_not::value)); // { dg-message "required from here" } -STATIC_ASSERT((has_truth_not::value)); // { dg-message "required from here" } -STATIC_ASSERT((has_preincrement::value)); // { dg-message "required from here" } -STATIC_ASSERT((has_predecrement::value)); // { dg-message "required from here" } -STATIC_ASSERT((has_postincrement::value)); // { dg-message "required from here" } -STATIC_ASSERT((has_postdecrement::value)); // { dg-message "required from here" } - +STATIC_ASSERT((!has_unary_plus::value)); +STATIC_ASSERT((!is_negatable::value)); +STATIC_ASSERT((!is_dereferenceable::value)); +STATIC_ASSERT((!has_bitwise_not::value)); +STATIC_ASSERT((!has_truth_not::value)); +STATIC_ASSERT((!has_preincrement::value)); +STATIC_ASSERT((!has_predecrement::value)); +STATIC_ASSERT((!has_postincrement::value)); +STATIC_ASSERT((!has_postdecrement::value)); Index: gcc/testsuite/g++.dg/template/sfinae6_neg.C =================================================================== --- gcc/testsuite/g++.dg/template/sfinae6_neg.C (revision 189572) +++ gcc/testsuite/g++.dg/template/sfinae6_neg.C (working copy) @@ -14,7 +14,7 @@ template struct enable_if { template typename enable_if()(create_a(), create_a()), 1), yes_type>::type - check_is_callable2(type, type, type); // { dg-error "within this context" } + check_is_callable2(type, type, type); // { dg-error "within this context" "" { target c++98 } } 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); // { dg-error "is private" "" { target c++98 } } }; -STATIC_ASSERT((is_callable2::value)); +STATIC_ASSERT((!is_callable2::value)); Index: gcc/cp/init.c =================================================================== --- gcc/cp/init.c (revision 189561) +++ gcc/cp/init.c (working copy) @@ -1876,9 +1876,9 @@ build_offset_ref (tree type, tree member, bool add (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_error); else - perform_or_defer_access_check (basebinfo, t, t); + perform_or_defer_access_check (basebinfo, t, t, tf_error); if (DECL_STATIC_FUNCTION_P (t)) return t; @@ -1891,7 +1891,7 @@ build_offset_ref (tree type, tree member, bool add /* 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_error); if (!address_p) { Index: gcc/cp/class.c =================================================================== --- gcc/cp/class.c (revision 189561) +++ gcc/cp/class.c (working copy) @@ -1189,7 +1189,7 @@ 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_error); DECL_ACCESS (fdecl) = tree_cons (t, access, DECL_ACCESS (fdecl)); return 1; } @@ -7138,7 +7138,7 @@ resolve_address_of_overloaded_function (tree targe && 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_error); } if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type)) Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c (revision 189561) +++ gcc/cp/decl.c (working copy) @@ -3306,10 +3306,10 @@ make_typename_type (tree context, tree name, enum 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 template instantiation time. */ @@ -3378,8 +3378,9 @@ make_unbound_class_template (tree context, tree na 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_error); } else { @@ -10569,7 +10571,7 @@ local_variable_p_walkfn (tree *tp, int *walk_subtr DECL, if there is no DECL available. */ tree -check_default_argument (tree decl, tree arg) +check_default_argument (tree decl, tree arg, tsubst_flags_t complain) { tree var; tree decl_type; @@ -10602,15 +10604,17 @@ tree parameter type. */ if (!TREE_TYPE (arg) || !can_convert_arg (decl_type, TREE_TYPE (arg), arg, LOOKUP_NORMAL, - tf_warning_or_error)) + complain)) { - if (decl) - error ("default argument for %q#D has type %qT", - decl, TREE_TYPE (arg)); - else - error ("default argument for parameter of type %qT has type %qT", - decl_type, TREE_TYPE (arg)); - + if (complain & tf_error) + { + if (decl) + error ("default argument for %q#D has type %qT", + decl, TREE_TYPE (arg)); + else + error ("default argument for parameter of type %qT has type %qT", + decl_type, TREE_TYPE (arg)); + } return error_mark_node; } @@ -10620,8 +10624,9 @@ tree && null_ptr_cst_p (arg) && !NULLPTR_TYPE_P (TREE_TYPE (arg))) { - warning (OPT_Wzero_as_null_pointer_constant, - "zero as null pointer constant"); + if (complain & tf_warning) + warning (OPT_Wzero_as_null_pointer_constant, + "zero as null pointer constant"); return nullptr_node; } @@ -10635,10 +10640,14 @@ tree var = cp_walk_tree_without_duplicates (&arg, local_variable_p_walkfn, NULL); if (var) { - if (DECL_NAME (var) == this_identifier) - permerror (input_location, "default argument %qE uses %qD", arg, var); - else - error ("default argument %qE uses local variable %qD", arg, var); + if (complain & tf_error) + { + if (DECL_NAME (var) == this_identifier) + permerror (input_location, "default argument %qE uses %qD", + arg, var); + else + error ("default argument %qE uses local variable %qD", arg, var); + } return error_mark_node; } @@ -10789,7 +10798,7 @@ grokparms (tree parmlist, tree *parms) if (any_error) init = NULL_TREE; else if (init && !processing_template_decl) - init = check_default_argument (decl, init); + init = check_default_argument (decl, init, tf_warning_or_error); } DECL_CHAIN (decl) = decls; Index: gcc/cp/pt.c =================================================================== --- gcc/cp/pt.c (revision 189561) +++ gcc/cp/pt.c (working copy) @@ -181,7 +181,7 @@ static int coerce_template_template_parms (tree, t tree, tree); static bool template_template_parm_bindings_ok_p (tree, tree); static int template_args_equal (tree, tree); -static void tsubst_default_arguments (tree); +static void tsubst_default_arguments (tree, tsubst_flags_t); static tree for_each_template_parm_r (tree *, int *, void *); static tree copy_default_args_to_explicit_spec_1 (tree, tree); static void copy_default_args_to_explicit_spec (tree); @@ -8370,7 +8370,7 @@ perform_typedefs_access_check (tree tmpl, tree tar 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_error); } input_location = saved_location; } @@ -8877,7 +8877,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_error); pop_nested_class (); maximum_field_alignment = saved_maximum_field_alignment; if (!fn_context) @@ -9596,7 +9596,8 @@ tsubst_aggr_type (tree t, FN), which has the indicated TYPE. */ tree -tsubst_default_argument (tree fn, tree type, tree arg) +tsubst_default_argument (tree fn, tree type, tree arg, + tsubst_flags_t complain) { tree saved_class_ptr = NULL_TREE; tree saved_class_ref = NULL_TREE; @@ -9635,7 +9636,7 @@ tree stack. */ ++function_depth; arg = tsubst_expr (arg, DECL_TI_ARGS (fn), - tf_warning_or_error, NULL_TREE, + complain, NULL_TREE, /*integral_constant_expression_p=*/false); --function_depth; pop_deferring_access_checks(); @@ -9648,7 +9649,7 @@ tree } /* Make sure the default argument is reasonable. */ - arg = check_default_argument (type, arg); + arg = check_default_argument (type, arg, complain); pop_access_scope (fn); @@ -9658,7 +9659,7 @@ tree /* Substitute into all the default arguments for FN. */ static void -tsubst_default_arguments (tree fn) +tsubst_default_arguments (tree fn, tsubst_flags_t complain) { tree arg; tree tmpl_args; @@ -9679,7 +9680,8 @@ static void if (TREE_PURPOSE (arg)) TREE_PURPOSE (arg) = tsubst_default_argument (fn, TREE_VALUE (arg), - TREE_PURPOSE (arg)); + TREE_PURPOSE (arg), + complain); } /* Substitute the ARGS into the T, which is a _DECL. Return the @@ -9870,10 +9872,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t com hash = hash_tmpl_and_args (gen_tmpl, argvec); spec = retrieve_specialization (gen_tmpl, argvec, hash); + r = spec; if (spec) { - r = spec; - break; + if (FNDECL_RECHECK_ACCESS_P (spec) && (complain & tf_error)) + /* Reinstantiate to get access errors. */; + else + break; } /* We can see more levels of arguments than parameters if @@ -9949,6 +9954,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t com 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 @@ -10021,7 +10033,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t com if (!member && !PRIMARY_TEMPLATE_P (gen_tmpl) && !uses_template_parms (argvec)) - tsubst_default_arguments (r); + tsubst_default_arguments (r, complain); } else DECL_TEMPLATE_INFO (r) = NULL_TREE; @@ -14294,6 +14306,7 @@ instantiate_template_1 (tree tmpl, tree orig_args, tree fndecl; tree gen_tmpl; tree spec; + tree tmp = NULL_TREE; if (tmpl == error_mark_node) return error_mark_node; @@ -14341,7 +14354,13 @@ instantiate_template_1 (tree tmpl, tree orig_args, || fndecl == NULL_TREE); if (spec != NULL_TREE) - return spec; + { + if (FNDECL_RECHECK_ACCESS_P (spec) + && (complain & tf_error)) + /* Do the instantiation again, we're out of SFINAE context. */; + else + return spec; + } if (check_instantiated_args (gen_tmpl, INNERMOST_TEMPLATE_ARGS (targ_ptr), complain)) @@ -14380,7 +14399,8 @@ instantiate_template_1 (tree tmpl, tree orig_args, /* Now we know the specialization, compute access previously deferred. */ push_access_scope (fndecl); - perform_deferred_access_checks (); + if (!perform_deferred_access_checks (complain)) + tmp = error_mark_node; pop_access_scope (fndecl); pop_deferring_access_checks (); @@ -14391,6 +14411,16 @@ instantiate_template_1 (tree tmpl, tree orig_args, if (DECL_CHAIN (gen_tmpl) && DECL_CLONED_FUNCTION_P (DECL_CHAIN (gen_tmpl))) clone_function_decl (fndecl, /*update_method_vec_p=*/0); + if (tmp) + { + 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; } Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 189561) +++ gcc/cp/semantics.c (working copy) @@ -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_error); } else { @@ -254,23 +254,26 @@ pop_to_parent_deferring_access_checks (void) is the BINFO indicating the qualifying scope used to access the DECL node stored in the TREE_VALUE of the node. */ -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 tmp = 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); + tmp &= enforce_access (chk->binfo, chk->decl, chk->diag_decl, complain); } input_location = loc; + return (complain & tf_error) ? true : tmp; } /* Perform the deferred access checks. @@ -289,17 +292,18 @@ pop_to_parent_deferring_access_checks (void) We have to perform deferred access of `A::X', first with `A::a', next with `x'. */ -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. */ -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 +314,7 @@ pop_to_parent_deferring_access_checks (void) /* 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 +323,8 @@ pop_to_parent_deferring_access_checks (void) /* 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 tmp = enforce_access (binfo, decl, diag_decl, complain); + return (complain & tf_error) ? true : tmp; } /* See if we are already going to perform this check. */ @@ -330,7 +334,7 @@ pop_to_parent_deferring_access_checks (void) if (chk->decl == decl && chk->binfo == binfo && chk->diag_decl == diag_decl) { - return; + return true; } } /* If not, record the check. */ @@ -341,6 +345,8 @@ pop_to_parent_deferring_access_checks (void) new_access->decl = decl; new_access->diag_decl = diag_decl; new_access->loc = input_location; + + return true; } /* Used by build_over_call in LOOKUP_SPECULATIVE mode: return whether DECL @@ -349,7 +355,7 @@ pop_to_parent_deferring_access_checks (void) bool speculative_access_check (tree binfo, tree decl, tree diag_decl, - bool complain) + tsubst_flags_t complain) { if (deferred_access_no_check) return true; @@ -359,8 +365,8 @@ speculative_access_check (tree binfo, tree decl, t if (!accessible_p (binfo, decl, true)) { /* Unless we're under maybe_explain_implicit_delete. */ - if (complain) - enforce_access (binfo, decl, diag_decl); + if (complain & tf_error) + enforce_access (binfo, decl, diag_decl, tf_error); return false; } @@ -1611,7 +1617,7 @@ finish_non_static_data_member (tree decl, tree obj tree access_type = TREE_TYPE (object); perform_or_defer_access_check (TYPE_BINFO (access_type), decl, - decl); + decl, tf_error); /* If the data member was named `C::M', convert `*this' to `C' first. */ @@ -1733,7 +1739,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_error); } /* EXPR is the result of a qualified-id. The QUALIFYING_CLASS was the @@ -3336,7 +3342,7 @@ 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_error); } } Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 189561) +++ gcc/cp/parser.c (working copy) @@ -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_error); } /* Consume the `;'. */ @@ -12416,7 +12416,7 @@ 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_error); } /* Return the stored value. */ return check_value->value; @@ -15751,7 +15751,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 (true); /* Restore the saved value. */ if (TREE_CODE (decl) == FUNCTION_DECL) @@ -21017,7 +21017,7 @@ cp_parser_function_definition_from_specifiers_and_ 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_error); if (!success_p) { @@ -21311,7 +21311,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_error); --processing_template_parmlist; } @@ -21838,7 +21838,8 @@ cp_parser_late_parse_one_default_arg (cp_parser *p /* In a non-template class, check conversions now. In a template, we'll wait and instantiate these as needed. */ if (TREE_CODE (decl) == PARM_DECL) - parsed_arg = check_default_argument (parmtype, parsed_arg); + parsed_arg = check_default_argument (parmtype, parsed_arg, + tf_warning_or_error); else { int flags = LOOKUP_IMPLICIT; @@ -22760,7 +22761,7 @@ cp_parser_pre_parsed_nested_name_specifier (cp_par 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_error); } /* Set the scope from the stored value. */ parser->scope = check_value->value; @@ -24018,7 +24019,7 @@ cp_parser_objc_method_definition_list (cp_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_error); stop_deferring_access_checks (); meth = cp_parser_function_definition_after_declarator (parser, false); Index: gcc/cp/call.c =================================================================== --- gcc/cp/call.c (revision 189561) +++ gcc/cp/call.c (working copy) @@ -5515,7 +5515,8 @@ build_op_delete_call (enum tree_code code, tree ad /* 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 ad 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 (cxx_dialect < cxx0x || 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; } @@ -6267,7 +6272,7 @@ convert_default_arg (tree type, tree arg, tree fn, push_defarg_context (fn); if (fn && DECL_TEMPLATE_INFO (fn)) - arg = tsubst_default_argument (fn, type, arg); + arg = tsubst_default_argument (fn, type, arg, complain); /* Due to: @@ -6513,11 +6518,12 @@ build_over_call (struct z_candidate *cand, int fla if (flags & LOOKUP_SPECULATIVE) { if (!speculative_access_check (cand->access_path, access_fn, fn, - complain & tf_error)) + complain)) return error_mark_node; } - else - perform_or_defer_access_check (cand->access_path, access_fn, fn); + else 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 Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 189561) +++ gcc/cp/cp-tree.h (working copy) @@ -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 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; @@ -4901,7 +4910,8 @@ extern bool can_convert_arg (tree, tree, tree, i 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, @@ -5097,7 +5107,7 @@ extern tree static_fn_type (tree); extern void revert_static_member_fn (tree); extern void fixup_anonymous_aggr (tree); extern tree compute_array_index_type (tree, tree, tsubst_flags_t); -extern tree check_default_argument (tree, tree); +extern tree check_default_argument (tree, tree, tsubst_flags_t); typedef int (*walk_namespaces_fn) (tree, void *); extern int walk_namespaces (walk_namespaces_fn, void *); @@ -5364,7 +5374,8 @@ extern tree maybe_process_partial_specialization ( extern tree most_specialized_instantiation (tree); extern void print_candidates (tree); extern void instantiate_pending_templates (int); -extern tree tsubst_default_argument (tree, tree, tree); +extern tree tsubst_default_argument (tree, tree, tree, + tsubst_flags_t); extern tree tsubst (tree, tree, tsubst_flags_t, tree); extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t, tree, bool, bool); @@ -5497,10 +5508,13 @@ 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 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); Index: gcc/cp/search.c =================================================================== --- gcc/cp/search.c (revision 189561) +++ gcc/cp/search.c (working copy) @@ -1254,8 +1254,10 @@ lookup_member (tree xbasetype, tree name, int prot && !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) Index: gcc/cp/friend.c =================================================================== --- gcc/cp/friend.c (revision 189561) +++ gcc/cp/friend.c (working copy) @@ -166,7 +166,7 @@ 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_error); maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1);