commit 0d4843a8a30cdbf32fb1ff74e79bf1c9ae38d447
Author: Jason Merrill <jason@redhat.com>
Date: Sun Sep 26 11:57:58 2010 -0400
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.
@@ -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);
@@ -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);
new file mode 100644
@@ -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() {