+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.
{
int format_length;
const char *format_chars;
+ tree array_size = 0;
+ tree array_init;
if (TREE_CODE (format_tree) == NOP_EXPR)
{
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++;
}
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++;
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));
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
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.
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);
}
|| 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);
}
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
+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
--- /dev/null
+/* 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" } */
+}