* c-tree.h (readonly_error): Remove.
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 30 Sep 2004 22:52:06 +0000 (22:52 +0000)
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 30 Sep 2004 22:52:06 +0000 (22:52 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@88362 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/c-tree.h
gcc/c-typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/lvalue-2.c [new file with mode: 0644]

index c3cf3a7..bac245f 100644 (file)
@@ -1,3 +1,10 @@
+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>
 
        PR debug/13974
index 76981a7..f6e195f 100644 (file)
@@ -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 parser_build_binary_op (enum tree_code, struct c_expr,
                                             struct c_expr);
-extern void readonly_error (tree, const char *);
 extern tree build_conditional_expr (tree, tree, tree);
 extern tree build_compound_expr (tree, tree);
 extern tree c_cast_expr (struct c_type_name *, tree);
index 1d79b23..70d3938 100644 (file)
@@ -44,6 +44,17 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tree-iterator.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__".  */
 int in_alignof;
 
@@ -89,7 +100,8 @@ static void add_pending_init (tree, tree);
 static void set_nonincremental_init (void);
 static void set_nonincremental_init_from_string (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);
 \f
 /* Do `exp = require_complete_type (exp);' to make sure exp
    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)
        /* Complain about anything else that is not a true lvalue.  */
        if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
                                    || code == POSTINCREMENT_EXPR)
-                                  ? "invalid lvalue in increment"
-                                  : "invalid lvalue in decrement")))
+                                  ? lv_increment
+                                  : lv_decrement)))
          return error_mark_node;
 
        /* Report a read-only lvalue.  */
@@ -2554,7 +2566,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
          readonly_error (arg,
                          ((code == PREINCREMENT_EXPR
                            || code == POSTINCREMENT_EXPR)
-                          ? "increment" : "decrement"));
+                          ? lv_increment : lv_decrement));
 
        if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
          val = boolean_increment (code, arg);
@@ -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
         or a non-lvalue array is an error.  */
       else if (typecode != FUNCTION_TYPE && !flag
-              && !lvalue_or_else (arg, "invalid lvalue in unary %<&%>"))
+              && !lvalue_or_else (arg, lv_addressof))
        return error_mark_node;
 
       /* Ordinary case; arg is a COMPONENT_REF or a decl.  */
@@ -2682,40 +2694,73 @@ lvalue_p (tree ref)
 }
 
 /* Return nonzero if REF is an lvalue valid for this language;
-   otherwise, print an error message and return zero.  MSGID
-   is a format string which receives no arguments, but in which
-   formats such as %< and %> may occur.  */
+   otherwise, print an error message and return zero.  USE says
+   how the lvalue is being used and so selects the error message.  */
 
 static int
-lvalue_or_else (tree ref, const char *msgid)
+lvalue_or_else (tree ref, enum lvalue_use use)
 {
   int win = lvalue_p (ref);
 
-  if (! win)
-    error (msgid);
+  if (!win)
+    {
+      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;
 }
 
 \f
-/* Warn about storing in something that is `const'.  */
+/* Give an error for storing in something that is 'const'.  */
 
-void
-readonly_error (tree arg, const char *msgid)
+static void
+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 (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
-       readonly_error (TREE_OPERAND (arg, 0), msgid);
+       readonly_error (TREE_OPERAND (arg, 0), use);
       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))));
     }
   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)));
   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")));
 }
 \f
 /* 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)
       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;
 
-  /* 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)
       || ((TREE_CODE (lhstype) == RECORD_TYPE
           || TREE_CODE (lhstype) == UNION_TYPE)
          && C_TYPE_FIELDS_READONLY (lhstype)))
-    readonly_error (lhs, "assignment");
+    readonly_error (lhs, lv_assign);
 
   /* If storing into a structure or union member,
      it has probably been given type `int'.
@@ -6249,7 +6294,7 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
       tree output = TREE_VALUE (tail);
       STRIP_NOPS (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)));
 
index 819d422..7fb0978 100644 (file)
@@ -1,5 +1,9 @@
 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
        * gcc.dg/pr17730-1.c: New test
 
diff --git a/gcc/testsuite/gcc.dg/lvalue-2.c b/gcc/testsuite/gcc.dg/lvalue-2.c
new file mode 100644 (file)
index 0000000..5ad648e
--- /dev/null
@@ -0,0 +1,48 @@
+/* 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" } */
+}