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
This commit is contained in:
Paolo Carlini 2012-07-19 01:36:50 +00:00 committed by Jason Merrill
parent 1936ace05c
commit 0e69fdf016
20 changed files with 278 additions and 125 deletions

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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);

View File

@ -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
{

View File

@ -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);

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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");

View File

@ -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);
}

View File

@ -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" }
}

View File

@ -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));

View File

@ -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));

View File

@ -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

View File

@ -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;
}