static int list_hash_eq PARAMS ((const void *, const void *));
static hashval_t list_hash_pieces PARAMS ((tree, tree, tree));
static hashval_t list_hash PARAMS ((const void *));
-static cp_lvalue_kind lvalue_p_1 PARAMS ((tree, int));
+static cp_lvalue_kind lvalue_p_1 PARAMS ((tree, int, int));
static tree no_linkage_helper PARAMS ((tree *, int *, void *));
static tree build_srcloc PARAMS ((const char *, int));
static tree mark_local_for_remap_r PARAMS ((tree *, int *, void *));
non-zero, rvalues of class type are considered lvalues. */
static cp_lvalue_kind
-lvalue_p_1 (ref, treat_class_rvalues_as_lvalues)
+lvalue_p_1 (ref, treat_class_rvalues_as_lvalues, allow_cast_as_lvalue)
tree ref;
int treat_class_rvalues_as_lvalues;
+ int allow_cast_as_lvalue;
{
cp_lvalue_kind op1_lvalue_kind = clk_none;
cp_lvalue_kind op2_lvalue_kind = clk_none;
case WITH_CLEANUP_EXPR:
case REALPART_EXPR:
case IMAGPART_EXPR:
- /* This shouldn't be here, but there are lots of places in the compiler
- that are sloppy about tacking on NOP_EXPRs to the same type when
- no actual conversion is happening. */
- case NOP_EXPR:
return lvalue_p_1 (TREE_OPERAND (ref, 0),
- treat_class_rvalues_as_lvalues);
+ treat_class_rvalues_as_lvalues,
+ allow_cast_as_lvalue);
+
+ case NOP_EXPR:
+ /* If expression doesn't change the type, we consider it as an
+ lvalue even when cast_as_lvalue extension isn't selected.
+ That's because parts of the compiler are alleged to be sloppy
+ about sticking in NOP_EXPR node for no good reason. */
+ if (allow_cast_as_lvalue ||
+ same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (ref)),
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (ref, 0)))))
+ return lvalue_p_1 (TREE_OPERAND (ref, 0),
+ treat_class_rvalues_as_lvalues,
+ allow_cast_as_lvalue);
+ else
+ return clk_none;
case COMPONENT_REF:
op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
- treat_class_rvalues_as_lvalues);
+ treat_class_rvalues_as_lvalues,
+ allow_cast_as_lvalue);
if (op1_lvalue_kind
/* The "field" can be a FUNCTION_DECL or an OVERLOAD in some
situations. */
case MAX_EXPR:
case MIN_EXPR:
op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
- treat_class_rvalues_as_lvalues);
+ treat_class_rvalues_as_lvalues,
+ allow_cast_as_lvalue);
op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),
- treat_class_rvalues_as_lvalues);
+ treat_class_rvalues_as_lvalues,
+ allow_cast_as_lvalue);
break;
case COND_EXPR:
op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),
- treat_class_rvalues_as_lvalues);
+ treat_class_rvalues_as_lvalues,
+ allow_cast_as_lvalue);
op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 2),
- treat_class_rvalues_as_lvalues);
+ treat_class_rvalues_as_lvalues,
+ allow_cast_as_lvalue);
break;
case MODIFY_EXPR:
case COMPOUND_EXPR:
return lvalue_p_1 (TREE_OPERAND (ref, 1),
- treat_class_rvalues_as_lvalues);
+ treat_class_rvalues_as_lvalues,
+ allow_cast_as_lvalue);
case TARGET_EXPR:
return treat_class_rvalues_as_lvalues ? clk_class : clk_none;
real_lvalue_p (ref)
tree ref;
{
- return lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/0);
+ return lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/ 0, /*cast*/ 1);
}
/* This differs from real_lvalue_p in that class rvalues are
tree ref;
{
return
- (lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/1) != clk_none);
+ (lvalue_p_1 (ref, /*class rvalue ok*/ 1, /*cast*/ 1) != clk_none);
}
/* Return nonzero if REF is an lvalue valid for this language;
tree ref;
const char *string;
{
- int win = lvalue_p (ref);
+ int ret = lvalue_p_1 (ref, /* class rvalue ok */ 1, /* cast ok */ 1);
+ int win = (ret != clk_none);
+ if (! win)
+ error ("non-lvalue in %s", string);
+ return win;
+}
+
+int
+non_cast_lvalue_or_else (ref, string)
+ tree ref;
+ const char *string;
+{
+ int ret = lvalue_p_1 (ref, /* class rvalue ok */ 1, /* cast ok */ 0);
+ int win = (ret != clk_none);
if (! win)
error ("non-lvalue in %s", string);
return win;