c-decl.c (c_init_decl_processing): Set pedantic_lvalues to true unconditionally.

* c-decl.c (c_init_decl_processing): Set pedantic_lvalues to
	true unconditionally.
	* c-typeck.c (unary_complex_lvalue, pedantic_lvalue_warning):
	Remove.
	(build_unary_op, build_modify_expr): Don't handle extended
	lvalues.
	(build_component_ref, build_conditional_expr): Call non_lvalue
	instead of pedantic_non_lvalue.
	(build_c_cast): Don't condition use of non_lvalue on pedantic.
	* fold-const.c (fold): Don't check pedantic directly for
	COMPOUND_EXPR.  Ensure that results for COMPOUND_EXPR are
	passed to pedantic_non_lvalue.
	* doc/extend.texi: Remove documentation of extended lvalues.

testsuite:
	* gcc.c-torture/compile/981022-1.c: Remove.
	* gcc.dg/array-5.c: Remove XFAIL.
	* gcc.dg/sequence-pt-1.c: Remove test using extended lvalues.
	* gcc.dg/cast-lvalue-1.c, gcc.dg/compound-lvalue-1.c,
	gcc.dg/cond-lvalue-1.c: Update.
	* gcc.dg/cast-lvalue-2.c: New test.

From-SVN: r76192
This commit is contained in:
Joseph Myers 2004-01-20 01:38:27 +00:00 committed by Joseph Myers
parent 87d11ccc82
commit 53cd18ec8e
13 changed files with 56 additions and 315 deletions

View File

@ -1,3 +1,19 @@
2004-01-20 Joseph S. Myers <jsm@polyomino.org.uk>
* c-decl.c (c_init_decl_processing): Set pedantic_lvalues to
true unconditionally.
* c-typeck.c (unary_complex_lvalue, pedantic_lvalue_warning):
Remove.
(build_unary_op, build_modify_expr): Don't handle extended
lvalues.
(build_component_ref, build_conditional_expr): Call non_lvalue
instead of pedantic_non_lvalue.
(build_c_cast): Don't condition use of non_lvalue on pedantic.
* fold-const.c (fold): Don't check pedantic directly for
COMPOUND_EXPR. Ensure that results for COMPOUND_EXPR are
passed to pedantic_non_lvalue.
* doc/extend.texi: Remove documentation of extended lvalues.
2004-01-19 Roger Sayle <roger@eyesopen.com>
PR optimization/5263

View File

@ -2282,7 +2282,7 @@ c_init_decl_processing (void)
input_location = save_loc;
pedantic_lvalues = pedantic;
pedantic_lvalues = true;
make_fname_decl = c_make_fname_decl;
start_fname_decls ();

View File

