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
This commit is contained in:
Joseph Myers 2001-11-06 12:39:36 +00:00 committed by Joseph Myers
parent 25cece2fbd
commit 207bf4854d
17 changed files with 381 additions and 124 deletions

View File

@ -1,3 +1,29 @@
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>
* aclocal.m4: (AM_WITH_NLS): Don't look at ALL_LINGUAS.

View File

@ -1181,7 +1181,8 @@ c_expand_expr_stmt (expr)
{
/* Do default conversion if safe and possibly important,
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)
expr = default_conversion (expr);

View File

@ -55,11 +55,12 @@ static int comp_target_types PARAMS ((tree, tree));
static int function_types_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 default_function_array_conversion PARAMS ((tree));
static tree lookup_field PARAMS ((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_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 tree internal_build_compound_expr PARAMS ((tree, int));
static tree convert_for_assignment PARAMS ((tree, tree, const char *,
@ -838,6 +839,110 @@ decl_constant_value_for_broken_optimization (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.
Arrays and functions are converted to pointers;
enumeral types or short or char, to int.
@ -851,6 +956,9 @@ default_conversion (exp)
tree type = TREE_TYPE (exp);
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. */
if (TREE_CODE (exp) == CONST_DECL)
exp = DECL_INITIAL (exp);
@ -924,69 +1032,6 @@ default_conversion (exp)
error ("void value not ignored as it ought to be");
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;
}
@ -1098,22 +1143,22 @@ build_component_ref (datum, component)
tree field = NULL;
tree ref;
/* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it
unless we are not to support things not strictly ANSI. */
/* If DATUM is a COMPOUND_EXPR, move our reference inside it.
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))
{
case COMPOUND_EXPR:
{
tree value = build_component_ref (TREE_OPERAND (datum, 1), component);
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:
break;
}
@ -1586,9 +1631,7 @@ convert_arguments (typelist, values, name, fundecl)
if (TREE_CODE (val) == NON_LVALUE_EXPR)
val = TREE_OPERAND (val, 0);
if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE)
val = default_conversion (val);
val = default_function_array_conversion (val);
val = require_complete_type (val);
@ -2771,20 +2814,25 @@ pointer_diff (op0, op1)
/* Construct and perhaps optimize a tree representation
for a unary operation. CODE, a tree_code, specifies the operation
and XARG is the operand. NOCONVERT nonzero suppresses
the default promotions (such as from short to int). */
and XARG is the operand.
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
build_unary_op (code, xarg, noconvert)
build_unary_op (code, xarg, flag)
enum tree_code code;
tree xarg;
int noconvert;
int flag;
{
/* No default_conversion here. It causes trouble for ADDR_EXPR. */
tree arg = xarg;
tree argtype = 0;
enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
tree val;
int noconvert = flag;
if (typecode == ERROR_MARK)
return error_mark_node;
@ -2898,7 +2946,7 @@ build_unary_op (code, xarg, noconvert)
/* Handle complex lvalues (when permitted)
by reduction to simpler cases. */
val = unary_complex_lvalue (code, arg);
val = unary_complex_lvalue (code, arg, 0);
if (val != 0)
return val;
@ -3045,8 +3093,7 @@ build_unary_op (code, xarg, noconvert)
}
case ADDR_EXPR:
/* Note that this operation never does default_conversion
regardless of NOCONVERT. */
/* Note that this operation never does default_conversion. */
/* Let &* cancel out to simplify resulting code. */
if (TREE_CODE (arg) == INDIRECT_REF)
@ -3068,7 +3115,7 @@ build_unary_op (code, xarg, noconvert)
/* Handle complex lvalues (when permitted)
by reduction to simpler cases. */
val = unary_complex_lvalue (code, arg);
val = unary_complex_lvalue (code, arg, flag);
if (val != 0)
return val;
@ -3099,8 +3146,8 @@ build_unary_op (code, xarg, noconvert)
if (TREE_CODE (arg) == CONSTRUCTOR && TREE_CONSTANT (arg))
;
/* Anything not already handled and not a true memory reference
is an error. */
else if (typecode != FUNCTION_TYPE
or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE && !flag
&& !lvalue_or_else (arg, "invalid lvalue in unary `&'"))
return error_mark_node;
@ -3129,7 +3176,7 @@ build_unary_op (code, xarg, noconvert)
{
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))
{
@ -3248,14 +3295,17 @@ lvalue_or_else (ref, msgid)
/* Apply unary lvalue-demanding operator CODE to the expression ARG
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. */
static tree
unary_complex_lvalue (code, arg)
unary_complex_lvalue (code, arg, flag)
enum tree_code code;
tree arg;
int flag;
{
/* Handle (a, b) used as an "lvalue". */
if (TREE_CODE (arg) == COMPOUND_EXPR)
@ -3264,7 +3314,7 @@ unary_complex_lvalue (code, arg)
/* If this returns a function type, it isn't really being used as
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);
return build (COMPOUND_EXPR, TREE_TYPE (real_result),
@ -3274,14 +3324,15 @@ unary_complex_lvalue (code, arg)
/* Handle (a ? b : c) used as an "lvalue". */
if (TREE_CODE (arg) == COND_EXPR)
{
pedantic_lvalue_warning (COND_EXPR);
if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE)
if (!flag)
pedantic_lvalue_warning (COND_EXPR);
if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE && !flag)
pedantic_lvalue_warning (COMPOUND_EXPR);
return (build_conditional_expr
(TREE_OPERAND (arg, 0),
build_unary_op (code, TREE_OPERAND (arg, 1), 0),
build_unary_op (code, TREE_OPERAND (arg, 2), 0)));
build_unary_op (code, TREE_OPERAND (arg, 1), flag),
build_unary_op (code, TREE_OPERAND (arg, 2), flag)));
}
return 0;
@ -3616,9 +3667,11 @@ internal_build_compound_expr (list, first_p)
if (TREE_CHAIN (list) == 0)
{
/* Convert arrays to pointers when there really is a comma operator. */
if (!first_p && TREE_CODE (TREE_TYPE (TREE_VALUE (list))) == ARRAY_TYPE)
TREE_VALUE (list) = default_conversion (TREE_VALUE (list));
/* Convert arrays and functions to pointers when there
really is a comma operator. */
if (!first_p)
TREE_VALUE (list)
= default_function_array_conversion (TREE_VALUE (list));
#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. */
@ -3705,9 +3758,7 @@ build_c_cast (type, expr)
else if (TREE_CODE (type) == UNION_TYPE)
{
tree field;
if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE)
value = default_conversion (value);
value = default_function_array_conversion (value);
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
@ -3750,9 +3801,7 @@ build_c_cast (type, expr)
/* Convert functions and arrays to pointers,
but don't convert any other types. */
if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE)
value = default_conversion (value);
value = default_function_array_conversion (value);
otype = TREE_TYPE (value);
/* Optionally warn about potentially worrisome casts. */
@ -3952,9 +4001,7 @@ build_modify_expr (lhs, modifycode, rhs)
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE)
newrhs = default_conversion (newrhs);
newrhs = default_function_array_conversion (newrhs);
{
tree inner_lhs = TREE_OPERAND (lhs, 0);
tree result;
@ -4734,10 +4781,8 @@ digest_init (type, init, require_constant, constructor_constant)
&& comptypes (TREE_TYPE (TREE_TYPE (inside_init)),
TREE_TYPE (type)))))
{
if (code == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE))
inside_init = default_conversion (inside_init);
if (code == POINTER_TYPE)
inside_init = default_function_array_conversion (inside_init);
else if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST
&& TREE_CODE (inside_init) != CONSTRUCTOR)
{
@ -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
expected to be in memory. */
for (tail = inputs; tail; tail = TREE_CHAIN (tail))
if (TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE)
TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail));
TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
return add_stmt (build_stmt (ASM_STMT, cv_qualifier, string,
outputs, inputs, clobbers));

