diff options
author | Paolo Carlini <paolo.carlini@oracle.com> | 2012-07-19 01:36:50 +0000 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2012-07-18 21:36:50 -0400 |
commit | 0e69fdf016311cb8570c43d8ec67e9d5cb2f2aeb (patch) | |
tree | d39c6d48e17f0d85751becc5f496f94737ead16b | |
parent | 1936ace05cdfab4a25242e03c2d70921f00576cb (diff) | |
download | gcc-0e69fdf016311cb8570c43d8ec67e9d5cb2f2aeb.zip gcc-0e69fdf016311cb8570c43d8ec67e9d5cb2f2aeb.tar.gz gcc-0e69fdf016311cb8570c43d8ec67e9d5cb2f2aeb.tar.bz2 |
DR 1170 PR c++/51213
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.
Co-Authored-By: Jason Merrill <jason@redhat.com>
From-SVN: r189639
-rw-r--r-- | gcc/cp/ChangeLog | 18 | ||||
-rw-r--r-- | gcc/cp/call.c | 34 | ||||
-rw-r--r-- | gcc/cp/class.c | 6 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 25 | ||||
-rw-r--r-- | gcc/cp/decl.c | 14 | ||||
-rw-r--r-- | gcc/cp/friend.c | 3 | ||||
-rw-r--r-- | gcc/cp/init.c | 9 | ||||
-rw-r--r-- | gcc/cp/method.c | 2 | ||||
-rw-r--r-- | gcc/cp/parser.c | 15 | ||||
-rw-r--r-- | gcc/cp/pt.c | 47 | ||||
-rw-r--r-- | gcc/cp/search.c | 6 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 70 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/sfinae37.C | 22 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/access23.C | 16 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/access7.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/sfinae10.C | 55 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/sfinae6_neg.C | 6 | ||||
-rw-r--r-- | libstdc++-v3/ChangeLog | 5 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/pair/noncopyable.cc | 39 |
20 files changed, 278 insertions, 125 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8865db3..5cc6ccd 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2012-07-18 Paolo Carlini <paolo.carlini@oracle.com> + Jason Merrill <jason@redhat.com> + + 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. + 2012-07-18 Jason Merrill <jason@redhat.com> * method.c (process_subob_fn): Make sure no_implicit_p is non-null 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/ChangeLog b/gcc/testsuite/ChangeLog index c50e716..32ed483 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2012-07-18 Paolo Carlini <paolo.carlini@oracle.com> + Jason Merrill <jason@redhat.com> + + * g++.dg/cpp0x/sfinae37.C: New. + * g++.dg/template/access23.C: New. + * g++.dg/template/access7.C: Adjust. + * g++.dg/template/sfinae10.C: Don't expect errors. + * g++.dg/template/sfinae6_neg.C: Don't expect errors. + 2012-07-18 Julian Brown <julian@codesourcery.com> Sandra Loosemore <sandra@codesroucery.com> 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..054cf920 --- /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/ChangeLog b/libstdc++-v3/ChangeLog index 06b7ca8..f9dd6c7 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,8 @@ +2012-07-18 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/51213 + * testsuite/20_util/pair/noncopyable.cc: New. + 2012-07-16 Jonathan Wakely <jwakely.gcc@gmail.com> PR libstdc++/53270 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; +} |