Commit 9bf24266 by Joseph Myers Committed by Joseph Myers

c-tree.h (readonly_error): Remove.

	* c-tree.h (readonly_error): Remove.
	* c-typeck (enum lvalue_use): New.
	(lvalue_or_else, readonly_error): Use it.  All callers changed.
	(readonly_error): Make static.

testsuite:
	* gcc.dg/lvalue-2.c: New test.

From-SVN: r88362
parent 29e12ba8
2004-09-30 Joseph S. Myers <jsm@polyomino.org.uk>
* c-tree.h (readonly_error): Remove.
* c-typeck (enum lvalue_use): New.
(lvalue_or_else, readonly_error): Use it. All callers changed.
(readonly_error): Make static.
2004-09-30 Jan Hubicka <jh@suse.cz> 2004-09-30 Jan Hubicka <jh@suse.cz>
PR debug/13974 PR debug/13974
......
...@@ -428,7 +428,6 @@ extern struct c_expr c_expr_sizeof_expr (struct c_expr); ...@@ -428,7 +428,6 @@ extern struct c_expr c_expr_sizeof_expr (struct c_expr);
extern struct c_expr c_expr_sizeof_type (struct c_type_name *); extern struct c_expr c_expr_sizeof_type (struct c_type_name *);
extern struct c_expr parser_build_binary_op (enum tree_code, struct c_expr, extern struct c_expr parser_build_binary_op (enum tree_code, struct c_expr,
struct c_expr); struct c_expr);
extern void readonly_error (tree, const char *);
extern tree build_conditional_expr (tree, tree, tree); extern tree build_conditional_expr (tree, tree, tree);
extern tree build_compound_expr (tree, tree); extern tree build_compound_expr (tree, tree);
extern tree c_cast_expr (struct c_type_name *, tree); extern tree c_cast_expr (struct c_type_name *, tree);
......
...@@ -44,6 +44,17 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -44,6 +44,17 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tree-iterator.h" #include "tree-iterator.h"
#include "tree-gimple.h" #include "tree-gimple.h"
/* Places where an lvalue, or modifiable lvalue, may be required.
Used to select diagnostic messages in lvalue_or_else and
readonly_error. */
enum lvalue_use {
lv_assign,
lv_increment,
lv_decrement,
lv_addressof,
lv_asm
};
/* The level of nesting inside "__alignof__". */ /* The level of nesting inside "__alignof__". */
int in_alignof; int in_alignof;
...@@ -89,7 +100,8 @@ static void add_pending_init (tree, tree); ...@@ -89,7 +100,8 @@ static void add_pending_init (tree, tree);
static void set_nonincremental_init (void); static void set_nonincremental_init (void);
static void set_nonincremental_init_from_string (tree); static void set_nonincremental_init_from_string (tree);
static tree find_init_member (tree); static tree find_init_member (tree);
static int lvalue_or_else (tree, const char *); static int lvalue_or_else (tree, enum lvalue_use);
static void readonly_error (tree, enum lvalue_use);
/* Do `exp = require_complete_type (exp);' to make sure exp /* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.) */ does not have an incomplete type. (That includes void types.) */
...@@ -2545,8 +2557,8 @@ build_unary_op (enum tree_code code, tree xarg, int flag) ...@@ -2545,8 +2557,8 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
/* Complain about anything else that is not a true lvalue. */ /* Complain about anything else that is not a true lvalue. */
if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR) || code == POSTINCREMENT_EXPR)
? "invalid lvalue in increment" ? lv_increment
: "invalid lvalue in decrement"))) : lv_decrement)))
return error_mark_node; return error_mark_node;
/* Report a read-only lvalue. */ /* Report a read-only lvalue. */
...@@ -2554,7 +2566,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag) ...@@ -2554,7 +2566,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
readonly_error (arg, readonly_error (arg,
((code == PREINCREMENT_EXPR ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR) || code == POSTINCREMENT_EXPR)
? "increment" : "decrement")); ? lv_increment : lv_decrement));
if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
val = boolean_increment (code, arg); val = boolean_increment (code, arg);
...@@ -2591,7 +2603,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag) ...@@ -2591,7 +2603,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
/* Anything not already handled and not a true memory reference /* Anything not already handled and not a true memory reference
or a non-lvalue array is an error. */ or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE && !flag else if (typecode != FUNCTION_TYPE && !flag
&& !lvalue_or_else (arg, "invalid lvalue in unary %<&%>")) && !lvalue_or_else (arg, lv_addressof))
return error_mark_node; return error_mark_node;
/* Ordinary case; arg is a COMPONENT_REF or a decl. */ /* Ordinary case; arg is a COMPONENT_REF or a decl. */
...@@ -2682,40 +2694,73 @@ lvalue_p (tree ref) ...@@ -2682,40 +2694,73 @@ lvalue_p (tree ref)
} }
/* Return nonzero if REF is an lvalue valid for this language; /* Return nonzero if REF is an lvalue valid for this language;
otherwise, print an error message and return zero. MSGID otherwise, print an error message and return zero. USE says
is a format string which receives no arguments, but in which how the lvalue is being used and so selects the error message. */
formats such as %< and %> may occur. */
static int static int
lvalue_or_else (tree ref, const char *msgid) lvalue_or_else (tree ref, enum lvalue_use use)
{ {
int win = lvalue_p (ref); int win = lvalue_p (ref);
if (! win) if (!win)
error (msgid); {
switch (use)
{
case lv_assign:
error ("invalid lvalue in assignment");
break;
case lv_increment:
error ("invalid lvalue in increment");
break;
case lv_decrement:
error ("invalid lvalue in decrement");
break;
case lv_addressof:
error ("invalid lvalue in unary %<&%>");
break;
case lv_asm:
error ("invalid lvalue in asm statement");
break;
default:
gcc_unreachable ();
}
}
return win; return win;
} }
/* Warn about storing in something that is `const'. */ /* Give an error for storing in something that is 'const'. */
void static void
readonly_error (tree arg, const char *msgid) readonly_error (tree arg, enum lvalue_use use)
{ {
gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement);
/* Using this macro rather than (for example) arrays of messages
ensures that all the format strings are checked at compile
time. */
#define READONLY_MSG(A, I, D) (use == lv_assign \
? (A) \
: (use == lv_increment ? (I) : (D)))
if (TREE_CODE (arg) == COMPONENT_REF) if (TREE_CODE (arg) == COMPONENT_REF)
{ {
if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0)))) if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
readonly_error (TREE_OPERAND (arg, 0), msgid); readonly_error (TREE_OPERAND (arg, 0), use);
else else
error ("%s of read-only member %qs", _(msgid), error (READONLY_MSG (N_("assignment of read-only member %qs"),
N_("increment of read-only member %qs"),
N_("decrement of read-only member %qs")),
IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1)))); IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1))));
} }
else if (TREE_CODE (arg) == VAR_DECL) else if (TREE_CODE (arg) == VAR_DECL)
error ("%s of read-only variable %qs", _(msgid), error (READONLY_MSG (N_("assignment of read-only variable %qs"),
N_("increment of read-only variable %qs"),
N_("decrement of read-only variable %qs")),
IDENTIFIER_POINTER (DECL_NAME (arg))); IDENTIFIER_POINTER (DECL_NAME (arg)));
else else
error ("%s of read-only location", _(msgid)); error (READONLY_MSG (N_("assignment of read-only location"),
N_("increment of read-only location"),
N_("decrement of read-only location")));
} }
/* Mark EXP saying that we need to be able to take the /* Mark EXP saying that we need to be able to take the
...@@ -3283,16 +3328,16 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs) ...@@ -3283,16 +3328,16 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
newrhs = build_binary_op (modifycode, lhs, rhs, 1); newrhs = build_binary_op (modifycode, lhs, rhs, 1);
} }
if (!lvalue_or_else (lhs, "invalid lvalue in assignment")) if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node; return error_mark_node;
/* Warn about storing in something that is `const'. */ /* Give an error for storing in something that is 'const'. */
if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype) if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype)
|| ((TREE_CODE (lhstype) == RECORD_TYPE || ((TREE_CODE (lhstype) == RECORD_TYPE
|| TREE_CODE (lhstype) == UNION_TYPE) || TREE_CODE (lhstype) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (lhstype))) && C_TYPE_FIELDS_READONLY (lhstype)))
readonly_error (lhs, "assignment"); readonly_error (lhs, lv_assign);
/* If storing into a structure or union member, /* If storing into a structure or union member,
it has probably been given type `int'. it has probably been given type `int'.
...@@ -6249,7 +6294,7 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers, ...@@ -6249,7 +6294,7 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
tree output = TREE_VALUE (tail); tree output = TREE_VALUE (tail);
STRIP_NOPS (output); STRIP_NOPS (output);
TREE_VALUE (tail) = output; TREE_VALUE (tail) = output;
lvalue_or_else (output, "invalid lvalue in asm statement"); lvalue_or_else (output, lv_asm);
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail))); constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
......
2004-09-30 Joseph S. Myers <jsm@polyomino.org.uk> 2004-09-30 Joseph S. Myers <jsm@polyomino.org.uk>
* gcc.dg/lvalue-2.c: New test.
2004-09-30 Joseph S. Myers <jsm@polyomino.org.uk>
PR c/17730 PR c/17730
* gcc.dg/pr17730-1.c: New test * gcc.dg/pr17730-1.c: New test
......
/* Test diagnostic messages for invalid lvalues and non-modifiable
lvalues. */
/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
/* { dg-do compile } */
/* { dg-options "" } */
int a, b;
void
f0 (void)
{
(a+b) = 1; /* { dg-error "error: invalid lvalue in assignment" } */
(a+b)++; /* { dg-error "error: invalid lvalue in increment" } */
++(a+b); /* { dg-error "error: invalid lvalue in increment" } */
(a+b)--; /* { dg-error "error: invalid lvalue in decrement" } */
--(a+b); /* { dg-error "error: invalid lvalue in decrement" } */
&(a+b); /* { dg-error "error: invalid lvalue in unary '&'" } */
}
const int c;
const struct { int x; } d;
struct { const int x; } e;
const int *f;
void
f1 (void)
{
c = 1; /* { dg-error "error: assignment of read-only variable 'c'" } */
d.x = 1; /* { dg-error "error: assignment of read-only variable 'd'" } */
e.x = 1; /* { dg-error "error: assignment of read-only member 'x'" } */
*f = 1; /* { dg-error "error: assignment of read-only location" } */
c++; /* { dg-error "error: increment of read-only variable 'c'" } */
d.x++; /* { dg-error "error: increment of read-only variable 'd'" } */
e.x++; /* { dg-error "error: increment of read-only member 'x'" } */
(*f)++; /* { dg-error "error: increment of read-only location" } */
++c; /* { dg-error "error: increment of read-only variable 'c'" } */
++d.x; /* { dg-error "error: increment of read-only variable 'd'" } */
++e.x; /* { dg-error "error: increment of read-only member 'x'" } */
++(*f); /* { dg-error "error: increment of read-only location" } */
c--; /* { dg-error "error: decrement of read-only variable 'c'" } */
d.x--; /* { dg-error "error: decrement of read-only variable 'd'" } */
e.x--; /* { dg-error "error: decrement of read-only member 'x'" } */
(*f)--; /* { dg-error "error: decrement of read-only location" } */
--c; /* { dg-error "error: decrement of read-only variable 'c'" } */
--d.x; /* { dg-error "error: decrement of read-only variable 'd'" } */
--e.x; /* { dg-error "error: decrement of read-only member 'x'" } */
--(*f); /* { dg-error "error: decrement of read-only location" } */
}
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