View File

@ -1540,10 +1540,12 @@ removed.
@cindex arrays, non-lvalue
@cindex subscripting and function values
Subscripting is allowed on arrays that are not lvalues, even though the
unary @samp{&} operator is not. (In ISO C99, both are allowed (though
the array may not be used after the next sequence point), but this ISO
C99 feature is not yet fully supported in GCC@.) For example,
In ISO C99, arrays that are not lvalues still decay to pointers, and
may be subscripted, although they may not be modified or used after
the next sequence point and the unary @samp{&} operator may not be
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:
@example

View File

@ -1,3 +1,14 @@
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>
* gcc.dg/cpp/defined.c: Update.

View File

@ -0,0 +1,7 @@
/* 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];

View File

@ -0,0 +1,7 @@
/* 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];

View File

@ -16,6 +16,6 @@ bar (void)
(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 *-*-* } 15 }
{ dg-error "non-lvalue" "array not decaying to lvalue" { target *-*-* } 16 }
{ dg-error "non-lvalue|incompatible" "array not decaying to lvalue" { target *-*-* } 15 }
{ dg-error "non-lvalue|invalid" "array not decaying to lvalue" { target *-*-* } 16 }
*/

View File

@ -17,4 +17,4 @@ ASSERT (r, sizeof ((foo ()).c) == 17);
/* The non-lvalue array does not decay to a pointer, so the comma expression
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" } */

View File

@ -0,0 +1,34 @@
/* 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 }
*/

View File

@ -0,0 +1,26 @@
/* 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" } */

View File

@ -0,0 +1,26 @@
/* 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 }
*/

View File

@ -12,6 +12,6 @@ bar (void)
{
char *t;
(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 *-*-* } } */
(foo ()).c + 1; /* { 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" } */
}

View File

@ -15,4 +15,4 @@ ASSERT (p, sizeof (x.c) == 17);
ASSERT (q, sizeof (0, x.c) == sizeof (char *));
ASSERT (r, sizeof ((foo ()).c) == 17);
/* 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" } */

View File

@ -0,0 +1,24 @@
/* 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;
}

View File

@ -0,0 +1,24 @@
/* 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" } */

View File

@ -0,0 +1,26 @@
/* 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 }
*/