diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 37553c53c58..42d8b1729b0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,25 @@ +2010-09-27 Jason Merrill + + Require lvalues as specified by the standard. + * typeck.c (lvalue_or_else): Use real_lvalue_p. + (cp_build_addr_expr_1): Split out of cp_build_unary_op. + (cp_build_addr_expr, cp_build_addr_expr_strict): Interfaces. + (decay_conversion, get_member_function_from_ptrfunc): Adjust. + (build_x_unary_op, build_reinterpret_cast_1): Adjust. + (build_const_cast_1): Adjust. + * cp-tree.h: Declare new fns. + * call.c (build_this, convert_like_real, build_over_call): Adjust. + (initialize_reference): Adjust. + * class.c (build_base_path, convert_to_base_statically): Adjust. + (build_vfn_ref, resolve_address_of_overloaded_function): Adjust. + * cvt.c (build_up_reference, convert_to_reference): Adjust. + * decl.c (register_dtor_fn): Adjust. + * decl2.c (build_offset_ref_call_from_tree): Adjust. + * except.c (initialize_handler_parm): Adjust. + * init.c (build_offset_ref, build_delete, build_vec_delete): Adjust. + * rtti.c (build_dynamic_cast_1, tinfo_base_init): Adjust. + * tree.c (stabilize_expr): Adjust. + 2010-09-27 Nicola Pero Merge from apple/trunk branch on FSF servers: diff --git a/gcc/cp/call.c b/gcc/cp/call.c index c3a579929c3..2e7083d45fd 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -2740,7 +2740,7 @@ build_this (tree obj) if (processing_template_decl) return build_address (obj); - return cp_build_unary_op (ADDR_EXPR, obj, 0, tf_warning_or_error); + return cp_build_addr_expr (obj, tf_warning_or_error); } /* Returns true iff functions are equivalent. Equivalent functions are @@ -5157,7 +5157,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, /* We are going to bind a reference directly to a base-class subobject of EXPR. */ /* Build an expression for `*((base*) &expr)'. */ - expr = cp_build_unary_op (ADDR_EXPR, expr, 0, complain); + expr = cp_build_addr_expr (expr, complain); expr = convert_to_base (expr, build_pointer_type (totype), !c_cast_p, /*nonnull=*/true, complain); expr = cp_build_indirect_ref (expr, RO_IMPLICIT_CONVERSION, complain); @@ -5206,8 +5206,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, VA_ARG_EXPR and CONSTRUCTOR expressions are special cases that need temporaries, even when their types are reference compatible with the type of reference being bound, so the - upcoming call to cp_build_unary_op (ADDR_EXPR, expr, ...) - doesn't fail. */ + upcoming call to cp_build_addr_expr doesn't fail. */ if (convs->need_temporary_p || TREE_CODE (expr) == CONSTRUCTOR || TREE_CODE (expr) == VA_ARG_EXPR) @@ -5264,7 +5263,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, /* Take the address of the thing to which we will bind the reference. */ - expr = cp_build_unary_op (ADDR_EXPR, expr, 1, complain); + expr = cp_build_addr_expr (expr, complain); if (expr == error_mark_node) return error_mark_node; @@ -6011,7 +6010,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) arg2 = TYPE_SIZE_UNIT (as_base); arg1 = arg; - arg0 = cp_build_unary_op (ADDR_EXPR, to, 0, complain); + arg0 = cp_build_addr_expr (to, complain); if (!can_trust_pointer_alignment ()) { @@ -7994,7 +7993,7 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup, } else /* Take the address of EXPR. */ - expr = cp_build_unary_op (ADDR_EXPR, expr, 0, tf_warning_or_error); + expr = cp_build_addr_expr (expr, tf_warning_or_error); /* If a BASE_CONV was required, perform it now. */ if (base_conv_type) expr = (perform_implicit_conversion diff --git a/gcc/cp/class.c b/gcc/cp/class.c index c594d6add33..b093ce0fcc5 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -282,7 +282,7 @@ build_base_path (enum tree_code code, if (!want_pointer) /* This must happen before the call to save_expr. */ - expr = cp_build_unary_op (ADDR_EXPR, expr, 0, tf_warning_or_error); + expr = cp_build_addr_expr (expr, tf_warning_or_error); else expr = mark_rvalue_use (expr); @@ -557,8 +557,7 @@ convert_to_base_statically (tree expr, tree base) when processing a template because they do not handle C++-specific trees. */ gcc_assert (!processing_template_decl); - expr = cp_build_unary_op (ADDR_EXPR, expr, /*noconvert=*/1, - tf_warning_or_error); + expr = cp_build_addr_expr (expr, tf_warning_or_error); if (!integer_zerop (BINFO_OFFSET (base))) expr = fold_build2_loc (input_location, POINTER_PLUS_EXPR, pointer_type, expr, @@ -661,8 +660,7 @@ build_vfn_ref (tree instance_ptr, tree idx) vtable entry is treated as a function pointer. */ if (TARGET_VTABLE_USES_DESCRIPTORS) aref = build1 (NOP_EXPR, TREE_TYPE (aref), - cp_build_unary_op (ADDR_EXPR, aref, /*noconvert=*/1, - tf_warning_or_error)); + cp_build_addr_expr (aref, tf_warning_or_error)); /* Remember this as a method reference, for later devirtualization. */ aref = build3 (OBJ_TYPE_REF, TREE_TYPE (aref), aref, instance_ptr, idx); @@ -6464,7 +6462,7 @@ resolve_address_of_overloaded_function (tree target_type, } if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type)) - return cp_build_unary_op (ADDR_EXPR, fn, 0, flags); + return cp_build_addr_expr (fn, flags); else { /* The target must be a REFERENCE_TYPE. Above, cp_build_unary_op diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index c78beb7c2f1..2ff0973d691 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5472,6 +5472,8 @@ extern tree build_x_binary_op (enum tree_code, tree, extern tree build_x_array_ref (tree, tree, tsubst_flags_t); extern tree build_x_unary_op (enum tree_code, tree, tsubst_flags_t); +extern tree cp_build_addr_expr (tree, tsubst_flags_t); +extern tree cp_build_addr_expr_strict (tree, tsubst_flags_t); extern tree cp_build_unary_op (enum tree_code, tree, int, tsubst_flags_t); extern tree unary_complex_lvalue (enum tree_code, tree); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index ab2b6bf2d70..00aa44aaa60 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -327,7 +327,7 @@ build_up_reference (tree type, tree arg, int flags, tree decl) /* If we had a way to wrap this up, and say, if we ever needed its address, transform all occurrences of the register, into a memory reference we could win better. */ - rval = cp_build_unary_op (ADDR_EXPR, arg, 1, tf_warning_or_error); + rval = cp_build_addr_expr (arg, tf_warning_or_error); if (rval == error_mark_node) return error_mark_node; @@ -471,7 +471,7 @@ convert_to_reference (tree reftype, tree expr, int convtype, warning (0, "casting %qT to %qT does not dereference pointer", intype, reftype); - rval = cp_build_unary_op (ADDR_EXPR, expr, 0, tf_warning_or_error); + rval = cp_build_addr_expr (expr, tf_warning_or_error); if (rval != error_mark_node) rval = convert_force (build_pointer_type (TREE_TYPE (reftype)), rval, 0); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 07eddb551df..18367b5e9db 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6354,8 +6354,8 @@ register_dtor_fn (tree decl) in, and, in general, it's cheaper to pass NULL than any other value. */ addr = null_pointer_node; - arg2 = cp_build_unary_op (ADDR_EXPR, get_dso_handle_node (), 0, - tf_warning_or_error); + arg2 = cp_build_addr_expr (get_dso_handle_node (), + tf_warning_or_error); if (targetm.cxx.use_aeabi_atexit ()) { arg1 = cleanup; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 63197705b32..fcc83fb66ba 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -4009,7 +4009,7 @@ build_offset_ref_call_from_tree (tree fn, VEC(tree,gc) **args) make_args_non_dependent (*args); object = build_non_dependent_expr (object); if (TREE_CODE (fn) == DOTSTAR_EXPR) - object = cp_build_unary_op (ADDR_EXPR, object, 0, tf_warning_or_error); + object = cp_build_addr_expr (object, tf_warning_or_error); VEC_safe_insert (tree, gc, *args, 0, object); /* Now that the arguments are done, transform FN. */ fn = build_non_dependent_expr (fn); @@ -4023,8 +4023,7 @@ build_offset_ref_call_from_tree (tree fn, VEC(tree,gc) **args) void B::g() { (this->*p)(); } */ if (TREE_CODE (fn) == OFFSET_REF) { - tree object_addr = cp_build_unary_op (ADDR_EXPR, object, 0, - tf_warning_or_error); + 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); VEC_safe_insert (tree, gc, *args, 0, object_addr); diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 351e685a687..9d19aa984fd 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -376,7 +376,7 @@ initialize_handler_parm (tree decl, tree exp) pointer catch parm with the address of the temporary. */ if (TREE_CODE (init_type) == REFERENCE_TYPE && TYPE_PTR_P (TREE_TYPE (init_type))) - exp = cp_build_unary_op (ADDR_EXPR, exp, 1, tf_warning_or_error); + exp = cp_build_addr_expr (exp, tf_warning_or_error); exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 189bcbec9a5..5091d4e749e 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1649,8 +1649,7 @@ build_offset_ref (tree type, tree member, bool address_p) if (flag_ms_extensions) { PTRMEM_OK_P (member) = 1; - return cp_build_unary_op (ADDR_EXPR, member, 0, - tf_warning_or_error); + return cp_build_addr_expr (member, tf_warning_or_error); } error ("invalid use of non-static member function %qD", TREE_OPERAND (member, 1)); @@ -3246,7 +3245,7 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, /* Don't check PROTECT here; leave that decision to the destructor. If the destructor is accessible, call it, else report error. */ - addr = cp_build_unary_op (ADDR_EXPR, addr, 0, tf_warning_or_error); + addr = cp_build_addr_expr (addr, tf_warning_or_error); if (TREE_SIDE_EFFECTS (addr)) addr = save_expr (addr); @@ -3486,7 +3485,7 @@ build_vec_delete (tree base, tree maxindex, bad name. */ maxindex = array_type_nelts_total (type); type = strip_array_types (type); - base = cp_build_unary_op (ADDR_EXPR, base, 1, tf_warning_or_error); + base = cp_build_addr_expr (base, tf_warning_or_error); if (TREE_SIDE_EFFECTS (base)) { base_init = get_target_expr (base); diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index c994683aae8..d7a151dec1f 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -693,10 +693,10 @@ build_dynamic_cast_1 (tree type, tree expr, tsubst_flags_t complain) static_type = TYPE_MAIN_VARIANT (TREE_TYPE (exprtype)); td2 = get_tinfo_decl (target_type); mark_used (td2); - td2 = cp_build_unary_op (ADDR_EXPR, td2, 0, complain); + td2 = cp_build_addr_expr (td2, complain); td3 = get_tinfo_decl (static_type); mark_used (td3); - td3 = cp_build_unary_op (ADDR_EXPR, td3, 0, complain); + td3 = cp_build_addr_expr (td3, complain); /* Determine how T and V are related. */ boff = dcast_base_hint (static_type, target_type); @@ -706,7 +706,7 @@ build_dynamic_cast_1 (tree type, tree expr, tsubst_flags_t complain) expr1 = expr; if (tc == REFERENCE_TYPE) - expr1 = cp_build_unary_op (ADDR_EXPR, expr1, 0, complain); + expr1 = cp_build_addr_expr (expr1, complain); elems[0] = expr1; elems[1] = td3; @@ -913,8 +913,7 @@ tinfo_base_init (tinfo_s *ti, tree target) } vtable_ptr = get_vtable_decl (real_type, /*complete=*/1); - vtable_ptr = cp_build_unary_op (ADDR_EXPR, vtable_ptr, 0, - tf_warning_or_error); + vtable_ptr = cp_build_addr_expr (vtable_ptr, tf_warning_or_error); /* We need to point into the middle of the vtable. */ vtable_ptr = build2 diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index ea01d1f4677..d52387b3b65 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3008,7 +3008,7 @@ stabilize_expr (tree exp, tree* initp) } else { - exp = cp_build_unary_op (ADDR_EXPR, exp, 1, tf_warning_or_error); + exp = cp_build_addr_expr (exp, tf_warning_or_error); init_expr = get_target_expr (exp); exp = TARGET_EXPR_SLOT (init_expr); exp = cp_build_indirect_ref (exp, RO_NULL, tf_warning_or_error); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 9959e409f53..c25a17708b4 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1942,7 +1942,7 @@ decay_conversion (tree exp) if (invalid_nonstatic_memfn_p (exp, tf_warning_or_error)) return error_mark_node; if (code == FUNCTION_TYPE || is_overloaded_fn (exp)) - return cp_build_unary_op (ADDR_EXPR, exp, 0, tf_warning_or_error); + return cp_build_addr_expr (exp, tf_warning_or_error); if (code == ARRAY_TYPE) { tree adr; @@ -1977,7 +1977,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_unary_op (ADDR_EXPR, exp, 1, tf_warning_or_error); + adr = cp_build_addr_expr (exp, tf_warning_or_error); return cp_convert (ptrtype, adr); } @@ -3211,8 +3211,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) vtable entry is treated as a function pointer. */ if (TARGET_VTABLE_USES_DESCRIPTORS) e2 = build1 (NOP_EXPR, TREE_TYPE (e2), - cp_build_unary_op (ADDR_EXPR, e2, /*noconvert=*/1, - tf_warning_or_error)); + cp_build_addr_expr (e2, tf_warning_or_error)); e2 = fold_convert (TREE_TYPE (e3), e2); e1 = build_conditional_expr (e1, e2, e3, tf_warning_or_error); @@ -4721,9 +4720,8 @@ build_x_unary_op (enum tree_code code, tree xarg, tsubst_flags_t complain) PTRMEM_OK_P (xarg) = ptrmem; } } - else if (TREE_CODE (xarg) == TARGET_EXPR && (complain & tf_warning)) - warning (0, "taking address of temporary"); - exp = cp_build_unary_op (ADDR_EXPR, xarg, 0, complain); + + exp = cp_build_addr_expr_strict (xarg, complain); } if (processing_template_decl && exp != error_mark_node) @@ -4800,6 +4798,276 @@ build_nop (tree type, tree expr) return build1 (NOP_EXPR, type, expr); } +/* Take the address of ARG, whatever that means under C++ semantics. + If STRICT_LVALUE is true, require an lvalue; otherwise, allow xvalues + and class rvalues as well. + + Nothing should call this function directly; instead, callers should use + cp_build_addr_expr or cp_build_addr_expr_strict. */ + +static tree +cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain) +{ + tree argtype; + tree val; + + if (!arg || error_operand_p (arg)) + return error_mark_node; + + arg = mark_lvalue_use (arg); + argtype = lvalue_type (arg); + + gcc_assert (TREE_CODE (arg) != IDENTIFIER_NODE + || !IDENTIFIER_OPNAME_P (arg)); + + if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg) + && !really_overloaded_fn (TREE_OPERAND (arg, 1))) + { + /* They're trying to take the address of a unique non-static + member function. This is ill-formed (except in MS-land), + but let's try to DTRT. + Note: We only handle unique functions here because we don't + want to complain if there's a static overload; non-unique + cases will be handled by instantiate_type. But we need to + handle this case here to allow casts on the resulting PMF. + We could defer this in non-MS mode, but it's easier to give + a useful error here. */ + + /* Inside constant member functions, the `this' pointer + contains an extra const qualifier. TYPE_MAIN_VARIANT + is used here to remove this const from the diagnostics + and the created OFFSET_REF. */ + tree base = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg, 0))); + tree fn = get_first_fn (TREE_OPERAND (arg, 1)); + mark_used (fn); + + if (! flag_ms_extensions) + { + tree name = DECL_NAME (fn); + if (!(complain & tf_error)) + return error_mark_node; + else if (current_class_type + && TREE_OPERAND (arg, 0) == current_class_ref) + /* An expression like &memfn. */ + permerror (input_location, "ISO C++ forbids taking the address of an unqualified" + " or parenthesized non-static member function to form" + " a pointer to member function. Say %<&%T::%D%>", + base, name); + else + permerror (input_location, "ISO C++ forbids taking the address of a bound member" + " function to form a pointer to member function." + " Say %<&%T::%D%>", + base, name); + } + arg = build_offset_ref (base, fn, /*address_p=*/true); + } + + /* Uninstantiated types are all functions. Taking the + address of a function is a no-op, so just return the + argument. */ + if (type_unknown_p (arg)) + return build1 (ADDR_EXPR, unknown_type_node, arg); + + if (TREE_CODE (arg) == OFFSET_REF) + /* We want a pointer to member; bypass all the code for actually taking + the address of something. */ + goto offset_ref; + + /* Anything not already handled and not a true memory reference + is an error. */ + if (TREE_CODE (argtype) != FUNCTION_TYPE + && TREE_CODE (argtype) != METHOD_TYPE) + { + bool win = strict_lvalue ? real_lvalue_p (arg) : lvalue_p (arg); + if (!win) + { + if (complain & tf_error) + lvalue_error (lv_addressof); + return error_mark_node; + } + } + + if (TREE_CODE (argtype) == REFERENCE_TYPE) + { + tree type = build_pointer_type (TREE_TYPE (argtype)); + arg = build1 (CONVERT_EXPR, type, arg); + return arg; + } + else if (pedantic && DECL_MAIN_P (arg)) + { + /* ARM $3.4 */ + /* Apparently a lot of autoconf scripts for C++ packages do this, + so only complain if -pedantic. */ + if (complain & (flag_pedantic_errors ? tf_error : tf_warning)) + pedwarn (input_location, OPT_pedantic, + "ISO C++ forbids taking address of function %<::main%>"); + else if (flag_pedantic_errors) + return error_mark_node; + } + + /* Let &* cancel out to simplify resulting code. */ + if (TREE_CODE (arg) == INDIRECT_REF) + { + /* We don't need to have `current_class_ptr' wrapped in a + NON_LVALUE_EXPR node. */ + if (arg == current_class_ref) + return current_class_ptr; + + arg = TREE_OPERAND (arg, 0); + if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE) + { + tree type = build_pointer_type (TREE_TYPE (TREE_TYPE (arg))); + arg = build1 (CONVERT_EXPR, type, arg); + } + else + /* Don't let this be an lvalue. */ + arg = rvalue (arg); + return arg; + } + + /* ??? Cope with user tricks that amount to offsetof. */ + if (TREE_CODE (argtype) != FUNCTION_TYPE + && TREE_CODE (argtype) != METHOD_TYPE + && argtype != unknown_type_node + && (val = get_base_address (arg)) + && TREE_CODE (val) == INDIRECT_REF + && TREE_CONSTANT (TREE_OPERAND (val, 0))) + { + tree type = build_pointer_type (argtype); + tree op0 = fold_convert (type, TREE_OPERAND (val, 0)); + tree op1 = fold_convert (sizetype, fold_offsetof (arg, val)); + return fold_build2 (POINTER_PLUS_EXPR, type, op0, op1); + } + + /* Handle complex lvalues (when permitted) + by reduction to simpler cases. */ + val = unary_complex_lvalue (ADDR_EXPR, arg); + if (val != 0) + return val; + + switch (TREE_CODE (arg)) + { + CASE_CONVERT: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + /* Even if we're not being pedantic, we cannot allow this + extension when we're instantiating in a SFINAE + context. */ + if (! lvalue_p (arg) && complain == tf_none) + { + if (complain & tf_error) + permerror (input_location, "ISO C++ forbids taking the address of a cast to a non-lvalue expression"); + else + return error_mark_node; + } + break; + + case BASELINK: + arg = BASELINK_FUNCTIONS (arg); + /* Fall through. */ + + case OVERLOAD: + arg = OVL_CURRENT (arg); + break; + + case OFFSET_REF: + offset_ref: + /* Turn a reference to a non-static data member into a + pointer-to-member. */ + { + tree type; + tree t; + + gcc_assert (PTRMEM_OK_P (arg)); + + t = TREE_OPERAND (arg, 1); + if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) + { + if (complain & tf_error) + error ("cannot create pointer to reference member %qD", t); + return error_mark_node; + } + + type = build_ptrmem_type (context_for_name_lookup (t), + TREE_TYPE (t)); + t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1)); + return t; + } + + default: + break; + } + + if (argtype != error_mark_node) + argtype = build_pointer_type (argtype); + + /* In a template, we are processing a non-dependent expression + so we can just form an ADDR_EXPR with the correct type. */ + if (processing_template_decl || TREE_CODE (arg) != COMPONENT_REF) + { + val = build_address (arg); + if (TREE_CODE (arg) == OFFSET_REF) + PTRMEM_OK_P (val) = PTRMEM_OK_P (arg); + } + else if (TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK) + { + tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1)); + + /* We can only get here with a single static member + function. */ + gcc_assert (TREE_CODE (fn) == FUNCTION_DECL + && DECL_STATIC_FUNCTION_P (fn)); + mark_used (fn); + val = build_address (fn); + if (TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0))) + /* Do not lose object's side effects. */ + val = build2 (COMPOUND_EXPR, TREE_TYPE (val), + TREE_OPERAND (arg, 0), val); + } + else if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1))) + { + if (complain & tf_error) + error ("attempt to take address of bit-field structure member %qD", + TREE_OPERAND (arg, 1)); + return error_mark_node; + } + else + { + tree object = TREE_OPERAND (arg, 0); + tree field = TREE_OPERAND (arg, 1); + gcc_assert (same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (object), decl_type_context (field))); + val = build_address (arg); + } + + if (TREE_CODE (argtype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE) + { + build_ptrmemfunc_type (argtype); + val = build_ptrmemfunc (argtype, val, 0, + /*c_cast_p=*/false, + tf_warning_or_error); + } + + return val; +} + +/* Take the address of ARG if it has one, even if it's an rvalue. */ + +tree +cp_build_addr_expr (tree arg, tsubst_flags_t complain) +{ + return cp_build_addr_expr_1 (arg, 0, complain); +} + +/* Take the address of ARG, but only if it's an lvalue. */ + +tree +cp_build_addr_expr_strict (tree arg, tsubst_flags_t complain) +{ + return cp_build_addr_expr_1 (arg, 1, complain); +} + /* C++: Must handle pointers to members. Perhaps type instantiation should be extended to handle conversion @@ -5066,238 +5334,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert, case ADDR_EXPR: /* Note that this operation never does default_conversion regardless of NOCONVERT. */ - - argtype = lvalue_type (arg); - - arg = mark_lvalue_use (arg); - - if (TREE_CODE (arg) == OFFSET_REF) - goto offset_ref; - - if (TREE_CODE (argtype) == REFERENCE_TYPE) - { - tree type = build_pointer_type (TREE_TYPE (argtype)); - arg = build1 (CONVERT_EXPR, type, arg); - return arg; - } - else if (pedantic && DECL_MAIN_P (arg)) - { - /* ARM $3.4 */ - /* Apparently a lot of autoconf scripts for C++ packages do this, - so only complain if -pedantic. */ - if (complain & (flag_pedantic_errors ? tf_error : tf_warning)) - pedwarn (input_location, OPT_pedantic, - "ISO C++ forbids taking address of function %<::main%>"); - else if (flag_pedantic_errors) - return error_mark_node; - } - - /* Let &* cancel out to simplify resulting code. */ - if (TREE_CODE (arg) == INDIRECT_REF) - { - /* We don't need to have `current_class_ptr' wrapped in a - NON_LVALUE_EXPR node. */ - if (arg == current_class_ref) - return current_class_ptr; - - arg = TREE_OPERAND (arg, 0); - if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE) - { - tree type = build_pointer_type (TREE_TYPE (TREE_TYPE (arg))); - arg = build1 (CONVERT_EXPR, type, arg); - } - else - /* Don't let this be an lvalue. */ - arg = rvalue (arg); - return arg; - } - - /* ??? Cope with user tricks that amount to offsetof. */ - if (TREE_CODE (argtype) != FUNCTION_TYPE - && TREE_CODE (argtype) != METHOD_TYPE - && argtype != unknown_type_node - && (val = get_base_address (arg)) - && TREE_CODE (val) == INDIRECT_REF - && TREE_CONSTANT (TREE_OPERAND (val, 0))) - { - tree type = build_pointer_type (argtype); - tree op0 = fold_convert (type, TREE_OPERAND (val, 0)); - tree op1 = fold_convert (sizetype, fold_offsetof (arg, val)); - return fold_build2 (POINTER_PLUS_EXPR, type, op0, op1); - } - - /* Uninstantiated types are all functions. Taking the - address of a function is a no-op, so just return the - argument. */ - - gcc_assert (TREE_CODE (arg) != IDENTIFIER_NODE - || !IDENTIFIER_OPNAME_P (arg)); - - if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg) - && !really_overloaded_fn (TREE_OPERAND (arg, 1))) - { - /* They're trying to take the address of a unique non-static - member function. This is ill-formed (except in MS-land), - but let's try to DTRT. - Note: We only handle unique functions here because we don't - want to complain if there's a static overload; non-unique - cases will be handled by instantiate_type. But we need to - handle this case here to allow casts on the resulting PMF. - We could defer this in non-MS mode, but it's easier to give - a useful error here. */ - - /* Inside constant member functions, the `this' pointer - contains an extra const qualifier. TYPE_MAIN_VARIANT - is used here to remove this const from the diagnostics - and the created OFFSET_REF. */ - tree base = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg, 0))); - tree fn = get_first_fn (TREE_OPERAND (arg, 1)); - mark_used (fn); - - if (! flag_ms_extensions) - { - tree name = DECL_NAME (fn); - if (!(complain & tf_error)) - return error_mark_node; - else if (current_class_type - && TREE_OPERAND (arg, 0) == current_class_ref) - /* An expression like &memfn. */ - permerror (input_location, "ISO C++ forbids taking the address of an unqualified" - " or parenthesized non-static member function to form" - " a pointer to member function. Say %<&%T::%D%>", - base, name); - else - permerror (input_location, "ISO C++ forbids taking the address of a bound member" - " function to form a pointer to member function." - " Say %<&%T::%D%>", - base, name); - } - arg = build_offset_ref (base, fn, /*address_p=*/true); - } - - offset_ref: - if (type_unknown_p (arg)) - return build1 (ADDR_EXPR, unknown_type_node, arg); - - /* Handle complex lvalues (when permitted) - by reduction to simpler cases. */ - val = unary_complex_lvalue (code, arg); - if (val != 0) - return val; - - switch (TREE_CODE (arg)) - { - CASE_CONVERT: - case FLOAT_EXPR: - case FIX_TRUNC_EXPR: - /* Even if we're not being pedantic, we cannot allow this - extension when we're instantiating in a SFINAE - context. */ - if (! lvalue_p (arg) && complain == tf_none) - { - if (complain & tf_error) - permerror (input_location, "ISO C++ forbids taking the address of a cast to a non-lvalue expression"); - else - return error_mark_node; - } - break; - - case BASELINK: - arg = BASELINK_FUNCTIONS (arg); - /* Fall through. */ - - case OVERLOAD: - arg = OVL_CURRENT (arg); - break; - - case OFFSET_REF: - /* Turn a reference to a non-static data member into a - pointer-to-member. */ - { - tree type; - tree t; - - if (!PTRMEM_OK_P (arg)) - return cp_build_unary_op (code, arg, 0, complain); - - t = TREE_OPERAND (arg, 1); - if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) - { - if (complain & tf_error) - error ("cannot create pointer to reference member %qD", t); - return error_mark_node; - } - - type = build_ptrmem_type (context_for_name_lookup (t), - TREE_TYPE (t)); - t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1)); - return t; - } - - default: - break; - } - - /* Anything not already handled and not a true memory reference - is an error. */ - if (TREE_CODE (argtype) != FUNCTION_TYPE - && TREE_CODE (argtype) != METHOD_TYPE - && TREE_CODE (arg) != OFFSET_REF - && !lvalue_or_else (arg, lv_addressof, complain)) - return error_mark_node; - - if (argtype != error_mark_node) - argtype = build_pointer_type (argtype); - - /* In a template, we are processing a non-dependent expression - so we can just form an ADDR_EXPR with the correct type. */ - if (processing_template_decl || TREE_CODE (arg) != COMPONENT_REF) - { - val = build_address (arg); - if (TREE_CODE (arg) == OFFSET_REF) - PTRMEM_OK_P (val) = PTRMEM_OK_P (arg); - } - else if (TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK) - { - tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1)); - - /* We can only get here with a single static member - function. */ - gcc_assert (TREE_CODE (fn) == FUNCTION_DECL - && DECL_STATIC_FUNCTION_P (fn)); - mark_used (fn); - val = build_address (fn); - if (TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0))) - /* Do not lose object's side effects. */ - val = build2 (COMPOUND_EXPR, TREE_TYPE (val), - TREE_OPERAND (arg, 0), val); - } - else if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1))) - { - if (complain & tf_error) - error ("attempt to take address of bit-field structure member %qD", - TREE_OPERAND (arg, 1)); - return error_mark_node; - } - else - { - tree object = TREE_OPERAND (arg, 0); - tree field = TREE_OPERAND (arg, 1); - gcc_assert (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (object), decl_type_context (field))); - val = build_address (arg); - } - - if (TREE_CODE (argtype) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE) - { - build_ptrmemfunc_type (argtype); - val = build_ptrmemfunc (argtype, val, 0, - /*c_cast_p=*/false, - tf_warning_or_error); - } - - return val; + return cp_build_addr_expr (arg, complain); default: break; @@ -6128,7 +6165,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, warning (0, "casting %qT to %qT does not dereference pointer", intype, type); - expr = cp_build_unary_op (ADDR_EXPR, expr, 0, complain); + expr = cp_build_addr_expr (expr, complain); if (warn_strict_aliasing > 2) strict_aliasing_warning (TREE_TYPE (expr), type, expr); @@ -6366,8 +6403,8 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain, } if (reference_type) { - expr = cp_build_unary_op (ADDR_EXPR, expr, 0, - complain? tf_warning_or_error : tf_none); + expr = cp_build_addr_expr (expr, + complain ? tf_warning_or_error : tf_none); expr = build_nop (reference_type, expr); return convert_from_reference (expr); } @@ -8324,7 +8361,7 @@ non_reference (tree t) int lvalue_or_else (tree ref, enum lvalue_use use, tsubst_flags_t complain) { - int win = lvalue_p (ref); + int win = real_lvalue_p (ref); if (!win && (complain & tf_error)) lvalue_error (use); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4f795dddb99..f56e70965e2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2010-09-27 Jason Merrill + + * g++.dg/cpp0x/rv-lvalue-req.C: New. + * g++.dg/ext/complit11.C: Adjust. + * g++.old-deja/g++.law/temps1.C: Adjust. + * g++.old-deja/g++.ns/koenig6.C: Adjust. + * g++.old-deja/g++.oliva/partord1.C: Adjust. + 2010-09-27 Ian Lance Taylor * lib/target-supports.exp (check_effective_target_split_stack): diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-lvalue-req.C b/gcc/testsuite/g++.dg/cpp0x/rv-lvalue-req.C new file mode 100644 index 00000000000..ba1c306d9dc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/rv-lvalue-req.C @@ -0,0 +1,12 @@ +// { dg-options -std=c++0x } + +template T&& declval(); + +int main() +{ + &declval(); // { dg-error "lvalue" } + declval() = declval(); // { dg-error "lvalue" } + declval()++; // { dg-error "lvalue" } + --declval(); // { dg-error "lvalue" } + declval() += 1; // { dg-error "lvalue" } +} diff --git a/gcc/testsuite/g++.dg/ext/complit11.C b/gcc/testsuite/g++.dg/ext/complit11.C index 7b41795ece3..2cff6cd2eb4 100644 --- a/gcc/testsuite/g++.dg/ext/complit11.C +++ b/gcc/testsuite/g++.dg/ext/complit11.C @@ -6,7 +6,7 @@ struct A { int i; }; template void foo() { - ((struct A) { 0 }).i += 1; + ((struct A) { 0 }).i += 1; // { dg-error "lvalue required" } } void g(void) diff --git a/gcc/testsuite/g++.old-deja/g++.law/temps1.C b/gcc/testsuite/g++.old-deja/g++.law/temps1.C index cd0bc876e87..2e6a4195116 100644 --- a/gcc/testsuite/g++.old-deja/g++.law/temps1.C +++ b/gcc/testsuite/g++.old-deja/g++.law/temps1.C @@ -16,4 +16,4 @@ struct cookie }; cookie cat(&foo("apabepa"));// { dg-warning "deprecated conversion" "dep" } -// { dg-warning "taking address of temporary" "add" { target *-*-* } 18 } +// { dg-error "lvalue required" "lvalue" { target *-*-* } 18 } diff --git a/gcc/testsuite/g++.old-deja/g++.ns/koenig6.C b/gcc/testsuite/g++.old-deja/g++.ns/koenig6.C index f77d975300c..b5fa9c98996 100644 --- a/gcc/testsuite/g++.old-deja/g++.ns/koenig6.C +++ b/gcc/testsuite/g++.old-deja/g++.ns/koenig6.C @@ -2,12 +2,12 @@ namespace A{ struct X{}; - X foo(X a){return a;} + X* foo(X a); void bar(X*){} } int main() { A::X x; - bar(&foo(x)); // { dg-warning "" } address of temporary + bar(foo(x)); } diff --git a/gcc/testsuite/g++.old-deja/g++.oliva/partord1.C b/gcc/testsuite/g++.old-deja/g++.oliva/partord1.C index 555931725d2..34fe92e6407 100644 --- a/gcc/testsuite/g++.old-deja/g++.oliva/partord1.C +++ b/gcc/testsuite/g++.old-deja/g++.oliva/partord1.C @@ -14,10 +14,10 @@ template class bar { }; template void foo(T) { - bar().i = 0; // ok, I'm a friend + bar().i; // ok, I'm a friend } template void foo(T*) { - bar().i = 1; // { dg-error "" } not a friend + bar().i; // { dg-error "" } not a friend } int main() {