c-common.c (check_format_info_recurse): Extract string constant initializers from...
authorJoseph Myers <jsm28@cam.ac.uk>
Fri, 20 Oct 2000 15:59:07 +0000 (16:59 +0100)
committerJoseph Myers <jsm28@gcc.gnu.org>
Fri, 20 Oct 2000 15:59:07 +0000 (16:59 +0100)
* c-common.c (check_format_info_recurse): Extract string constant
initializers from non-volatile constant arrays and check them as
formats.
* c-typeck.c (decl_constant_value): Don't check pedantic or check
for DECL_MODE (decl) != BLKmode.
(decl_constant_value_for_broken_optimization): New function which
includes these checks.
(default_conversion, convert_for_assignment, digest_init): Use
decl_constant_value_for_broken_optimization instead of
decl_constant_value.

testsuite:
* gcc.dg/format-array-1.c: New test.

From-SVN: r36965

gcc/ChangeLog
gcc/c-common.c
gcc/c-typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/format-array-1.c [new file with mode: 0644]

index b9f58c10a3cd0a1292c693b551ae56964ab42973..5a71796a0b52712aa899e151f671eedcc9efb0e9 100644 (file)
@@ -1,3 +1,16 @@
+2000-10-20  Joseph S. Myers  <jsm28@cam.ac.uk>
+
+       * c-common.c (check_format_info_recurse): Extract string constant
+       initializers from non-volatile constant arrays and check them as
+       formats.
+       * c-typeck.c (decl_constant_value): Don't check pedantic or check
+       for DECL_MODE (decl) != BLKmode.
+       (decl_constant_value_for_broken_optimization): New function which
+       includes these checks.
+       (default_conversion, convert_for_assignment, digest_init): Use
+       decl_constant_value_for_broken_optimization instead of
+       decl_constant_value.
+
 2000-10-20  Mark Mitchell  <mark@codesourcery.com>
 
        * tree.h (DECL_ALIGN_UNIT): New macro.
index 086177f5860f16ca563bddcd8fe47374a898862c..e9ce259901acdaa65e4b6f1be1f07f234ea6914c 100644 (file)
@@ -2344,6 +2344,8 @@ check_format_info_recurse (status, res, info, format_tree, params, arg_num)
 {
   int format_length;
   const char *format_chars;
+  tree array_size = 0;
+  tree array_init;
 
   if (TREE_CODE (format_tree) == NOP_EXPR)
     {
@@ -2436,6 +2438,17 @@ check_format_info_recurse (status, res, info, format_tree, params, arg_num)
       return;
     }
   format_tree = TREE_OPERAND (format_tree, 0);
+  if (TREE_CODE (format_tree) == VAR_DECL
+      && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE
+      && (array_init = decl_constant_value (format_tree)) != format_tree
+      && TREE_CODE (array_init) == STRING_CST)
+    {
+      /* Extract the string constant initializer.  Note that this may include
+        a trailing NUL character that is not in the array (e.g.
+        const char a[3] = "foo";).  */
+      array_size = DECL_SIZE_UNIT (format_tree);
+      format_tree = array_init;
+    }
   if (TREE_CODE (format_tree) != STRING_CST)
     {
       res->number_non_literal++;
@@ -2448,6 +2461,20 @@ check_format_info_recurse (status, res, info, format_tree, params, arg_num)
     }
   format_chars = TREE_STRING_POINTER (format_tree);
   format_length = TREE_STRING_LENGTH (format_tree);
+  if (array_size != 0)
+    {
+      /* Variable length arrays can't be initialized.  */
+      if (TREE_CODE (array_size) != INTEGER_CST)
+       abort ();
+      if (host_integerp (array_size, 0))
+       {
+         HOST_WIDE_INT array_size_value = TREE_INT_CST_LOW (array_size);
+         if (array_size_value > 0
+             && array_size_value == (int) array_size_value
+             && format_length > array_size_value)
+           format_length = array_size_value;
+       }
+    }
   if (format_length < 1)
     {
       res->number_unterminated++;
index 0d2209e501a473621636ef262cd384bf2ef9e6d8..e055e988beb063f8fd3f2320272876f597c9b63e 100644 (file)
@@ -54,6 +54,7 @@ static tree qualify_type              PARAMS ((tree, tree));
 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 lookup_field               PARAMS ((tree, tree, tree *));
 static tree convert_arguments          PARAMS ((tree, tree, tree, tree));
 static tree pointer_int_sum            PARAMS ((enum tree_code, tree, tree));
@@ -844,7 +845,6 @@ decl_constant_value (decl)
   if (/* Don't change a variable array bound or initial value to a constant
         in a place where a variable is invalid.  */
       current_function_decl != 0
-      && ! pedantic
       && ! TREE_THIS_VOLATILE (decl)
       && TREE_READONLY (decl)
       && DECL_INITIAL (decl) != 0
@@ -854,12 +854,29 @@ decl_constant_value (decl)
         or a variable, then re-evaluating it could give different results.  */
       && TREE_CONSTANT (DECL_INITIAL (decl))
       /* Check for cases where this is sub-optimal, even though valid.  */
-      && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR
-      && DECL_MODE (decl) != BLKmode)
+      && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR)
     return DECL_INITIAL (decl);
   return decl;
 }
 