@ -60,8 +60,6 @@ static tree default_function_array_conversion (tree);
static tree lookup_field (tree, tree);
static tree convert_arguments (tree, tree, tree, tree);
static tree pointer_diff (tree, tree);
static tree unary_complex_lvalue (enum tree_code, tree, int);
static void pedantic_lvalue_warning (enum tree_code);
static tree internal_build_compound_expr (tree, int);
static tree convert_for_assignment (tree, tree, const char *, tree, tree,
int);
@ -1303,7 +1301,7 @@ build_component_ref (tree datum, tree component)
tree ref;
/* If DATUM is a COMPOUND_EXPR, move our reference inside it.
If pedantic ensure that the arguments are not lvalues; otherwise,
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
@ -1316,7 +1314,7 @@ build_component_ref (tree datum, tree component)
{
tree value = build_component_ref (TREE_OPERAND (datum, 1), component);
return build (COMPOUND_EXPR, TREE_TYPE (value),
TREE_OPERAND (datum, 0), pedantic_non_lvalue (value));
TREE_OPERAND (datum, 0), non_lvalue (value));
}
default:
break;
@ -2287,12 +2285,6 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
case POSTINCREMENT_EXPR:
case PREDECREMENT_EXPR:
case POSTDECREMENT_EXPR:
/* Handle complex lvalues (when permitted)
by reduction to simpler cases. */
val = unary_complex_lvalue (code, arg, 0);
if (val != 0)
return val;
/* Increment or decrement the real part of the value,
and don't change the imaginary part. */
@ -2360,57 +2352,6 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
inc = convert (argtype, inc);
/* Handle incrementing a cast-expression. */
while (1)
switch (TREE_CODE (arg))
{
case NOP_EXPR:
case CONVERT_EXPR:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
pedantic_lvalue_warning (CONVERT_EXPR);
/* If the real type has the same machine representation
as the type it is cast to, we can make better output
by adding directly to the inside of the cast. */
if ((TREE_CODE (TREE_TYPE (arg))
== TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 0))))
&& (TYPE_MODE (TREE_TYPE (arg))
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (arg, 0)))))
arg = TREE_OPERAND (arg, 0);
else
{
tree incremented, modify, value;
if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
value = boolean_increment (code, arg);
else
{
arg = stabilize_reference (arg);
if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
value = arg;
else
value = save_expr (arg);
incremented = build (((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? PLUS_EXPR : MINUS_EXPR),
argtype, value, inc);
TREE_SIDE_EFFECTS (incremented) = 1;
modify = build_modify_expr (arg, NOP_EXPR, incremented);
value = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
}
TREE_USED (value) = 1;
return value;
}
break;
default:
goto give_up;
}
give_up:
/* Complain about anything else that is not a true lvalue. */
if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
@ -2457,12 +2398,6 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
TREE_OPERAND (arg, 1), 1);
}
/* Handle complex lvalues (when permitted)
by reduction to simpler cases. */
val = unary_complex_lvalue (code, arg, flag);
if (val != 0)
return val;
/* Anything not already handled and not a true memory reference
or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE && !flag
@ -2580,67 +2515,6 @@ lvalue_or_else (tree ref, const char *msgid)
return win;
}
/* 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. 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 (enum tree_code code, tree arg, int flag)
{
/* Handle (a, b) used as an "lvalue". */
if (TREE_CODE (arg) == COMPOUND_EXPR)
{
tree real_result = build_unary_op (code, TREE_OPERAND (arg, 1), 0);
/* 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 && !flag)
pedantic_lvalue_warning (COMPOUND_EXPR);
return build (COMPOUND_EXPR, TREE_TYPE (real_result),
TREE_OPERAND (arg, 0), real_result);
}
/* Handle (a ? b : c) used as an "lvalue". */
if (TREE_CODE (arg) == COND_EXPR)
{
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), flag),
build_unary_op (code, TREE_OPERAND (arg, 2), flag)));
}
return 0;
}
/* If pedantic, warn about improper lvalue. CODE is either COND_EXPR
COMPOUND_EXPR, or CONVERT_EXPR (for casts). */
static void
pedantic_lvalue_warning (enum tree_code code)
{
switch (code)
{
case COND_EXPR:
pedwarn ("use of conditional expressions as lvalues is deprecated");
break;
case COMPOUND_EXPR:
pedwarn ("use of compound expressions as lvalues is deprecated");
break;
default:
pedwarn ("use of cast expressions as lvalues is deprecated");
break;
}
}
/* Warn about storing in something that is `const'. */
@ -2901,7 +2775,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
op2 = convert_and_check (result_type, op2);
if (TREE_CODE (ifexp) == INTEGER_CST)
return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1);
return non_lvalue (integer_zerop (ifexp) ? op2 : op1);
return fold (build (COND_EXPR, result_type, ifexp, op1, op2));
}
@ -3158,14 +3032,14 @@ build_c_cast (tree type, tree expr)
}
}
/* Pedantically, don't let (void *) (FOO *) 0 be a null pointer constant. */
if (pedantic && TREE_CODE (value) == INTEGER_CST
/* Don't let (void *) (FOO *) 0 be a null pointer constant. */
if (TREE_CODE (value) == INTEGER_CST
&& TREE_CODE (expr) == INTEGER_CST
&& TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE)
value = non_lvalue (value);
/* If pedantic, don't let a cast be an lvalue. */
if (value == expr && pedantic)
/* Don't let a cast be an lvalue. */
if (value == expr)
value = non_lvalue (value);
return value;
@ -3216,45 +3090,6 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
newrhs = rhs;
/* Handle control structure constructs used as "lvalues". */
switch (TREE_CODE (lhs))
{
/* Handle (a, b) used as an "lvalue". */
case COMPOUND_EXPR:
pedantic_lvalue_warning (COMPOUND_EXPR);
newrhs = build_modify_expr (TREE_OPERAND (lhs, 1), modifycode, rhs);
if (TREE_CODE (newrhs) == ERROR_MARK)
return error_mark_node;
return build (COMPOUND_EXPR, lhstype,
TREE_OPERAND (lhs, 0), newrhs);
/* Handle (a ? b : c) used as an "lvalue". */
case COND_EXPR:
pedantic_lvalue_warning (COND_EXPR);
rhs = save_expr (rhs);
{
/* Produce (a ? (b = rhs) : (c = rhs))
except that the RHS goes through a save-expr
so the code to compute it is only emitted once. */
tree cond
= build_conditional_expr (TREE_OPERAND (lhs, 0),
build_modify_expr (TREE_OPERAND (lhs, 1),
modifycode, rhs),
build_modify_expr (TREE_OPERAND (lhs, 2),
modifycode, rhs));
if (TREE_CODE (cond) == ERROR_MARK)
return cond;
/* Make sure the code to compute the rhs comes out
before the split. */
return build (COMPOUND_EXPR, TREE_TYPE (lhs),
/* But cast it to void to avoid an "unused" error. */
convert (void_type_node, rhs), cond);
}
default:
break;
}
/* If a binary op has been requested, combine the old LHS value with the RHS
producing the value we should actually store into the LHS. */
@ -3264,42 +3099,6 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
newrhs = build_binary_op (modifycode, lhs, rhs, 1);
}
/* Handle a cast used as an "lvalue".
We have already performed any binary operator using the value as cast.
Now convert the result to the cast type of the lhs,
and then true type of the lhs and store it there;
then convert result back to the cast type to be the value
of the assignment. */
switch (TREE_CODE (lhs))
{
case NOP_EXPR:
case CONVERT_EXPR:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
newrhs = default_function_array_conversion (newrhs);
{
tree inner_lhs = TREE_OPERAND (lhs, 0);
tree result;
result = build_modify_expr (inner_lhs, NOP_EXPR,
convert (TREE_TYPE (inner_lhs),
convert (lhstype, newrhs)));
if (TREE_CODE (result) == ERROR_MARK)
return result;
pedantic_lvalue_warning (CONVERT_EXPR);
return convert (TREE_TYPE (lhs), result);
}
default:
break;
}
/* Now we have handled acceptable kinds of LHS that are not truly lvalues.
Reject anything strange now. */
if (!lvalue_or_else (lhs, "invalid lvalue in assignment"))
return error_mark_node;

