Commit 207bf485 by Joseph Myers Committed by Joseph Myers

re PR c/461 (non-lvalue arrays)

	* c-common.c (c_expand_expr_stmt): Apply default conversions to
	non-lvalue arrays if C99.
	* c-typeck.c (default_conversion): Split out code handling
	array-to-pointer and function-to-pointer conversions into a
	separate default_function_array_conversion function.
	(default_function_array_conversion): New function.  Keep track of
	whether any NON_LVALUE_EXPRs were stripped.  Return non-lvalue
	arrays unchanged outside C99 mode instead of giving an error for
	them.
	(build_component_ref): Use pedantic_non_lvalue when handling
	COMPOUND_EXPR.  Don't handle COND_EXPR specially.
	(convert_arguments): Use default_function_array_conversion.
	(build_unary_op): For ADDR_EXPR, take a flag indicating whether
	non-lvalues are OK.
	(unary_complex_lvalue): Likewise.
	(internal_build_compound_expr): Use
	default_function_array_conversion.  Apply default conversions to
	function in compound expression.
	(build_c_cast, build_modify_expr, digest_init, build_asm_stmt):
	Use default_function_array_conversion.
	* doc/extend.texi: Update documentation of subscripting non-lvalue
	arrays.
	Fixes PR c/461.

testsuite:
	* gcc.dg/c90-array-lval-1.c, gcc.dg/c90-array-lval-2.c,
	gcc.dg/c99-array-lval-1.c, gcc.dg/c99-array-lval-2.c: Remove
	XFAILs.  Adjust expected error texts.
	* gcc.c-torture/compile/20011106-1.c,
	gcc.c-torture/compile/20011106-2.c, gcc.dg/c90-array-lval-3.c,
	gcc.dg/c90-array-lval-4.c, gcc.dg/c90-array-lval-5.c,
	gcc.dg/c99-array-lval-3.c, gcc.dg/c99-array-lval-4.c,
	gcc.dg/c99-array-lval-5.c: New tests.

