From 89fcabafa13d82c44c87b745d08de04386c5b15f Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Wed, 18 Apr 2012 10:21:43 +0000 Subject: [PATCH] re PR c++/52422 ([C++11][SFINAE] Hard errors with void or arithmetic expressions) /cp 2012-04-18 Paolo Carlini PR c++/52422 * cp-tree.h (build_addr_func, decay_conversion, get_member_function_from_ptrfunc, build_m_component_ref, convert_member_func_to_ptr): Add tsubst_flags_t parameter. * typeck.c (cp_default_conversion): Add. (decay_conversion, default_conversion, get_member_function_from_ptrfunc, convert_member_func_to_ptr): Add tsubst_flags_t parameter and use it throughout. (cp_build_indirect_ref, cp_build_array_ref, cp_build_function_call_vec, convert_arguments, build_x_binary_op, cp_build_binary_op, cp_build_unary_op, build_reinterpret_cast_1, build_const_cast_1, expand_ptrmemfunc_cst, convert_for_initialization): Adjust. * init.c (build_vec_init): Adjust. * decl.c (grok_reference_init, get_atexit_node): Likewise. * rtti.c (build_dynamic_cast_1, tinfo_base_init): Likewise. * except.c (build_throw): Likewise. * typeck2.c (build_x_arrow): Likewise. (build_m_component_ref): Add tsubst_flags_t parameter and use it throughout. * pt.c (convert_nontype_argument): Adjust. * semantics.c (finish_asm_stmt, maybe_add_lambda_conv_op): Likewise. * decl2.c (build_offset_ref_call_from_tree): Likewise. * call.c (build_addr_func): Add tsubst_flags_t parameter and use it throughout. (build_call_a, build_conditional_expr_1, build_new_op_1, convert_like_real, convert_arg_to_ellipsis, build_over_call, build_special_member_call): Adjust. * cvt.c (cp_convert_to_pointer, force_rvalue, build_expr_type_conversion): Likewise. /testsuite 2012-04-18 Paolo Carlini PR c++/52422 * g++.dg/cpp0x/sfinae33.C: New. * g++.dg/cpp0x/sfinae34.C: Likewise. From-SVN: r186565 --- gcc/cp/ChangeLog | 34 ++++++ gcc/cp/call.c | 47 +++++--- gcc/cp/cp-tree.h | 10 +- gcc/cp/cvt.c | 12 +- gcc/cp/decl.c | 4 +- gcc/cp/decl2.c | 5 +- gcc/cp/except.c | 4 +- gcc/cp/init.c | 11 +- gcc/cp/pt.c | 10 +- gcc/cp/rtti.c | 5 +- gcc/cp/semantics.c | 4 +- gcc/cp/typeck.c | 153 +++++++++++++++++--------- gcc/cp/typeck2.c | 37 ++++--- gcc/testsuite/ChangeLog | 6 + gcc/testsuite/g++.dg/cpp0x/sfinae33.C | 27 +++++ gcc/testsuite/g++.dg/cpp0x/sfinae34.C | 27 +++++ 16 files changed, 288 insertions(+), 108 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/sfinae33.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/sfinae34.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8619b26e507..0be0be4b6a1 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,37 @@ +2012-04-18 Paolo Carlini + + PR c++/52422 + * cp-tree.h (build_addr_func, decay_conversion, + get_member_function_from_ptrfunc, + build_m_component_ref, convert_member_func_to_ptr): + Add tsubst_flags_t parameter. + * typeck.c (cp_default_conversion): Add. + (decay_conversion, default_conversion, + get_member_function_from_ptrfunc, convert_member_func_to_ptr): + Add tsubst_flags_t parameter and use it throughout. + (cp_build_indirect_ref, cp_build_array_ref, + cp_build_function_call_vec, convert_arguments, build_x_binary_op, + cp_build_binary_op, cp_build_unary_op, build_reinterpret_cast_1, + build_const_cast_1, expand_ptrmemfunc_cst, + convert_for_initialization): Adjust. + * init.c (build_vec_init): Adjust. + * decl.c (grok_reference_init, get_atexit_node): Likewise. + * rtti.c (build_dynamic_cast_1, tinfo_base_init): Likewise. + * except.c (build_throw): Likewise. + * typeck2.c (build_x_arrow): Likewise. + (build_m_component_ref): Add tsubst_flags_t parameter and + use it throughout. + * pt.c (convert_nontype_argument): Adjust. + * semantics.c (finish_asm_stmt, maybe_add_lambda_conv_op): Likewise. + * decl2.c (build_offset_ref_call_from_tree): Likewise. + * call.c (build_addr_func): Add tsubst_flags_t parameter and + use it throughout. + (build_call_a, build_conditional_expr_1, build_new_op_1, + convert_like_real, convert_arg_to_ellipsis, build_over_call, + build_special_member_call): Adjust. + * cvt.c (cp_convert_to_pointer, force_rvalue, + build_expr_type_conversion): Likewise. + 2012-04-17 Tom de Vries * cp-gimplify.c (begin_bc_block): Add location parameter and use as diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 06a12250e2c..6adf654278f 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -263,7 +263,7 @@ check_dtor_name (tree basetype, tree name) pointer-to-member function. */ tree -build_addr_func (tree function) +build_addr_func (tree function, tsubst_flags_t complain) { tree type = TREE_TYPE (function); @@ -275,12 +275,13 @@ build_addr_func (tree function) { tree object = build_address (TREE_OPERAND (function, 0)); return get_member_function_from_ptrfunc (&object, - TREE_OPERAND (function, 1)); + TREE_OPERAND (function, 1), + complain); } function = build_address (function); } else - function = decay_conversion (function); + function = decay_conversion (function, complain); return function; } @@ -341,7 +342,7 @@ build_call_a (tree function, int n, tree *argarray) tree fntype; int i; - function = build_addr_func (function); + function = build_addr_func (function, tf_warning_or_error); gcc_assert (TYPE_PTR_P (TREE_TYPE (function))); fntype = TREE_TYPE (TREE_TYPE (function)); @@ -4373,9 +4374,9 @@ build_conditional_expr_1 (tree arg1, tree arg2, tree arg3, since it can't have any effect and since decay_conversion does not handle that case gracefully. */ if (!VOID_TYPE_P (arg2_type)) - arg2 = decay_conversion (arg2); + arg2 = decay_conversion (arg2, complain); if (!VOID_TYPE_P (arg3_type)) - arg3 = decay_conversion (arg3); + arg3 = decay_conversion (arg3, complain); arg2_type = TREE_TYPE (arg2); arg3_type = TREE_TYPE (arg3); @@ -5263,7 +5264,7 @@ build_new_op_1 (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3, case MEMBER_REF: return build_m_component_ref (cp_build_indirect_ref (arg1, RO_NULL, complain), - arg2); + arg2, complain); /* The caller will deal with these. */ case ADDR_EXPR: @@ -5807,7 +5808,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, /* Build up the initializer_list object. */ totype = complete_type (totype); field = next_initializable_field (TYPE_FIELDS (totype)); - CONSTRUCTOR_APPEND_ELT (vec, field, decay_conversion (array)); + CONSTRUCTOR_APPEND_ELT (vec, field, decay_conversion (array, complain)); field = next_initializable_field (DECL_CHAIN (field)); CONSTRUCTOR_APPEND_ELT (vec, field, size_int (len)); new_ctor = build_constructor (totype, vec); @@ -5844,7 +5845,10 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, switch (convs->kind) { case ck_rvalue: - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); + if (expr == error_mark_node) + return error_mark_node; + if (! MAYBE_CLASS_TYPE_P (totype)) return expr; /* Else fall through. */ @@ -5970,7 +5974,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, } case ck_lvalue: - return decay_conversion (expr); + return decay_conversion (expr, complain); case ck_qual: /* Warn about deprecated conversion if appropriate. */ @@ -6014,7 +6018,7 @@ convert_arg_to_ellipsis (tree arg) The lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard conversions are performed. */ - arg = decay_conversion (arg); + arg = decay_conversion (arg, tf_warning_or_error); arg_type = TREE_TYPE (arg); /* [expr.call] @@ -6341,7 +6345,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) errors will be deferred until the template is instantiated. */ if (processing_template_decl) { - tree expr; + tree expr, addr; tree return_type; const tree *argarray; unsigned int nargs; @@ -6363,9 +6367,12 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) alcarray[ix + 1] = arg; argarray = alcarray; } - expr = build_call_array_loc (input_location, - return_type, build_addr_func (fn), nargs, - argarray); + + addr = build_addr_func (fn, complain); + if (addr == error_mark_node) + return error_mark_node; + expr = build_call_array_loc (input_location, return_type, + addr, nargs, argarray); if (TREE_THIS_VOLATILE (fn) && cfun) current_function_returns_abnormally = 1; return convert_from_reference (expr); @@ -6782,7 +6789,11 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) TREE_TYPE (fn) = t; } else - fn = build_addr_func (fn); + { + fn = build_addr_func (fn, complain); + if (fn == error_mark_node) + return error_mark_node; + } return build_cxx_call (fn, nargs, argarray); } @@ -7003,7 +7014,9 @@ build_special_member_call (tree instance, tree name, VEC(tree,gc) **args, or destructor, then we fetch the VTT directly. Otherwise, we look it up using the VTT we were given. */ vtt = DECL_CHAIN (CLASSTYPE_VTABLES (current_class_type)); - vtt = decay_conversion (vtt); + vtt = decay_conversion (vtt, complain); + if (vtt == error_mark_node) + return error_mark_node; vtt = build3 (COND_EXPR, TREE_TYPE (vtt), build2 (EQ_EXPR, boolean_type_node, current_in_charge_parm, integer_zero_node), diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index db5e8a5e084..284a634c906 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4854,7 +4854,7 @@ extern bool check_dtor_name (tree, tree); extern tree build_conditional_expr (tree, tree, tree, tsubst_flags_t); -extern tree build_addr_func (tree); +extern tree build_addr_func (tree, tsubst_flags_t); extern void set_flags_from_callee (tree); extern tree build_call_a (tree, int, tree*); extern tree build_call_n (tree, int, ...); @@ -5782,7 +5782,7 @@ extern tree cxx_sizeof_or_alignof_type (tree, enum tree_code, bool); extern tree cxx_sizeof_nowarn (tree); extern tree is_bitfield_expr_with_lowered_type (const_tree); extern tree unlowered_expr_type (const_tree); -extern tree decay_conversion (tree); +extern tree decay_conversion (tree, tsubst_flags_t); extern tree build_class_member_access_expr (tree, tree, tree, bool, tsubst_flags_t); extern tree finish_class_member_access_expr (tree, tree, bool, @@ -5794,7 +5794,7 @@ extern tree cp_build_indirect_ref (tree, ref_operator, extern tree build_array_ref (location_t, tree, tree); extern tree cp_build_array_ref (location_t, tree, tree, tsubst_flags_t); -extern tree get_member_function_from_ptrfunc (tree *, tree); +extern tree get_member_function_from_ptrfunc (tree *, tree, tsubst_flags_t); extern tree cp_build_function_call (tree, tree, tsubst_flags_t); extern tree cp_build_function_call_nary (tree, tsubst_flags_t, ...) ATTRIBUTE_SENTINEL; @@ -5865,7 +5865,7 @@ extern tree build_nop (tree, tree); extern tree non_reference (tree); extern tree lookup_anon_field (tree, tree); extern bool invalid_nonstatic_memfn_p (const_tree, tsubst_flags_t); -extern tree convert_member_func_to_ptr (tree, tree); +extern tree convert_member_func_to_ptr (tree, tree, tsubst_flags_t); extern tree convert_ptrmem (tree, tree, bool, bool, tsubst_flags_t); extern int lvalue_or_else (tree, enum lvalue_use, @@ -5895,7 +5895,7 @@ extern tree digest_init (tree, tree, tsubst_flags_t); extern tree digest_init_flags (tree, tree, int); extern tree build_scoped_ref (tree, tree, tree *); extern tree build_x_arrow (tree, tsubst_flags_t); -extern tree build_m_component_ref (tree, tree); +extern tree build_m_component_ref (tree, tree, tsubst_flags_t); extern tree build_functional_cast (tree, tree, tsubst_flags_t); extern tree add_exception_specifier (tree, tree, int); extern tree merge_exception_specifiers (tree, tree, tree); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 5694abede45..09a589efd02 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -1,7 +1,7 @@ /* Language-level data type conversion for GNU C++. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - 2011 Free Software Foundation, Inc. + 2011, 2012 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -109,7 +109,7 @@ cp_convert_to_pointer (tree type, tree expr) { if (TYPE_PTRMEMFUNC_P (intype) || TREE_CODE (intype) == METHOD_TYPE) - return convert_member_func_to_ptr (type, expr); + return convert_member_func_to_ptr (type, expr, tf_warning_or_error); if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE) return build_nop (type, expr); intype = TREE_TYPE (expr); @@ -188,7 +188,8 @@ cp_convert_to_pointer (tree type, tree expr) { tree object = TREE_OPERAND (expr, 0); return get_member_function_from_ptrfunc (&object, - TREE_OPERAND (expr, 1)); + TREE_OPERAND (expr, 1), + tf_warning_or_error); } } error ("cannot convert %qE from type %qT to type %qT", @@ -550,7 +551,7 @@ force_rvalue (tree expr, tsubst_flags_t complain) expr = build_cplus_new (type, expr, complain); } else - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); return expr; } @@ -1495,7 +1496,8 @@ build_expr_type_conversion (int desires, tree expr, bool complain) case FUNCTION_TYPE: case ARRAY_TYPE: - return (desires & WANT_POINTER) ? decay_conversion (expr) + return (desires & WANT_POINTER) ? decay_conversion (expr, + tf_warning_or_error) : NULL_TREE; case COMPLEX_TYPE: diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 711ceef7a8d..cfab4e20662 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4668,7 +4668,7 @@ grok_reference_init (tree decl, tree type, tree init, int flags) if (TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE) /* Note: default conversion is only called in very special cases. */ - init = decay_conversion (init); + init = decay_conversion (init, tf_warning_or_error); /* Convert INIT to the reference type TYPE. This may involve the creation of a temporary, whose lifetime must be the same as that @@ -6535,7 +6535,7 @@ get_atexit_node (void) atexit_fndecl = build_library_fn_ptr (name, fn_type); mark_used (atexit_fndecl); pop_lang_context (); - atexit_node = decay_conversion (atexit_fndecl); + atexit_node = decay_conversion (atexit_fndecl, tf_warning_or_error); return atexit_node; } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 90498ea2941..a190aee5d57 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1,7 +1,7 @@ /* Process declarations and variables for C++ compiler. Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, - 2011 Free Software Foundation, Inc. + 2011, 2012 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -4175,7 +4175,8 @@ build_offset_ref_call_from_tree (tree fn, VEC(tree,gc) **args) { tree object_addr = cp_build_addr_expr (object, tf_warning_or_error); fn = TREE_OPERAND (fn, 1); - fn = get_member_function_from_ptrfunc (&object_addr, fn); + fn = get_member_function_from_ptrfunc (&object_addr, fn, + tf_warning_or_error); VEC_safe_insert (tree, gc, *args, 0, object_addr); } diff --git a/gcc/cp/except.c b/gcc/cp/except.c index c56dc2c734b..d39cfa6abd3 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1,6 +1,6 @@ /* Handle exceptional things in C++. Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2012 Free Software Foundation, Inc. Contributed by Michael Tiemann Rewritten by Mike Stump , based upon an @@ -850,7 +850,7 @@ build_throw (tree exp) } else { - tmp = decay_conversion (exp); + tmp = decay_conversion (exp, tf_warning_or_error); if (tmp == error_mark_node) return error_mark_node; exp = build2 (INIT_EXPR, temp_type, object, tmp); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index bcb5ab7a23b..d4c357facd7 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1,7 +1,7 @@ /* Handle initialization things in C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - 2011 Free Software Foundation, Inc. + 2011, 2012 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -3194,7 +3194,10 @@ build_vec_init (tree base, tree maxindex, tree init, if (TREE_CODE (atype) == ARRAY_TYPE) { ptype = build_pointer_type (type); - base = cp_convert (ptype, decay_conversion (base)); + base = decay_conversion (base, complain); + if (base == error_mark_node) + return error_mark_node; + base = cp_convert (ptype, base); } else ptype = atype; @@ -3243,7 +3246,9 @@ build_vec_init (tree base, tree maxindex, tree init, { if (lvalue_kind (init) & clk_rvalueref) xvalue = true; - base2 = decay_conversion (init); + base2 = decay_conversion (init, complain); + if (base2 == error_mark_node) + return error_mark_node; itype = TREE_TYPE (base2); base2 = get_temp_regvar (itype, base2); itype = TREE_TYPE (itype); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 0ca6993b701..907e0c5fecd 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5692,7 +5692,11 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) value_dependent_expression_p. */ if (TYPE_PTROBV_P (type) && TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE) - expr = decay_conversion (expr); + { + expr = decay_conversion (expr, complain); + if (expr == error_mark_node) + return error_mark_node; + } /* If we are in a template, EXPR may be non-dependent, but still have a syntactic, rather than semantic, form. For example, EXPR @@ -5900,7 +5904,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) } } - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); if (expr == error_mark_node) return error_mark_node; @@ -5985,7 +5989,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) context information to decay the pointer. */ if (!type_unknown_p (expr_type)) { - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); if (expr == error_mark_node) return error_mark_node; } diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 2ca8fa511fa..92427648497 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -551,7 +551,7 @@ build_dynamic_cast_1 (tree type, tree expr, tsubst_flags_t complain) if (tc == POINTER_TYPE) { - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); exprtype = TREE_TYPE (expr); /* If T is a pointer type, v shall be an rvalue of a pointer to @@ -936,7 +936,8 @@ tinfo_base_init (tinfo_s *ti, tree target) v = VEC_alloc (constructor_elt, gc, 2); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, vtable_ptr); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, decay_conversion (name_decl)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + decay_conversion (name_decl, tf_warning_or_error)); init = build_constructor (init_list_type_node, v); TREE_CONSTANT (init) = 1; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 22185ea72ab..a621f25a4f4 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1382,7 +1382,7 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands, for (i = 0, t = input_operands; t; ++i, t = TREE_CHAIN (t)) { constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); - operand = decay_conversion (TREE_VALUE (t)); + operand = decay_conversion (TREE_VALUE (t), tf_warning_or_error); /* If the type of the operand hasn't been determined (e.g., because it involves an overloaded function), then issue @@ -9365,7 +9365,7 @@ maybe_add_lambda_conv_op (tree type) body = begin_function_body (); compound_stmt = begin_compound_stmt (0); - finish_return_stmt (decay_conversion (statfn)); + finish_return_stmt (decay_conversion (statfn, tf_warning_or_error)); finish_compound_stmt (compound_stmt); finish_function_body (body); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index d2ed940cbc0..01fea6f930c 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1818,7 +1818,7 @@ unlowered_expr_type (const_tree exp) that the return value is no longer an lvalue. */ tree -decay_conversion (tree exp) +decay_conversion (tree exp, tsubst_flags_t complain) { tree type; enum tree_code code; @@ -1832,7 +1832,8 @@ decay_conversion (tree exp) exp = resolve_nondeduced_context (exp); if (type_unknown_p (exp)) { - cxx_incomplete_type_error (exp, TREE_TYPE (exp)); + if (complain & tf_error) + cxx_incomplete_type_error (exp, TREE_TYPE (exp)); return error_mark_node; } @@ -1851,13 +1852,14 @@ decay_conversion (tree exp) code = TREE_CODE (type); if (code == VOID_TYPE) { - error ("void value not ignored as it ought to be"); + if (complain & tf_error) + error ("void value not ignored as it ought to be"); return error_mark_node; } - if (invalid_nonstatic_memfn_p (exp, tf_warning_or_error)) + if (invalid_nonstatic_memfn_p (exp, complain)) return error_mark_node; if (code == FUNCTION_TYPE || is_overloaded_fn (exp)) - return cp_build_addr_expr (exp, tf_warning_or_error); + return cp_build_addr_expr (exp, complain); if (code == ARRAY_TYPE) { tree adr; @@ -1869,7 +1871,9 @@ decay_conversion (tree exp) if (TREE_CODE (exp) == COMPOUND_EXPR) { - tree op1 = decay_conversion (TREE_OPERAND (exp, 1)); + tree op1 = decay_conversion (TREE_OPERAND (exp, 1), complain); + if (op1 == error_mark_node) + return error_mark_node; return build2 (COMPOUND_EXPR, TREE_TYPE (op1), TREE_OPERAND (exp, 0), op1); } @@ -1877,7 +1881,8 @@ decay_conversion (tree exp) if (!lvalue_p (exp) && ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp))) { - error ("invalid use of non-lvalue array"); + if (complain & tf_error) + error ("invalid use of non-lvalue array"); return error_mark_node; } @@ -1892,7 +1897,7 @@ decay_conversion (tree exp) } /* This way is better for a COMPONENT_REF since it can simplify the offset for a component. */ - adr = cp_build_addr_expr (exp, tf_warning_or_error); + adr = cp_build_addr_expr (exp, complain); return cp_convert (ptrtype, adr); } @@ -1931,8 +1936,8 @@ decay_conversion (tree exp) applied to both operands to a binary operator before determining what additional conversions should apply. */ -tree -default_conversion (tree exp) +static tree +cp_default_conversion (tree exp, tsubst_flags_t complain) { /* Check for target-specific promotions. */ tree promoted_type = targetm.promoted_type (TREE_TYPE (exp)); @@ -1944,11 +1949,19 @@ default_conversion (tree exp) else if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (exp))) exp = perform_integral_promotions (exp); /* Perform the other conversions. */ - exp = decay_conversion (exp); + exp = decay_conversion (exp, complain); return exp; } +/* C version. */ + +tree +default_conversion (tree exp) +{ + return cp_default_conversion (exp, tf_warning_or_error); +} + /* EXPR is an expression with an integral or enumeration type. Perform the integral promotions in [conv.prom], and return the converted value. */ @@ -2758,14 +2771,14 @@ cp_build_indirect_ref (tree ptr, ref_operator errorstring, { tree pointer, type; - if (ptr == error_mark_node) - return error_mark_node; - if (ptr == current_class_ptr) return current_class_ref; pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE - ? ptr : decay_conversion (ptr)); + ? ptr : decay_conversion (ptr, complain)); + if (pointer == error_mark_node) + return error_mark_node; + type = TREE_TYPE (pointer); if (POINTER_TYPE_P (type)) @@ -2982,8 +2995,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx, } { - tree ar = default_conversion (array); - tree ind = default_conversion (idx); + tree ar = cp_default_conversion (array, complain); + tree ind = cp_default_conversion (idx, complain); /* Put the integer in IND to simplify error checking. */ if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE) @@ -2993,8 +3006,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx, ind = temp; } - if (ar == error_mark_node) - return ar; + if (ar == error_mark_node || ind == error_mark_node) + return error_mark_node; if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE) { @@ -3040,7 +3053,8 @@ build_array_ref (location_t loc, tree array, tree idx) later has the right member. */ tree -get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) +get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function, + tsubst_flags_t complain) { if (TREE_CODE (function) == OFFSET_REF) function = TREE_OPERAND (function, 1); @@ -3059,13 +3073,14 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) /* Extracting the function address from a pmf is only allowed with -Wno-pmf-conversions. It only works for pmf constants. */ - e1 = build_addr_func (PTRMEM_CST_MEMBER (function)); + e1 = build_addr_func (PTRMEM_CST_MEMBER (function), complain); e1 = convert (fntype, e1); return e1; } else { - error ("object missing in use of %qE", function); + if (complain & tf_error) + error ("object missing in use of %qE", function); return error_mark_node; } } @@ -3085,25 +3100,32 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) case ptrmemfunc_vbit_in_pfn: e1 = cp_build_binary_op (input_location, BIT_AND_EXPR, idx, integer_one_node, - tf_warning_or_error); + complain); idx = cp_build_binary_op (input_location, MINUS_EXPR, idx, integer_one_node, - tf_warning_or_error); + complain); + if (idx == error_mark_node) + return error_mark_node; break; case ptrmemfunc_vbit_in_delta: e1 = cp_build_binary_op (input_location, BIT_AND_EXPR, delta, integer_one_node, - tf_warning_or_error); + complain); delta = cp_build_binary_op (input_location, RSHIFT_EXPR, delta, integer_one_node, - tf_warning_or_error); + complain); + if (delta == error_mark_node) + return error_mark_node; break; default: gcc_unreachable (); } + if (e1 == error_mark_node) + return error_mark_node; + /* Convert down to the right base before using the instance. A special case is that in a pointer to member of class C, C may be incomplete. In that case, the function will of course be @@ -3117,7 +3139,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) basetype = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)), basetype, ba_check, NULL); instance_ptr = build_base_path (PLUS_EXPR, instance_ptr, basetype, - 1, tf_warning_or_error); + 1, complain); if (instance_ptr == error_mark_node) return error_mark_node; } @@ -3130,7 +3152,10 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) /* Next extract the vtable pointer from the object. */ vtbl = build1 (NOP_EXPR, build_pointer_type (vtbl_ptr_type_node), instance_ptr); - vtbl = cp_build_indirect_ref (vtbl, RO_NULL, tf_warning_or_error); + vtbl = cp_build_indirect_ref (vtbl, RO_NULL, complain); + if (vtbl == error_mark_node) + return error_mark_node; + /* If the object is not dynamic the access invokes undefined behavior. As it is not executed in this case silence the spurious warnings it may provoke. */ @@ -3138,17 +3163,21 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) /* Finally, extract the function pointer from the vtable. */ e2 = fold_build_pointer_plus_loc (input_location, vtbl, idx); - e2 = cp_build_indirect_ref (e2, RO_NULL, tf_warning_or_error); + e2 = cp_build_indirect_ref (e2, RO_NULL, complain); + if (e2 == error_mark_node) + return error_mark_node; TREE_CONSTANT (e2) = 1; /* When using function descriptors, the address of the vtable entry is treated as a function pointer. */ if (TARGET_VTABLE_USES_DESCRIPTORS) e2 = build1 (NOP_EXPR, TREE_TYPE (e2), - cp_build_addr_expr (e2, tf_warning_or_error)); + cp_build_addr_expr (e2, complain)); e2 = fold_convert (TREE_TYPE (e3), e2); - e1 = build_conditional_expr (e1, e2, e3, tf_warning_or_error); + e1 = build_conditional_expr (e1, e2, e3, complain); + if (e1 == error_mark_node) + return error_mark_node; /* Make sure this doesn't get evaluated first inside one of the branches of the COND_EXPR. */ @@ -3261,13 +3290,13 @@ cp_build_function_call_vec (tree function, VEC(tree,gc) **params, pedwarn (input_location, OPT_pedantic, "ISO C++ forbids calling %<::main%> from within program"); - function = build_addr_func (function); + function = build_addr_func (function, complain); } else { fndecl = NULL_TREE; - function = build_addr_func (function); + function = build_addr_func (function, complain); } if (function == error_mark_node) @@ -3432,7 +3461,7 @@ convert_arguments (tree typelist, VEC(tree,gc) **values, tree fndecl, if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE) - val = decay_conversion (val); + val = decay_conversion (val, complain); } if (val == error_mark_node) @@ -3559,7 +3588,7 @@ build_x_binary_op (enum tree_code code, tree arg1, enum tree_code arg1_code, } if (code == DOTSTAR_EXPR) - expr = build_m_component_ref (arg1, arg2); + expr = build_m_component_ref (arg1, arg2, complain); else expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE, overload, complain); @@ -3723,16 +3752,16 @@ cp_build_binary_op (location_t location, || code == TRUTH_XOR_EXPR) { if (!really_overloaded_fn (op0) && !VOID_TYPE_P (TREE_TYPE (op0))) - op0 = decay_conversion (op0); + op0 = decay_conversion (op0, complain); if (!really_overloaded_fn (op1) && !VOID_TYPE_P (TREE_TYPE (op1))) - op1 = decay_conversion (op1); + op1 = decay_conversion (op1, complain); } else { if (!really_overloaded_fn (op0) && !VOID_TYPE_P (TREE_TYPE (op0))) - op0 = default_conversion (op0); + op0 = cp_default_conversion (op0, complain); if (!really_overloaded_fn (op1) && !VOID_TYPE_P (TREE_TYPE (op1))) - op1 = default_conversion (op1); + op1 = cp_default_conversion (op1, complain); } /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ @@ -5129,7 +5158,11 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert, { code = CONJ_EXPR; if (!noconvert) - arg = default_conversion (arg); + { + arg = cp_default_conversion (arg, complain); + if (arg == error_mark_node) + return error_mark_node; + } } else if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM | WANT_VECTOR_OR_COMPLEX, @@ -5143,7 +5176,11 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert, if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true))) errstring = _("wrong type argument to abs"); else if (!noconvert) - arg = default_conversion (arg); + { + arg = cp_default_conversion (arg, complain); + if (arg == error_mark_node) + return error_mark_node; + } break; case CONJ_EXPR: @@ -5151,7 +5188,11 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert, if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true))) errstring = _("wrong type argument to conjugation"); else if (!noconvert) - arg = default_conversion (arg); + { + arg = cp_default_conversion (arg, complain); + if (arg == error_mark_node) + return error_mark_node; + } break; case TRUTH_NOT_EXPR: @@ -6129,7 +6170,7 @@ build_static_cast (tree type, tree expr, tsubst_flags_t complain) converted expression. */ tree -convert_member_func_to_ptr (tree type, tree expr) +convert_member_func_to_ptr (tree type, tree expr, tsubst_flags_t complain) { tree intype; tree decl; @@ -6138,21 +6179,27 @@ convert_member_func_to_ptr (tree type, tree expr) gcc_assert (TYPE_PTRMEMFUNC_P (intype) || TREE_CODE (intype) == METHOD_TYPE); + if (!(complain & tf_warning_or_error)) + return error_mark_node; + if (pedantic || warn_pmf2ptr) pedwarn (input_location, pedantic ? OPT_pedantic : OPT_Wpmf_conversions, "converting from %qT to %qT", intype, type); if (TREE_CODE (intype) == METHOD_TYPE) - expr = build_addr_func (expr); + expr = build_addr_func (expr, complain); else if (TREE_CODE (expr) == PTRMEM_CST) expr = build_address (PTRMEM_CST_MEMBER (expr)); else { decl = maybe_dummy_object (TYPE_PTRMEM_CLASS_TYPE (intype), 0); decl = build_address (decl); - expr = get_member_function_from_ptrfunc (&decl, expr); + expr = get_member_function_from_ptrfunc (&decl, expr, complain); } + if (expr == error_mark_node) + return error_mark_node; + return build_nop (type, expr); } @@ -6230,12 +6277,12 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, && TYPE_PTR_P (type) && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE || VOID_TYPE_P (TREE_TYPE (type)))) - return convert_member_func_to_ptr (type, expr); + return convert_member_func_to_ptr (type, expr, complain); /* If the cast is not to a reference type, the lvalue-to-rvalue, array-to-pointer, and function-to-pointer conversions are performed. */ - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */ @@ -6474,12 +6521,17 @@ build_const_cast_1 (tree dst_type, tree expr, tsubst_flags_t complain, if (reference_type) { expr = cp_build_addr_expr (expr, complain); + if (expr == error_mark_node) + return error_mark_node; expr = build_nop (reference_type, expr); return convert_from_reference (expr); } else { - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); + if (expr == error_mark_node) + return error_mark_node; + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */ @@ -7333,7 +7385,8 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn) /*c_cast_p=*/0, tf_warning_or_error); if (!DECL_VIRTUAL_P (fn)) - *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn)); + *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), + build_addr_func (fn, tf_warning_or_error)); else { /* If we're dealing with a virtual function, we have to adjust 'this' @@ -7667,7 +7720,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags, && (TREE_CODE (type) != REFERENCE_TYPE || TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)) || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE) - rhs = decay_conversion (rhs); + rhs = decay_conversion (rhs, complain); rhstype = TREE_TYPE (rhs); coder = TREE_CODE (rhstype); diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index f9b525cba40..af72851a2ef 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1,7 +1,8 @@ /* Report error messages, build initializers, and perform some front-end optimizations for C++ compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) @@ -1528,7 +1529,7 @@ build_x_arrow (tree expr, tsubst_flags_t complain) last_rval = convert_from_reference (last_rval); } else - last_rval = decay_conversion (expr); + last_rval = decay_conversion (expr, complain); if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE) { @@ -1557,7 +1558,7 @@ build_x_arrow (tree expr, tsubst_flags_t complain) already been checked out to be of aggregate type. */ tree -build_m_component_ref (tree datum, tree component) +build_m_component_ref (tree datum, tree component, tsubst_flags_t complain) { tree ptrmem_type; tree objtype; @@ -1574,18 +1575,18 @@ build_m_component_ref (tree datum, tree component) ptrmem_type = TREE_TYPE (component); if (!TYPE_PTR_TO_MEMBER_P (ptrmem_type)) { - error ("%qE cannot be used as a member pointer, since it is of " - "type %qT", - component, ptrmem_type); + if (complain & tf_error) + error ("%qE cannot be used as a member pointer, since it is of " + "type %qT", component, ptrmem_type); return error_mark_node; } objtype = TYPE_MAIN_VARIANT (TREE_TYPE (datum)); if (! MAYBE_CLASS_TYPE_P (objtype)) { - error ("cannot apply member pointer %qE to %qE, which is of " - "non-class type %qT", - component, datum, objtype); + if (complain & tf_error) + error ("cannot apply member pointer %qE to %qE, which is of " + "non-class type %qT", component, datum, objtype); return error_mark_node; } @@ -1605,9 +1606,9 @@ build_m_component_ref (tree datum, tree component) if (!binfo) { mismatch: - error ("pointer to member type %qT incompatible with object " - "type %qT", - type, objtype); + if (complain & tf_error) + error ("pointer to member type %qT incompatible with object " + "type %qT", type, objtype); return error_mark_node; } else if (binfo == error_mark_node) @@ -1631,14 +1632,20 @@ build_m_component_ref (tree datum, tree component) /* Convert object to the correct base. */ if (binfo) - datum = build_base_path (PLUS_EXPR, datum, binfo, 1, - tf_warning_or_error); + { + datum = build_base_path (PLUS_EXPR, datum, binfo, 1, complain); + if (datum == error_mark_node) + return error_mark_node; + } /* Build an expression for "object + offset" where offset is the value stored in the pointer-to-data-member. */ ptype = build_pointer_type (type); datum = fold_build_pointer_plus (fold_convert (ptype, datum), component); - datum = cp_build_indirect_ref (datum, RO_NULL, tf_warning_or_error); + datum = cp_build_indirect_ref (datum, RO_NULL, complain); + if (datum == error_mark_node) + return error_mark_node; + /* If the object expression was an rvalue, return an rvalue. */ if (!is_lval) datum = move (datum); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7750484e804..fba4c22ee6a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2012-04-18 Paolo Carlini + + PR c++/52422 + * g++.dg/cpp0x/sfinae33.C: New. + * g++.dg/cpp0x/sfinae34.C: Likewise. + 2012-04-18 Joey Ye * gcc.target/arm/thumb1-imm.c: Skip it in non-thumb1 target. diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae33.C b/gcc/testsuite/g++.dg/cpp0x/sfinae33.C new file mode 100644 index 00000000000..3a5e6f77dfb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae33.C @@ -0,0 +1,27 @@ +// PR c++/52422 +// { dg-options -std=c++11 } + +template +struct add_rval_ref +{ + typedef T&& type; +}; + +template<> +struct add_rval_ref +{ + typedef void type; +}; + +template +typename add_rval_ref::type create(); + +template()()) +> +auto f(int) -> char(&)[1]; + +template +auto f(...) -> char(&)[2]; + +static_assert(sizeof(f(0)) != 1, ""); diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae34.C b/gcc/testsuite/g++.dg/cpp0x/sfinae34.C new file mode 100644 index 00000000000..d5d1ca4646b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae34.C @@ -0,0 +1,27 @@ +// PR c++/52422 +// { dg-options -std=c++11 } + +template +struct add_rval_ref +{ + typedef T&& type; +}; + +template<> +struct add_rval_ref +{ + typedef void type; +}; + +template +typename add_rval_ref::type create(); + +template().*create())() ) +> +auto f(int) -> char(&)[1]; + +template +auto f(...) -> char(&)[2]; + +static_assert(sizeof(f(0)) != 1, "");