View File

@ -429,7 +429,6 @@ extensions, accepted by GCC in C89 mode and in C++.
* Nested Functions:: As in Algol and Pascal, lexical scoping of functions.
* Constructing Calls:: Dispatching a call to another function.
* Typeof:: @code{typeof}: referring to the type of an expression.
* Lvalues:: Using @samp{?:}, @samp{,} and casts in lvalues.
* Conditionals:: Omitting the middle operand of a @samp{?:} expression.
* Long Long:: Double-word integers---@code{long long int}.
* Complex:: Data types for complex numbers.
@ -1060,94 +1059,6 @@ typedef typeof(@var{expr}) @var{T};
@noindent
This will work with all versions of GCC@.
@node Lvalues
@section Generalized Lvalues
@cindex compound expressions as lvalues
@cindex expressions, compound, as lvalues
@cindex conditional expressions as lvalues
@cindex expressions, conditional, as lvalues
@cindex casts as lvalues
@cindex generalized lvalues
@cindex lvalues, generalized
@cindex extensions, @code{?:}
@cindex @code{?:} extensions
Compound expressions, conditional expressions and casts are allowed as
lvalues provided their operands are lvalues. This means that you can take
their addresses or store values into them. All these extensions are
deprecated.
Standard C++ allows compound expressions and conditional expressions
as lvalues, and permits casts to reference type, so use of this
extension is not supported for C++ code.
For example, a compound expression can be assigned, provided the last
expression in the sequence is an lvalue. These two expressions are
equivalent:
@smallexample
(a, b) += 5
a, (b += 5)
@end smallexample
Similarly, the address of the compound expression can be taken. These two
expressions are equivalent:
@smallexample
&(a, b)
a, &b
@end smallexample
A conditional expression is a valid lvalue if its type is not void and the
true and false branches are both valid lvalues. For example, these two
expressions are equivalent:
@smallexample
(a ? b : c) = 5
(a ? b = 5 : (c = 5))
@end smallexample
A cast is a valid lvalue if its operand is an lvalue. This extension
is deprecated. A simple
assignment whose left-hand side is a cast works by converting the
right-hand side first to the specified type, then to the type of the
inner left-hand side expression. After this is stored, the value is
converted back to the specified type to become the value of the
assignment. Thus, if @code{a} has type @code{char *}, the following two
expressions are equivalent:
@smallexample
(int)a = 5
(int)(a = (char *)(int)5)
@end smallexample
An assignment-with-arithmetic operation such as @samp{+=} applied to a cast
performs the arithmetic using the type resulting from the cast, and then
continues as in the previous case. Therefore, these two expressions are
equivalent:
@smallexample
(int)a += 5
(int)(a = (char *)(int) ((int)a + 5))
@end smallexample
You cannot take the address of an lvalue cast, because the use of its
address would not work out coherently. Suppose that @code{&(int)f} were
permitted, where @code{f} has type @code{float}. Then the following
statement would try to store an integer bit-pattern where a floating
point number belongs:
@smallexample
*&(int)f = 1;
@end smallexample
This is quite different from what @code{(int)f = 1} would do---that
would convert 1 to floating point and store it. Rather than cause this
inconsistency, we think it is better to prohibit use of @samp{&} on a cast.
If you really do want an @code{int *} pointer with the address of
@code{f}, you can simply write @code{(int *)&f}.
@node Conditionals
@section Conditionals with Omitted Operands
@cindex conditional expressions, extensions

