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:
Jason Merrill 2010-09-27 16:05:34 -04:00 committed by Jason Merrill
parent a77bfaebbf
commit 93c0e0bb1d
18 changed files with 355 additions and 280 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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