This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch for lvalue_or_else, readonly_error


This patch cleans up the C front end diagnostics for invalid lvalues
and invalid modifiable lvalues.  Previously, sentences and sentence
fragments in conditional expessions selecting between versions for
"increment" and "decrement" didn't get extracted to gcc.pot, and the
messages in readonly_error were built up from sentence fragments which
is bad for translation: as there are only nine sentence variants
possible there it makes more sense simply to have all the sentences in
the source in full so each sentence can be translated as a whole.

Bootstrapped with no regressions on i686-pc-linux-gnu.  Applied to
mainline.  I'll also regenerate gcc.pot.

-- 
Joseph S. Myers               http://www.srcf.ucam.org/~jsm28/gcc/
  http://www.srcf.ucam.org/~jsm28/gcc/#c90status - status of C90 for GCC 4.0
    jsm@polyomino.org.uk (personal mail)
    jsm28@gcc.gnu.org (Bugzilla assignments and CCs)

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.

testsuite:
2004-09-30  Joseph S. Myers  <jsm@polyomino.org.uk>

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

diff -rupN GCC.orig/gcc/c-tree.h GCC/gcc/c-tree.h
--- GCC.orig/gcc/c-tree.h	2004-09-17 18:15:07.000000000 +0000
+++ GCC/gcc/c-tree.h	2004-09-30 13:08:07.000000000 +0000
@@ -428,7 +428,6 @@ extern struct c_expr c_expr_sizeof_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);
diff -rupN GCC.orig/gcc/c-typeck.c GCC/gcc/c-typeck.c
--- GCC.orig/gcc/c-typeck.c	2004-09-30 18:19:47.000000000 +0000
+++ GCC/gcc/c-typeck.c	2004-09-30 15:23:37.000000000 +0000
@@ -44,6 +44,17 @@ Software Foundation, 59 Temple Place - S
 #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);
 
 /* 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, tre
 	/* 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, tre
 	  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, tre
       /* 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;
 }
 
 
-/* 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")));
 }
 
 /* Mark EXP saying that we need to be able to take the
@@ -3283,16 +3328,16 @@ build_modify_expr (tree lhs, enum tree_c
       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 output
       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)));
 
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/lvalue-2.c GCC/gcc/testsuite/gcc.dg/lvalue-2.c
--- GCC.orig/gcc/testsuite/gcc.dg/lvalue-2.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/lvalue-2.c	2004-09-30 15:37:50.000000000 +0000
@@ -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" } */
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]