+/* Return either DECL or its known constant value (if it has one), but
+   return DECL if pedantic or DECL has mode BLKmode.  This is for
+   bug-compatibility with the old behavior of decl_constant_value
+   (before GCC 3.0); every use of this function is a bug and it should
+   be removed before GCC 3.1.  It is not appropriate to use pedantic
+   in a way that affects optimization, and BLKmode is probably not the
+   right test for avoiding misoptimizations either.  */
+
+static tree
+decl_constant_value_for_broken_optimization (decl)
+     tree decl;
+{
+  if (pedantic || DECL_MODE (decl) == BLKmode)
+    return decl;
+  else
+    return decl_constant_value (decl);
+}
+
 /* Perform default promotions for C data used in expressions.
    Arrays and functions are converted to pointers;
    enumeral types or short or char, to int.
@@ -881,7 +898,7 @@ default_conversion (exp)
      address of the array produces consistent results.  */
   else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE)
     {
-      exp = decl_constant_value (exp);
+      exp = decl_constant_value_for_broken_optimization (exp);
       type = TREE_TYPE (exp);
     }
 
@@ -4019,7 +4036,7 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
       || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE)
     rhs = default_conversion (rhs);
   else if (optimize && TREE_CODE (rhs) == VAR_DECL)
-    rhs = decl_constant_value (rhs);
+    rhs = decl_constant_value_for_broken_optimization (rhs);
 
   rhstype = TREE_TYPE (rhs);
   coder = TREE_CODE (rhstype);
@@ -4695,7 +4712,7 @@ digest_init (type, init, require_constant, constructor_constant)
        }
 
       if (optimize && TREE_CODE (inside_init) == VAR_DECL)
-       inside_init = decl_constant_value (inside_init);
+       inside_init = decl_constant_value_for_broken_optimization (inside_init);
 
       /* Compound expressions can only occur here if -pedantic or
         -pedantic-errors is specified.  In the later case, we always want
index 679b4edf630432d33426ca613342aca05f81777b..ebaa50f34db2e89587f5fd5508f3b2a9f7d1e178 100644 (file)
@@ -1,3 +1,7 @@
+2000-10-20  Joseph S. Myers  <jsm28@cam.ac.uk>
+
+       * gcc.dg/format-array-1.c: New test.
+
 2000-10-18  Joseph S. Myers  <jsm28@cam.ac.uk>
 
        * gcc.dg/c90-printf-1.c, gcc.dg/c90-scanf-1.c: Add tests for
diff --git a/gcc/testsuite/gcc.dg/format-array-1.c b/gcc/testsuite/gcc.dg/format-array-1.c
new file mode 100644 (file)
index 0000000..8d632a7
--- /dev/null
@@ -0,0 +1,39 @@
+/* Test for format checking of constant arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+extern int printf (const char *, ...);
+
+const char a1[] = "foo";
+const char a2[] = "foo%d";
+const char b[3] = "foo";
+static const char c1[] = "foo";
+static const char c2[] = "foo%d";
+char d[] = "foo";
+volatile const char e[] = "foo";
+
+void
+foo (int i, long l)
+{
+  const char p1[] = "bar";
+  const char p2[] = "bar%d";
+  static const char q1[] = "bar";
+  static const char q2[] = "bar%d";
+  printf (a1);
+  printf (a2, i);
+  printf (a2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (b); /* { dg-warning "unterminated" "unterminated array" } */
+  printf (c1);
+  printf (c2, i);
+  printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (p1);
+  printf (p2, i);
+  printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (q1);
+  printf (q2, i);
+  printf (q2, l); /* { dg-warning "format" "wrong type with array" } */
+  /* Volatile or non-constant arrays must not be checked.  */
+  printf (d); /* { dg-warning "not a string literal" "non-const" } */
+  printf ((const char *)e); /* { dg-warning "not a string literal" "volatile" } */
+}