From-SVN: r46805
parent 25cece2f
2001-11-06 Joseph S. Myers <jsm28@cam.ac.uk>
* c-common.c (c_expand_expr_stmt): Apply default conversions to
non-lvalue arrays if C99.
* c-typeck.c (default_conversion): Split out code handling
array-to-pointer and function-to-pointer conversions into a
separate default_function_array_conversion function.
(default_function_array_conversion): New function. Keep track of
whether any NON_LVALUE_EXPRs were stripped. Return non-lvalue
arrays unchanged outside C99 mode instead of giving an error for
them.
(build_component_ref): Use pedantic_non_lvalue when handling
COMPOUND_EXPR. Don't handle COND_EXPR specially.
(convert_arguments): Use default_function_array_conversion.
(build_unary_op): For ADDR_EXPR, take a flag indicating whether
non-lvalues are OK.
(unary_complex_lvalue): Likewise.
(internal_build_compound_expr): Use
default_function_array_conversion. Apply default conversions to
function in compound expression.
(build_c_cast, build_modify_expr, digest_init, build_asm_stmt):
Use default_function_array_conversion.
* doc/extend.texi: Update documentation of subscripting non-lvalue
arrays.
Fixes PR c/461.
2001-11-05 Zack Weinberg <zack@codesourcery.com> 2001-11-05 Zack Weinberg <zack@codesourcery.com>
* aclocal.m4: (AM_WITH_NLS): Don't look at ALL_LINGUAS. * aclocal.m4: (AM_WITH_NLS): Don't look at ALL_LINGUAS.
......
...@@ -1181,7 +1181,8 @@ c_expand_expr_stmt (expr) ...@@ -1181,7 +1181,8 @@ c_expand_expr_stmt (expr)
{ {
/* Do default conversion if safe and possibly important, /* Do default conversion if safe and possibly important,
in case within ({...}). */ in case within ({...}). */
if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && lvalue_p (expr)) if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
&& (flag_isoc99 || lvalue_p (expr)))
|| TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE) || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
expr = default_conversion (expr); expr = default_conversion (expr);
......
...@@ -55,11 +55,12 @@ static int comp_target_types PARAMS ((tree, tree)); ...@@ -55,11 +55,12 @@ static int comp_target_types PARAMS ((tree, tree));
static int function_types_compatible_p PARAMS ((tree, tree)); static int function_types_compatible_p PARAMS ((tree, tree));
static int type_lists_compatible_p PARAMS ((tree, tree)); static int type_lists_compatible_p PARAMS ((tree, tree));
static tree decl_constant_value_for_broken_optimization PARAMS ((tree)); static tree decl_constant_value_for_broken_optimization PARAMS ((tree));
static tree default_function_array_conversion PARAMS ((tree));
static tree lookup_field PARAMS ((tree, tree)); static tree lookup_field PARAMS ((tree, tree));
static tree convert_arguments PARAMS ((tree, tree, tree, tree)); static tree convert_arguments PARAMS ((tree, tree, tree, tree));
static tree pointer_int_sum PARAMS ((enum tree_code, tree, tree)); static tree pointer_int_sum PARAMS ((enum tree_code, tree, tree));
static tree pointer_diff PARAMS ((tree, tree)); static tree pointer_diff PARAMS ((tree, tree));
static tree unary_complex_lvalue PARAMS ((enum tree_code, tree)); static tree unary_complex_lvalue PARAMS ((enum tree_code, tree, int));
static void pedantic_lvalue_warning PARAMS ((enum tree_code)); static void pedantic_lvalue_warning PARAMS ((enum tree_code));
static tree internal_build_compound_expr PARAMS ((tree, int)); static tree internal_build_compound_expr PARAMS ((tree, int));
static tree convert_for_assignment PARAMS ((tree, tree, const char *, static tree convert_for_assignment PARAMS ((tree, tree, const char *,
...@@ -838,6 +839,110 @@ decl_constant_value_for_broken_optimization (decl) ...@@ -838,6 +839,110 @@ decl_constant_value_for_broken_optimization (decl)
return decl_constant_value (decl); return decl_constant_value (decl);
} }
/* Perform the default conversion of arrays and functions to pointers.
Return the result of converting EXP. For any other expression, just
return EXP. */
static tree
default_function_array_conversion (exp)
tree exp;
{
tree orig_exp;
tree type = TREE_TYPE (exp);
enum tree_code code = TREE_CODE (type);
int not_lvalue = 0;
/* Strip NON_LVALUE_EXPRs and no-op conversions, since we aren't using as
an lvalue.
Do not use STRIP_NOPS here! It will remove conversions from pointer
to integer and cause infinite recursion. */
orig_exp = exp;
while (TREE_CODE (exp) == NON_LVALUE_EXPR
|| (TREE_CODE (exp) == NOP_EXPR
&& TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp)))
{
if (TREE_CODE (exp) == NON_LVALUE_EXPR)
not_lvalue = 1;
exp = TREE_OPERAND (exp, 0);
}
/* Preserve the original expression code. */
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (exp))))
C_SET_EXP_ORIGINAL_CODE (exp, C_EXP_ORIGINAL_CODE (orig_exp));
if (code == FUNCTION_TYPE)
{
return build_unary_op (ADDR_EXPR, exp, 0);
}
if (code == ARRAY_TYPE)
{
tree adr;
tree restype = TREE_TYPE (type);
tree ptrtype;
int constp = 0;
int volatilep = 0;
int lvalue_array_p;
if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r' || DECL_P (exp))
{
constp = TREE_READONLY (exp);
volatilep = TREE_THIS_VOLATILE (exp);
}
if (TYPE_QUALS (type) || constp || volatilep)
restype
= c_build_qualified_type (restype,
TYPE_QUALS (type)
| (constp * TYPE_QUAL_CONST)
| (volatilep * TYPE_QUAL_VOLATILE));
if (TREE_CODE (exp) == INDIRECT_REF)
return convert (TYPE_POINTER_TO (restype),
TREE_OPERAND (exp, 0));
if (TREE_CODE (exp) == COMPOUND_EXPR)
{
tree op1 = default_conversion (TREE_OPERAND (exp, 1));
return build (COMPOUND_EXPR, TREE_TYPE (op1),
TREE_OPERAND (exp, 0), op1);
}
lvalue_array_p = !not_lvalue && lvalue_p (exp);
if (!flag_isoc99 && !lvalue_array_p
&& !(TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
{
/* Before C99, non-lvalue arrays do not decay to pointers.
Normally, using such an array would be invalid; but it can
be used correctly inside sizeof or as a statement expression.
Thus, do not give an error here; an error will result later. */
return exp;
}
ptrtype = build_pointer_type (restype);
if (TREE_CODE (exp) == VAR_DECL)
{
/* ??? This is not really quite correct
in that the type of the operand of ADDR_EXPR
is not the target type of the type of the ADDR_EXPR itself.
Question is, can this lossage be avoided? */
adr = build1 (ADDR_EXPR, ptrtype, exp);
if (mark_addressable (exp) == 0)
return error_mark_node;
TREE_CONSTANT (adr) = staticp (exp);
TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */
return adr;
}
/* This way is better for a COMPONENT_REF since it can
simplify the offset for a component. */
adr = build_unary_op (ADDR_EXPR, exp, 1);
return convert (ptrtype, adr);
}
return exp;
}
/* Perform default promotions for C data used in expressions. /* Perform default promotions for C data used in expressions.
Arrays and functions are converted to pointers; Arrays and functions are converted to pointers;
enumeral types or short or char, to int. enumeral types or short or char, to int.
...@@ -851,6 +956,9 @@ default_conversion (exp) ...@@ -851,6 +956,9 @@ default_conversion (exp)
tree type = TREE_TYPE (exp); tree type = TREE_TYPE (exp);
enum tree_code code = TREE_CODE (type); enum tree_code code = TREE_CODE (type);
if (code == FUNCTION_TYPE || code == ARRAY_TYPE)
return default_function_array_conversion (exp);
/* Constants can be used directly unless they're not loadable. */ /* Constants can be used directly unless they're not loadable. */
if (TREE_CODE (exp) == CONST_DECL) if (TREE_CODE (exp) == CONST_DECL)
exp = DECL_INITIAL (exp); exp = DECL_INITIAL (exp);
...@@ -924,69 +1032,6 @@ default_conversion (exp) ...@@ -924,69 +1032,6 @@ default_conversion (exp)
error ("void value not ignored as it ought to be"); error ("void value not ignored as it ought to be");
return error_mark_node; return error_mark_node;
} }
if (code == FUNCTION_TYPE)
{
return build_unary_op (ADDR_EXPR, exp, 0);
}
if (code == ARRAY_TYPE)
{
tree adr;
tree restype = TREE_TYPE (type);
tree ptrtype;
int constp = 0;
int volatilep = 0;
if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r' || DECL_P (exp))
{
constp = TREE_READONLY (exp);
volatilep = TREE_THIS_VOLATILE (exp);
}
if (TYPE_QUALS (type) || constp || volatilep)
restype
= c_build_qualified_type (restype,
TYPE_QUALS (type)
| (constp * TYPE_QUAL_CONST)
| (volatilep * TYPE_QUAL_VOLATILE));
if (TREE_CODE (exp) == INDIRECT_REF)
return convert (TYPE_POINTER_TO (restype),
TREE_OPERAND (exp, 0));
if (TREE_CODE (exp) == COMPOUND_EXPR)
{
tree op1 = default_conversion (TREE_OPERAND (exp, 1));
return build (COMPOUND_EXPR, TREE_TYPE (op1),
TREE_OPERAND (exp, 0), op1);
}
if (! lvalue_p (exp)
&& ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
{
error ("invalid use of non-lvalue array");
return error_mark_node;
}
ptrtype = build_pointer_type (restype);
if (TREE_CODE (exp) == VAR_DECL)
{
/* ??? This is not really quite correct
in that the type of the operand of ADDR_EXPR
is not the target type of the type of the ADDR_EXPR itself.
Question is, can this lossage be avoided? */
adr = build1 (ADDR_EXPR, ptrtype, exp);
if (mark_addressable (exp) == 0)
return error_mark_node;
TREE_CONSTANT (adr) = staticp (exp);
TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */
return adr;
}
/* This way is better for a COMPONENT_REF since it can
simplify the offset for a component. */
adr = build_unary_op (ADDR_EXPR, exp, 1);
return convert (ptrtype, adr);
}
return exp; return exp;
} }
...@@ -1098,22 +1143,22 @@ build_component_ref (datum, component) ...@@ -1098,22 +1143,22 @@ build_component_ref (datum, component)
tree field = NULL; tree field = NULL;
tree ref; tree ref;
/* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it /* If DATUM is a COMPOUND_EXPR, move our reference inside it.
unless we are not to support things not strictly ANSI. */ If pedantic ensure that the arguments are not lvalues; otherwise,
if the component is an array, it would wrongly decay to a pointer in
C89 mode.
We cannot do this with a COND_EXPR, because in a conditional expression
the default promotions are applied to both sides, and this would yield
the wrong type of the result; for example, if the components have
type "char". */
switch (TREE_CODE (datum)) switch (TREE_CODE (datum))
{ {
case COMPOUND_EXPR: case COMPOUND_EXPR:
{ {
tree value = build_component_ref (TREE_OPERAND (datum, 1), component); tree value = build_component_ref (TREE_OPERAND (datum, 1), component);
return build (COMPOUND_EXPR, TREE_TYPE (value), return build (COMPOUND_EXPR, TREE_TYPE (value),
TREE_OPERAND (datum, 0), value); TREE_OPERAND (datum, 0), pedantic_non_lvalue (value));
} }
case COND_EXPR:
return build_conditional_expr
(TREE_OPERAND (datum, 0),
build_component_ref (TREE_OPERAND (datum, 1), component),
build_component_ref (TREE_OPERAND (datum, 2), component));
default: default:
break; break;
} }
...@@ -1586,9 +1631,7 @@ convert_arguments (typelist, values, name, fundecl) ...@@ -1586,9 +1631,7 @@ convert_arguments (typelist, values, name, fundecl)
if (TREE_CODE (val) == NON_LVALUE_EXPR) if (TREE_CODE (val) == NON_LVALUE_EXPR)
val = TREE_OPERAND (val, 0); val = TREE_OPERAND (val, 0);
if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE val = default_function_array_conversion (val);
|| TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE)
val = default_conversion (val);
val = require_complete_type (val); val = require_complete_type (val);
...@@ -2771,20 +2814,25 @@ pointer_diff (op0, op1) ...@@ -2771,20 +2814,25 @@ pointer_diff (op0, op1)
/* Construct and perhaps optimize a tree representation /* Construct and perhaps optimize a tree representation
for a unary operation. CODE, a tree_code, specifies the operation for a unary operation. CODE, a tree_code, specifies the operation
and XARG is the operand. NOCONVERT nonzero suppresses and XARG is the operand.
the default promotions (such as from short to int). */ For any CODE other than ADDR_EXPR, FLAG nonzero suppresses
the default promotions (such as from short to int).
For ADDR_EXPR, the default promotions are not applied; FLAG nonzero
allows non-lvalues; this is only used to handle conversion of non-lvalue
arrays to pointers in C99. */
tree tree
build_unary_op (code, xarg, noconvert) build_unary_op (code, xarg, flag)
enum tree_code code; enum tree_code code;
tree xarg; tree xarg;
int noconvert; int flag;
{ {
/* No default_conversion here. It causes trouble for ADDR_EXPR. */ /* No default_conversion here. It causes trouble for ADDR_EXPR. */
tree arg = xarg; tree arg = xarg;
tree argtype = 0; tree argtype = 0;
enum tree_code typecode = TREE_CODE (TREE_TYPE (arg)); enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
tree val; tree val;
int noconvert = flag;
if (typecode == ERROR_MARK) if (typecode == ERROR_MARK)
return error_mark_node; return error_mark_node;
...@@ -2898,7 +2946,7 @@ build_unary_op (code, xarg, noconvert) ...@@ -2898,7 +2946,7 @@ build_unary_op (code, xarg, noconvert)
/* Handle complex lvalues (when permitted) /* Handle complex lvalues (when permitted)
by reduction to simpler cases. */ by reduction to simpler cases. */
val = unary_complex_lvalue (code, arg); val = unary_complex_lvalue (code, arg, 0);
if (val != 0) if (val != 0)
return val; return val;
...@@ -3045,8 +3093,7 @@ build_unary_op (code, xarg, noconvert) ...@@ -3045,8 +3093,7 @@ build_unary_op (code, xarg, noconvert)
} }
case ADDR_EXPR: case ADDR_EXPR:
/* Note that this operation never does default_conversion /* Note that this operation never does default_conversion. */
regardless of NOCONVERT. */
/* Let &* cancel out to simplify resulting code. */ /* Let &* cancel out to simplify resulting code. */
if (TREE_CODE (arg) == INDIRECT_REF) if (TREE_CODE (arg) == INDIRECT_REF)
...@@ -3068,7 +3115,7 @@ build_unary_op (code, xarg, noconvert) ...@@ -3068,7 +3115,7 @@ build_unary_op (code, xarg, noconvert)
/* Handle complex lvalues (when permitted) /* Handle complex lvalues (when permitted)
by reduction to simpler cases. */ by reduction to simpler cases. */
val = unary_complex_lvalue (code, arg); val = unary_complex_lvalue (code, arg, flag);
if (val != 0) if (val != 0)
return val; return val;
...@@ -3099,8 +3146,8 @@ build_unary_op (code, xarg, noconvert) ...@@ -3099,8 +3146,8 @@ build_unary_op (code, xarg, noconvert)
if (TREE_CODE (arg) == CONSTRUCTOR && TREE_CONSTANT (arg)) if (TREE_CODE (arg) == CONSTRUCTOR && TREE_CONSTANT (arg))
; ;
/* Anything not already handled and not a true memory reference /* Anything not already handled and not a true memory reference
is an error. */ or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE else if (typecode != FUNCTION_TYPE && !flag
&& !lvalue_or_else (arg, "invalid lvalue in unary `&'")) && !lvalue_or_else (arg, "invalid lvalue in unary `&'"))
return error_mark_node; return error_mark_node;
...@@ -3129,7 +3176,7 @@ build_unary_op (code, xarg, noconvert) ...@@ -3129,7 +3176,7 @@ build_unary_op (code, xarg, noconvert)
{ {
tree field = TREE_OPERAND (arg, 1); tree field = TREE_OPERAND (arg, 1);
addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0); addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), flag);
if (DECL_C_BIT_FIELD (field)) if (DECL_C_BIT_FIELD (field))
{ {
...@@ -3248,14 +3295,17 @@ lvalue_or_else (ref, msgid) ...@@ -3248,14 +3295,17 @@ lvalue_or_else (ref, msgid)
/* Apply unary lvalue-demanding operator CODE to the expression ARG /* Apply unary lvalue-demanding operator CODE to the expression ARG
for certain kinds of expressions which are not really lvalues for certain kinds of expressions which are not really lvalues
but which we can accept as lvalues. but which we can accept as lvalues. If FLAG is nonzero, then
non-lvalues are OK since we may be converting a non-lvalue array to
a pointer in C99.
If ARG is not a kind of expression we can handle, return zero. */ If ARG is not a kind of expression we can handle, return zero. */
static tree static tree
unary_complex_lvalue (code, arg) unary_complex_lvalue (code, arg, flag)
enum tree_code code; enum tree_code code;
tree arg; tree arg;
int flag;
{ {
/* Handle (a, b) used as an "lvalue". */ /* Handle (a, b) used as an "lvalue". */
if (TREE_CODE (arg) == COMPOUND_EXPR) if (TREE_CODE (arg) == COMPOUND_EXPR)
...@@ -3264,7 +3314,7 @@ unary_complex_lvalue (code, arg) ...@@ -3264,7 +3314,7 @@ unary_complex_lvalue (code, arg)
/* If this returns a function type, it isn't really being used as /* If this returns a function type, it isn't really being used as
an lvalue, so don't issue a warning about it. */ an lvalue, so don't issue a warning about it. */
if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE) if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE && !flag)
pedantic_lvalue_warning (COMPOUND_EXPR); pedantic_lvalue_warning (COMPOUND_EXPR);
return build (COMPOUND_EXPR, TREE_TYPE (real_result), return build (COMPOUND_EXPR, TREE_TYPE (real_result),
...@@ -3274,14 +3324,15 @@ unary_complex_lvalue (code, arg) ...@@ -3274,14 +3324,15 @@ unary_complex_lvalue (code, arg)
/* Handle (a ? b : c) used as an "lvalue". */ /* Handle (a ? b : c) used as an "lvalue". */
if (TREE_CODE (arg) == COND_EXPR) if (TREE_CODE (arg) == COND_EXPR)
{ {
pedantic_lvalue_warning (COND_EXPR); if (!flag)
if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE) pedantic_lvalue_warning (COND_EXPR);
if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE && !flag)
pedantic_lvalue_warning (COMPOUND_EXPR); pedantic_lvalue_warning (COMPOUND_EXPR);
return (build_conditional_expr return (build_conditional_expr
(TREE_OPERAND (arg, 0), (TREE_OPERAND (arg, 0),
build_unary_op (code, TREE_OPERAND (arg, 1), 0), build_unary_op (code, TREE_OPERAND (arg, 1), flag),
build_unary_op (code, TREE_OPERAND (arg, 2), 0))); build_unary_op (code, TREE_OPERAND (arg, 2), flag)));
} }
return 0; return 0;
...@@ -3616,9 +3667,11 @@ internal_build_compound_expr (list, first_p) ...@@ -3616,9 +3667,11 @@ internal_build_compound_expr (list, first_p)
if (TREE_CHAIN (list) == 0) if (TREE_CHAIN (list) == 0)
{ {
/* Convert arrays to pointers when there really is a comma operator. */ /* Convert arrays and functions to pointers when there
if (!first_p && TREE_CODE (TREE_TYPE (TREE_VALUE (list))) == ARRAY_TYPE) really is a comma operator. */
TREE_VALUE (list) = default_conversion (TREE_VALUE (list)); if (!first_p)
TREE_VALUE (list)
= default_function_array_conversion (TREE_VALUE (list));
#if 0 /* If something inside inhibited lvalueness, we should not override. */ #if 0 /* If something inside inhibited lvalueness, we should not override. */
/* Consider (x, y+0), which is not an lvalue since y+0 is not. */ /* Consider (x, y+0), which is not an lvalue since y+0 is not. */
...@@ -3705,9 +3758,7 @@ build_c_cast (type, expr) ...@@ -3705,9 +3758,7 @@ build_c_cast (type, expr)
else if (TREE_CODE (type) == UNION_TYPE) else if (TREE_CODE (type) == UNION_TYPE)
{ {
tree field; tree field;
if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE value = default_function_array_conversion (value);
|| TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE)
value = default_conversion (value);
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)), if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
...@@ -3750,9 +3801,7 @@ build_c_cast (type, expr) ...@@ -3750,9 +3801,7 @@ build_c_cast (type, expr)
/* Convert functions and arrays to pointers, /* Convert functions and arrays to pointers,
but don't convert any other types. */ but don't convert any other types. */
if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE value = default_function_array_conversion (value);
|| TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE)
value = default_conversion (value);
otype = TREE_TYPE (value); otype = TREE_TYPE (value);
/* Optionally warn about potentially worrisome casts. */ /* Optionally warn about potentially worrisome casts. */
...@@ -3952,9 +4001,7 @@ build_modify_expr (lhs, modifycode, rhs) ...@@ -3952,9 +4001,7 @@ build_modify_expr (lhs, modifycode, rhs)
case FIX_FLOOR_EXPR: case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR: case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR: case FIX_CEIL_EXPR:
if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE newrhs = default_function_array_conversion (newrhs);
|| TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE)
newrhs = default_conversion (newrhs);
{ {
tree inner_lhs = TREE_OPERAND (lhs, 0); tree inner_lhs = TREE_OPERAND (lhs, 0);
tree result; tree result;
...@@ -4734,10 +4781,8 @@ digest_init (type, init, require_constant, constructor_constant) ...@@ -4734,10 +4781,8 @@ digest_init (type, init, require_constant, constructor_constant)
&& comptypes (TREE_TYPE (TREE_TYPE (inside_init)), && comptypes (TREE_TYPE (TREE_TYPE (inside_init)),
TREE_TYPE (type))))) TREE_TYPE (type)))))
{ {
if (code == POINTER_TYPE if (code == POINTER_TYPE)
&& (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE inside_init = default_function_array_conversion (inside_init);
|| TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE))
inside_init = default_conversion (inside_init);
else if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST else if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST
&& TREE_CODE (inside_init) != CONSTRUCTOR) && TREE_CODE (inside_init) != CONSTRUCTOR)
{ {
...@@ -6862,9 +6907,7 @@ build_asm_stmt (cv_qualifier, string, outputs, inputs, clobbers) ...@@ -6862,9 +6907,7 @@ build_asm_stmt (cv_qualifier, string, outputs, inputs, clobbers)
Don't do this for other types as it would screw up operands Don't do this for other types as it would screw up operands
expected to be in memory. */ expected to be in memory. */
for (tail = inputs; tail; tail = TREE_CHAIN (tail)) for (tail = inputs; tail; tail = TREE_CHAIN (tail))
if (TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == ARRAY_TYPE TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
|| TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE)
TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail));
return add_stmt (build_stmt (ASM_STMT, cv_qualifier, string, return add_stmt (build_stmt (ASM_STMT, cv_qualifier, string,
outputs, inputs, clobbers)); outputs, inputs, clobbers));
......
...@@ -1540,10 +1540,12 @@ removed. ...@@ -1540,10 +1540,12 @@ removed.
@cindex arrays, non-lvalue @cindex arrays, non-lvalue
@cindex subscripting and function values @cindex subscripting and function values
Subscripting is allowed on arrays that are not lvalues, even though the In ISO C99, arrays that are not lvalues still decay to pointers, and
unary @samp{&} operator is not. (In ISO C99, both are allowed (though may be subscripted, although they may not be modified or used after
the array may not be used after the next sequence point), but this ISO the next sequence point and the unary @samp{&} operator may not be
C99 feature is not yet fully supported in GCC@.) For example, applied to them. As an extension, GCC allows such arrays to be
subscripted in C89 mode, though otherwise they do not decay to
pointers outside C99 mode. For example,
this is valid in GNU C though not valid in C89: this is valid in GNU C though not valid in C89:
@example @example
......
2001-11-06 Joseph S. Myers <jsm28@cam.ac.uk>
* gcc.dg/c90-array-lval-1.c, gcc.dg/c90-array-lval-2.c,
gcc.dg/c99-array-lval-1.c, gcc.dg/c99-array-lval-2.c: Remove
XFAILs. Adjust expected error texts.
* gcc.c-torture/compile/20011106-1.c,
gcc.c-torture/compile/20011106-2.c, gcc.dg/c90-array-lval-3.c,
gcc.dg/c90-array-lval-4.c, gcc.dg/c90-array-lval-5.c,
gcc.dg/c99-array-lval-3.c, gcc.dg/c99-array-lval-4.c,
gcc.dg/c99-array-lval-5.c: New tests.
2001-11-05 Neil Booth <neil@cat.daikokuya.demon.co.uk> 2001-11-05 Neil Booth <neil@cat.daikokuya.demon.co.uk>
* gcc.dg/cpp/defined.c: Update. * gcc.dg/cpp/defined.c: Update.
......
/* Test that functions passed to the comma operator are correctly converted
to pointers. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk>. */
void foo (void);
void (*fp) (void);
char x[sizeof (1, foo) == sizeof (fp) ? 1 : -1];
/* Test the the type of a component of a conditional expression between
two structures is correct. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk>. */
struct s { char c; } a, b;
int c;
char x[sizeof ((c ? a : b).c) == 1 ? 1 : -1];
...@@ -16,6 +16,6 @@ bar (void) ...@@ -16,6 +16,6 @@ bar (void)
(foo ()).c + 1; /* { dg-bogus "warning" "warning in place of error" } */ (foo ()).c + 1; /* { dg-bogus "warning" "warning in place of error" } */
} }
/* { dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 14 } /* { dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 14 }
{ dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 15 } { dg-error "non-lvalue|incompatible" "array not decaying to lvalue" { target *-*-* } 15 }
{ dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 16 } { dg-error "non-lvalue|invalid" "array not decaying to lvalue" { target *-*-* } 16 }
*/ */
...@@ -17,4 +17,4 @@ ASSERT (r, sizeof ((foo ()).c) == 17); ...@@ -17,4 +17,4 @@ ASSERT (r, sizeof ((foo ()).c) == 17);
/* The non-lvalue array does not decay to a pointer, so the comma expression /* The non-lvalue array does not decay to a pointer, so the comma expression
has (non-lvalue) array type. has (non-lvalue) array type.
*/ */
ASSERT (s, sizeof (0, (foo ()).c) == 17); /* { dg-bogus "array" "bad non-lvalue array handling" { xfail *-*-* } } */ ASSERT (s, sizeof (0, (foo ()).c) == 17); /* { dg-bogus "array" "bad non-lvalue array handling" } */
/* Test for non-lvalue arrays decaying to pointers: in C99 only.
Test various ways of producing non-lvalue arrays. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
struct s { char c[1]; };
struct s a, b, c;
int d;
void
bar (void)
{
char *t;
(d ? b : c).c[0]; /* { dg-bogus "warning" "warning in place of error" } */
(d, b).c[0]; /* { dg-bogus "warning" "warning in place of error" } */
(a = b).c[0]; /* { dg-bogus "warning" "warning in place of error" } */
t = (d ? b : c).c; /* { dg-bogus "warning" "warning in place of error" } */
t = (d, b).c; /* { dg-bogus "warning" "warning in place of error" } */
t = (a = b).c; /* { dg-bogus "warning" "warning in place of error" } */
(d ? b : c).c + 1; /* { dg-bogus "warning" "warning in place of error" } */
(d, b).c + 1; /* { dg-bogus "warning" "warning in place of error" } */
(a = b).c + 1; /* { dg-bogus "warning" "warning in place of error" } */
}
/* { dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 15 }
{ dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 16 }
{ dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 17 }
{ dg-error "non-lvalue|incompatible" "array not decaying to lvalue" { target *-*-* } 18 }
{ dg-error "non-lvalue|incompatible" "array not decaying to lvalue" { target *-*-* } 19 }
{ dg-error "non-lvalue|incompatible" "array not decaying to lvalue" { target *-*-* } 20 }
{ dg-error "non-lvalue|invalid" "array not decaying to lvalue" { target *-*-* } 21 }
{ dg-error "non-lvalue|invalid" "array not decaying to lvalue" { target *-*-* } 22 }
{ dg-error "non-lvalue|invalid" "array not decaying to lvalue" { target *-*-* } 23 }
*/
/* Test for non-lvalue arrays decaying to pointers: in C99 only.
Test various ways of producing non-lvalue arrays. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
struct s { char c[17]; };
struct s x;
struct s a, b, c;
int d;
#define ASSERT(v, a) char v[((a) ? 1 : -1)]
ASSERT (p, sizeof (x.c) == 17);
ASSERT (q, sizeof (0, x.c) == sizeof (char *));
ASSERT (r0, sizeof ((d ? b : c).c) == 17);
ASSERT (r1, sizeof ((d, b).c) == 17);
ASSERT (r2, sizeof ((a = b).c) == 17);
/* The non-lvalue array does not decay to a pointer, so the comma expression
has (non-lvalue) array type.
*/
ASSERT (s0, sizeof (0, (d ? b : c).c) == 17); /* { dg-bogus "array" "bad non-lvalue array handling" } */
ASSERT (s0, sizeof (0, (d, b).c) == 17); /* { dg-bogus "array" "bad non-lvalue array handling" } */
ASSERT (s0, sizeof (0, (a = b).c) == 17); /* { dg-bogus "array" "bad non-lvalue array handling" } */
/* Test for non-lvalue arrays: test that the unary '&' operator is not
allowed on them, for both C90 and C99. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
struct s { char c[1]; };
extern struct s foo (void);
struct s a, b, c;
int d;
void
bar (void)
{
&((foo ()).c); /* { dg-bogus "warning" "warning in place of error" } */
&((d ? b : c).c); /* { dg-bogus "warning" "warning in place of error" } */
&((d, b).c); /* { dg-bogus "warning" "warning in place of error" } */
&((a = b).c); /* { dg-bogus "warning" "warning in place of error" } */
}
/* { dg-error "lvalue" "bad address-of" { target *-*-* } 17 }
{ dg-error "lvalue" "bad address-of" { target *-*-* } 18 }
{ dg-error "lvalue" "bad address-of" { target *-*-* } 19 }
{ dg-error "lvalue" "bad address-of" { target *-*-* } 20 }
*/
...@@ -12,6 +12,6 @@ bar (void) ...@@ -12,6 +12,6 @@ bar (void)
{ {
char *t; char *t;
(foo ()).c[0]; /* { dg-bogus "non-lvalue" "array not decaying to lvalue" } */ (foo ()).c[0]; /* { dg-bogus "non-lvalue" "array not decaying to lvalue" } */
t = (foo ()).c; /* { dg-bogus "non-lvalue" "array not decaying to lvalue" { xfail *-*-* } } */ t = (foo ()).c; /* { dg-bogus "non-lvalue" "array not decaying to lvalue" } */
(foo ()).c + 1; /* { dg-bogus "non-lvalue" "array not decaying to lvalue" { xfail *-*-* } } */ (foo ()).c + 1; /* { dg-bogus "non-lvalue" "array not decaying to lvalue" } */
} }
...@@ -15,4 +15,4 @@ ASSERT (p, sizeof (x.c) == 17); ...@@ -15,4 +15,4 @@ ASSERT (p, sizeof (x.c) == 17);
ASSERT (q, sizeof (0, x.c) == sizeof (char *)); ASSERT (q, sizeof (0, x.c) == sizeof (char *));
ASSERT (r, sizeof ((foo ()).c) == 17); ASSERT (r, sizeof ((foo ()).c) == 17);
/* The non-lvalue array decays to a pointer in C99. */ /* The non-lvalue array decays to a pointer in C99. */
ASSERT (s, sizeof (0, (foo ()).c) == sizeof (char *)); /* { dg-bogus "array" "bad non-lvalue array handling" { xfail *-*-* } } */ ASSERT (s, sizeof (0, (foo ()).c) == sizeof (char *)); /* { dg-bogus "array" "bad non-lvalue array handling" } */
/* Test for non-lvalue arrays decaying to pointers: in C99 only.
Test various ways of producing non-lvalue arrays. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
struct s { char c[1]; };
struct s a, b, c;
int d;
void
bar (void)
{
char *t;
(d ? b : c).c[0];
(d, b).c[0];
(a = b).c[0];
t = (d ? b : c).c;
t = (d, b).c;
t = (a = b).c;
(d ? b : c).c + 1;
(d, b).c + 1;
(a = b).c + 1;
}
/* Test for non-lvalue arrays decaying to pointers: in C99 only.
Test various ways of producing non-lvalue arrays. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
struct s { char c[17]; };
struct s x;
struct s a, b, c;
int d;
#define ASSERT(v, a) char v[((a) ? 1 : -1)]
ASSERT (p, sizeof (x.c) == 17);
ASSERT (q, sizeof (0, x.c) == sizeof (char *));
ASSERT (r0, sizeof ((d ? b : c).c) == 17);
ASSERT (r1, sizeof ((d, b).c) == 17);
ASSERT (r2, sizeof ((a = b).c) == 17);
/* The non-lvalue array decays to a pointer in C99. */
ASSERT (s0, sizeof (0, (d ? b : c).c) == sizeof (char *)); /* { dg-bogus "array" "bad non-lvalue array handling" } */
ASSERT (s0, sizeof (0, (d, b).c) == sizeof (char *)); /* { dg-bogus "array" "bad non-lvalue array handling" } */
ASSERT (s0, sizeof (0, (a = b).c) == sizeof (char *)); /* { dg-bogus "array" "bad non-lvalue array handling" } */
/* Test for non-lvalue arrays: test that the unary '&' operator is not
allowed on them, for both C90 and C99. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
struct s { char c[1]; };
extern struct s foo (void);
struct s a, b, c;
int d;
void
bar (void)
{
&((foo ()).c); /* { dg-bogus "warning" "warning in place of error" } */
&((d ? b : c).c); /* { dg-bogus "warning" "warning in place of error" } */
&((d, b).c); /* { dg-bogus "warning" "warning in place of error" } */
&((a = b).c); /* { dg-bogus "warning" "warning in place of error" } */
}
/* { dg-error "lvalue" "bad address-of" { target *-*-* } 17 }
{ dg-error "lvalue" "bad address-of" { target *-*-* } 18 }
{ dg-error "lvalue" "bad address-of" { target *-*-* } 19 }
{ dg-error "lvalue" "bad address-of" { target *-*-* } 20 }
*/
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment