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. From-SVN: r164666
This commit is contained in:
parent
a77bfaebbf
commit
93c0e0bb1d
|
@ -1,3 +1,25 @@
|
|||
2010-09-27 Jason Merrill <jason@redhat.com>
|
||||
|
||||
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 <nicola.pero@meta-innovation.com>
|
||||
|
||||
Merge from apple/trunk branch on FSF servers:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
523
gcc/cp/typeck.c
523
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);
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
2010-09-27 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* 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 <iant@google.com>
|
||||
|
||||
* lib/target-supports.exp (check_effective_target_split_stack):
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
template <class T> T&& declval();
|
||||
|
||||
int main()
|
||||
{
|
||||
&declval<int>(); // { dg-error "lvalue" }
|
||||
declval<int>() = declval<int>(); // { dg-error "lvalue" }
|
||||
declval<int>()++; // { dg-error "lvalue" }
|
||||
--declval<int>(); // { dg-error "lvalue" }
|
||||
declval<int>() += 1; // { dg-error "lvalue" }
|
||||
}
|
|
@ -6,7 +6,7 @@ struct A { int i; };
|
|||
template<int t>
|
||||
void foo()
|
||||
{
|
||||
((struct A) { 0 }).i += 1;
|
||||
((struct A) { 0 }).i += 1; // { dg-error "lvalue required" }
|
||||
}
|
||||
|
||||
void g(void)
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@ template <typename T> class bar {
|
|||
};
|
||||
|
||||
template <typename T> void foo(T) {
|
||||
bar<T>().i = 0; // ok, I'm a friend
|
||||
bar<T>().i; // ok, I'm a friend
|
||||
}
|
||||
template <typename T> void foo(T*) {
|
||||
bar<T*>().i = 1; // { dg-error "" } not a friend
|
||||
bar<T*>().i; // { dg-error "" } not a friend
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
|
Loading…
Reference in New Issue