View File

@ -8170,12 +8170,12 @@ fold (tree expr)
case COMPOUND_EXPR:
/* When pedantic, a compound expression can be neither an lvalue
nor an integer constant expression. */
if (TREE_SIDE_EFFECTS (arg0) || pedantic)
if (TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1))
return t;
/* Don't let (0, 0) be null pointer constant. */
if (integer_zerop (arg1))
return build1 (NOP_EXPR, type, arg1);
return convert (type, arg1);
return pedantic_non_lvalue (build1 (NOP_EXPR, type, arg1));
return pedantic_non_lvalue (convert (type, arg1));
case COMPLEX_EXPR:
if (wins)

View File

@ -1,3 +1,12 @@
2004-01-20 Joseph S. Myers <jsm@polyomino.org.uk>
* gcc.c-torture/compile/981022-1.c: Remove.
* gcc.dg/array-5.c: Remove XFAIL.
* gcc.dg/sequence-pt-1.c: Remove test using extended lvalues.
* gcc.dg/cast-lvalue-1.c, gcc.dg/compound-lvalue-1.c,
gcc.dg/cond-lvalue-1.c: Update.
* gcc.dg/cast-lvalue-2.c: New test.
2004-01-19 Mark Mitchell <mark@codesourcery.com>
PR c++/13592

View File

@ -1,9 +0,0 @@
/* This tests a combination of two gcc extensions. Omitting the middle
operand of ?: and using ?: as an lvalue. */
int x, y;
int main ()
{
(x ?: y) = 0; /* { dg-bogus "lvalue" "" { xfail *-*-* } } */
return 0;
}

View File

@ -37,6 +37,6 @@ void func(int n, int m)
expression, and thus A is a VLA. */
int a[6][(2, 2)];
int (*p)[3];
p = a; /* { dg-bogus "incompatible" "bad vla handling" { xfail *-*-* } } */
p = a; /* { dg-bogus "incompatible" "bad vla handling" } */
}
}

View File

@ -8,5 +8,6 @@ int x;
void
foo (void)
{
(char) x = 1; /* { dg-warning "lvalue" "cast as lvalue deprecated" } */
(char) x = 1; /* { dg-bogus "warning" "warning in place of error" } */
}
/* { dg-error "lvalue" "cast as lvalue" { target *-*-* } 11 } */

View File

@ -0,0 +1,13 @@
/* Test for error on casts as lvalues. Casts to same type. */
/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
/* { dg-do compile } */
/* { dg-options "" } */
int x;
void
foo (void)
{
(int) x = 1; /* { dg-bogus "warning" "warning in place of error" } */
}
/* { dg-error "lvalue" "cast as lvalue" { target *-*-*} 11 } */

View File

@ -8,5 +8,6 @@ int x, y;
void
foo (void)
{
(x, y) = 1; /* { dg-warning "lvalue" "compound expression as lvalue deprecated" } */
(x, y) = 1; /* { dg-bogus "warning" "warning in place of error" } */
}
/* { dg-error "lvalue" "compound expression as lvalue" { target *-*-* } 11 } */

View File

@ -8,5 +8,6 @@ int x, y, z;
void
foo (void)
{
(x ? y : z) = 1; /* { dg-warning "lvalue" "conditional expression as lvalue deprecated" } */
(x ? y : z) = 1; /* { dg-bogus "warning" "warning in place of error" } */
}
/* { dg-error "lvalue" "conditional expression as lvalue" { target *-*-* } 11 } */

View File

@ -58,7 +58,6 @@ foo (int a, int b, int n, int p, int *ptr, struct s *sptr,
b = a, a = a++; /* { dg-warning "undefined" "sequence point warning" } */
a = (b++ ? n : a) + b; /* { dg-warning "undefined" "sequence point warning" { xfail *-*-* } } */
b ? a = a++ : a; /* { dg-warning "undefined" "sequence point warning" } */
b ? a : a = a++; /* { dg-warning "undefined" "sequence point warning" } */
b && (a = a++); /* { dg-warning "undefined" "sequence point warning" } */
(a = a++) && b; /* { dg-warning "undefined" "sequence point warning" } */
b, (a = a++); /* { dg-warning "undefined" "sequence point warning" } */