summaryrefslogtreecommitdiffstats
path: root/gcc
diff options
context:
space:
mode:
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>2001-10-02 07:12:25 +0000
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>2001-10-02 07:12:25 +0000
commit7d3b509adae17f526dad2929ae2b16183408401d (patch)
tree4648d58efabadc87677da26b0f516d5bfc64f45c /gcc
parent7c2404e186a146b9f3c028fed4742d3abc302d1b (diff)
downloadppe42-gcc-7d3b509adae17f526dad2929ae2b16183408401d.tar.gz
ppe42-gcc-7d3b509adae17f526dad2929ae2b16183408401d.zip
* attribs.c (decl_attributes): Possibly call
insert_default_attributes to insert default attributes on functions in a lazy manner. * builtin-attrs.def: New file; define the default format and format_arg attributes. * c-common.c (c_format_attribute_table): Move to earlier in the file. (c_common_nodes_and_builtins): Initialize format_attribute_table. (enum built_in_attribute, built_in_attributes, c_attrs_initialized, c_init_attributes, c_common_insert_default_attributes): New. (c_common_lang_init): Don't initialize format_attribute_table. Do call c_init_attributes. * Makefile.in (c-common.o): Depend on builtin-attrs.def. * c-common.h (init_function_format_info): Don't declare. (c_common_insert_default_attributes): Declare. * c-decl.c (implicitly_declare, builtin_function): Call decl_attributes. (init_decl_processing): Don't call init_function_format_info. (insert_default_attributes): New. * c-format.c (handle_format_attribute, handle_format_arg_attribute): Be quiet about inappropriate declaration when applying default attributes. (init_function_format_info): Remove. * tree.h (enum attribute_flags): Add ATTR_FLAG_BUILT_IN. (insert_default_attributes): Declare. cp: * decl.c (init_decl_processing): Don't call init_function_format_info. Initialize lang_attribute_table earlier. (builtin_function): Call decl_attributes. (insert_default_attributes): New. testsuite: * gcc.dg/format/attr-5.c, gcc.dg/format/attr-6.c: New tests. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@45942 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog29
-rw-r--r--gcc/Makefile.in2
-rw-r--r--gcc/attribs.c10
-rw-r--r--gcc/builtin-attrs.def166
-rw-r--r--gcc/c-common.c106
-rw-r--r--gcc/c-common.h2
-rw-r--r--gcc/c-decl.c23
-rw-r--r--gcc/c-format.c90
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/decl.c24
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/format/attr-5.c28
-rw-r--r--gcc/testsuite/gcc.dg/format/attr-6.c21
-rw-r--r--gcc/tree.h13
14 files changed, 421 insertions, 105 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index afccd79e465..7a10bfa342c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,34 @@
2001-10-02 Joseph S. Myers <jsm28@cam.ac.uk>
+ * attribs.c (decl_attributes): Possibly call
+ insert_default_attributes to insert default attributes on
+ functions in a lazy manner.
+ * builtin-attrs.def: New file; define the default format and
+ format_arg attributes.
+ * c-common.c (c_format_attribute_table): Move to earlier in the
+ file.
+ (c_common_nodes_and_builtins): Initialize format_attribute_table.
+ (enum built_in_attribute, built_in_attributes,
+ c_attrs_initialized, c_init_attributes,
+ c_common_insert_default_attributes): New.
+ (c_common_lang_init): Don't initialize format_attribute_table. Do
+ call c_init_attributes.
+ * Makefile.in (c-common.o): Depend on builtin-attrs.def.
+ * c-common.h (init_function_format_info): Don't declare.
+ (c_common_insert_default_attributes): Declare.
+ * c-decl.c (implicitly_declare, builtin_function): Call
+ decl_attributes.
+ (init_decl_processing): Don't call init_function_format_info.
+ (insert_default_attributes): New.
+ * c-format.c (handle_format_attribute,
+ handle_format_arg_attribute): Be quiet about inappropriate
+ declaration when applying default attributes.
+ (init_function_format_info): Remove.
+ * tree.h (enum attribute_flags): Add ATTR_FLAG_BUILT_IN.
+ (insert_default_attributes): Declare.
+
+2001-10-02 Joseph S. Myers <jsm28@cam.ac.uk>
+
* c-format.c (CPLUSPLUS_STD_VER): Define to STD_C94.
2001-10-01 Jim Wilson <wilson@redhat.com>
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 301b6e7144c..5cd0610d804 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1249,7 +1249,7 @@ s-under: $(GCC_PASSES)
c-common.o : c-common.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(OBSTACK_H) \
$(C_COMMON_H) flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \
- $(EXPR_H) $(TM_P_H) builtin-types.def $(TARGET_H)
+ $(EXPR_H) $(TM_P_H) builtin-types.def builtin-attrs.def $(TARGET_H)
# A file used by all variants of C and some other languages.
diff --git a/gcc/attribs.c b/gcc/attribs.c
index 1413dc267f9..29982dec529 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -241,7 +241,11 @@ init_attributes ()
information, in the form of a bitwise OR of flags in enum attribute_flags
from tree.h. Depending on these flags, some attributes may be
returned to be applied at a later stage (for example, to apply
- a decl attribute to the declaration rather than to its type). */
+ a decl attribute to the declaration rather than to its type). If
+ ATTR_FLAG_BUILT_IN is not set and *NODE is a DECL, then also consider
+ whether there might be some default attributes to apply to this DECL;
+ if so, decl_attributes will be called recusrively with those attributes
+ and ATTR_FLAG_BUILT_IN set. */
tree
decl_attributes (node, attributes, flags)
@@ -256,6 +260,10 @@ decl_attributes (node, attributes, flags)
(*targetm.insert_attributes) (*node, &attributes);
+ if (DECL_P (*node) && TREE_CODE (*node) == FUNCTION_DECL
+ && !(flags & (int) ATTR_FLAG_BUILT_IN))
+ insert_default_attributes (*node);
+
for (a = attributes; a; a = TREE_CHAIN (a))
{
tree name = TREE_PURPOSE (a);
diff --git a/gcc/builtin-attrs.def b/gcc/builtin-attrs.def
new file mode 100644
index 00000000000..de98501cf36
--- /dev/null
+++ b/gcc/builtin-attrs.def
@@ -0,0 +1,166 @@
+/* Copyright (C) 2001 Free Software Foundation, Inc.
+ Contributed by Joseph Myers <jsm28@cam.ac.uk>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+/* This header provides a declarative way of describing the attributes
+ that are applied to some functions by default.
+
+ Before including this header, you must define the following macros.
+ In each case where there is an ENUM, it is an identifier used to
+ reference the tree in subsequent definitions.
+
+ DEF_ATTR_NULL_TREE (ENUM)
+
+ Constructs a NULL_TREE.
+
+ DEF_ATTR_INT (ENUM, VALUE)
+
+ Constructs an INTEGER_CST with value VALUE (an integer representable
+ in HOST_WIDE_INT).
+
+ DEF_ATTR_IDENT (ENUM, STRING)
+
+ Constructs an IDENTIFIER_NODE for STRING.
+
+ DEF_ATTR_TREE_LIST (ENUM, PURPOSE, VALUE, CHAIN)
+
+ Constructs a TREE_LIST with given PURPOSE, VALUE and CHAIN (given
+ as previous ENUM names).
+
+ DEF_FN_ATTR (NAME, ATTRS, PREDICATE)
+
+ Specifies that the function with name NAME (a previous ENUM for an
+ IDENTIFIER_NODE) has attributes ATTRS (a previous ENUM) if
+ PREDICATE is true. */
+
+DEF_ATTR_NULL_TREE (ATTR_NULL)
+
+/* Note that below we must avoid whitespace in arguments of CONCAT*. */
+
+/* Construct a tree for a given integer and a list containing it. */
+#define DEF_ATTR_FOR_INT(VALUE) \
+ DEF_ATTR_INT (CONCAT2 (ATTR_,VALUE), VALUE) \
+ DEF_ATTR_TREE_LIST (CONCAT2 (ATTR_LIST_,VALUE), ATTR_NULL, \
+ CONCAT2 (ATTR_,VALUE), ATTR_NULL)
+DEF_ATTR_FOR_INT (0)
+DEF_ATTR_FOR_INT (1)
+DEF_ATTR_FOR_INT (2)
+DEF_ATTR_FOR_INT (3)
+DEF_ATTR_FOR_INT (4)
+#undef DEF_ATTR_FOR_INT
+
+/* Construct a tree for a list of two integers. */
+#define DEF_LIST_INT_INT(VALUE1, VALUE2) \
+ DEF_ATTR_TREE_LIST (CONCAT4 (ATTR_LIST_,VALUE1,_,VALUE2), ATTR_NULL, \
+ CONCAT2 (ATTR_,VALUE1), CONCAT2 (ATTR_LIST_,VALUE2))
+DEF_LIST_INT_INT (1,0)
+DEF_LIST_INT_INT (1,2)
+DEF_LIST_INT_INT (2,0)
+DEF_LIST_INT_INT (2,3)
+DEF_LIST_INT_INT (3,0)
+DEF_LIST_INT_INT (3,4)
+#undef DEF_LIST_INT_INT
+
+DEF_ATTR_IDENT (ATTR_PRINTF, "printf")
+DEF_ATTR_IDENT (ATTR_SCANF, "scanf")
+DEF_ATTR_IDENT (ATTR_STRFTIME, "strftime")
+DEF_ATTR_IDENT (ATTR_STRFMON, "strfmon")
+
+DEF_ATTR_IDENT (ATTR_FORMAT, "format")
+DEF_ATTR_IDENT (ATTR_FORMAT_ARG, "format_arg")
+
+/* Construct a tree for a format attribute. */
+#define DEF_FORMAT_ATTRIBUTE(TYPE, VALUES) \
+ DEF_ATTR_TREE_LIST (CONCAT4 (ATTR_,TYPE,_,VALUES), ATTR_NULL, \
+ CONCAT2 (ATTR_,TYPE), CONCAT2 (ATTR_LIST_,VALUES)) \
+ DEF_ATTR_TREE_LIST (CONCAT4 (ATTR_FORMAT_,TYPE,_,VALUES), ATTR_FORMAT, \
+ CONCAT4 (ATTR_,TYPE,_,VALUES), ATTR_NULL)
+DEF_FORMAT_ATTRIBUTE(PRINTF,1_0)
+DEF_FORMAT_ATTRIBUTE(PRINTF,1_2)
+DEF_FORMAT_ATTRIBUTE(PRINTF,2_0)
+DEF_FORMAT_ATTRIBUTE(PRINTF,2_3)
+DEF_FORMAT_ATTRIBUTE(PRINTF,3_0)
+DEF_FORMAT_ATTRIBUTE(PRINTF,3_4)
+DEF_FORMAT_ATTRIBUTE(SCANF,1_0)
+DEF_FORMAT_ATTRIBUTE(SCANF,1_2)
+DEF_FORMAT_ATTRIBUTE(SCANF,2_0)
+DEF_FORMAT_ATTRIBUTE(SCANF,2_3)
+DEF_FORMAT_ATTRIBUTE(STRFTIME,3_0)
+DEF_FORMAT_ATTRIBUTE(STRFMON,3_4)
+#undef DEF_FORMAT_ATTRIBUTE
+
+DEF_ATTR_TREE_LIST (ATTR_FORMAT_ARG_1, ATTR_FORMAT_ARG, ATTR_LIST_1, ATTR_NULL)
+DEF_ATTR_TREE_LIST (ATTR_FORMAT_ARG_2, ATTR_FORMAT_ARG, ATTR_LIST_2, ATTR_NULL)
+
+/* Define an attribute for a function, along with the IDENTIFIER_NODE. */
+#define DEF_FN_ATTR_IDENT(NAME, ATTRS, PREDICATE) \
+ DEF_ATTR_IDENT (CONCAT2(ATTR_,NAME), STRINGX(NAME)) \
+ DEF_FN_ATTR (CONCAT2(ATTR_,NAME), ATTRS, PREDICATE)
+
+/* The ISO C functions are always checked (whether <stdio.h> is
+ included or not), since it is common to call printf without
+ including <stdio.h>. There shouldn't be a problem with this,
+ since ISO C reserves these function names whether you include the
+ header file or not. In any case, the checking is harmless. With
+ -ffreestanding, these default attributes are disabled, and must be
+ specified manually if desired. */
+
+/* __builtin functions should be checked unconditionally, even with
+ -ffreestanding. */
+DEF_FN_ATTR_IDENT (__builtin_printf, ATTR_FORMAT_PRINTF_1_2, true)
+DEF_FN_ATTR_IDENT (__builtin_fprintf, ATTR_FORMAT_PRINTF_2_3, true)
+
+/* Functions from ISO/IEC 9899:1990. */
+#define DEF_C89_ATTR(NAME, ATTRS) DEF_FN_ATTR_IDENT (NAME, ATTRS, flag_hosted)
+DEF_C89_ATTR (printf, ATTR_FORMAT_PRINTF_1_2)
+DEF_C89_ATTR (fprintf, ATTR_FORMAT_PRINTF_2_3)
+DEF_C89_ATTR (sprintf, ATTR_FORMAT_PRINTF_2_3)
+DEF_C89_ATTR (scanf, ATTR_FORMAT_SCANF_1_2)
+DEF_C89_ATTR (fscanf, ATTR_FORMAT_SCANF_2_3)
+DEF_C89_ATTR (sscanf, ATTR_FORMAT_SCANF_2_3)
+DEF_C89_ATTR (vprintf, ATTR_FORMAT_PRINTF_1_0)
+DEF_C89_ATTR (vfprintf, ATTR_FORMAT_PRINTF_2_0)
+DEF_C89_ATTR (vsprintf, ATTR_FORMAT_PRINTF_2_0)
+DEF_C89_ATTR (strftime, ATTR_FORMAT_STRFTIME_3_0)
+#undef DEF_C89_ATTR
+
+/* ISO C99 adds the snprintf and vscanf family functions. */
+#define DEF_C99_ATTR(NAME, ATTRS) \
+ DEF_FN_ATTR_IDENT (NAME, ATTRS, \
+ (flag_hosted \
+ && (flag_isoc99 || flag_noniso_default_format_attributes)))
+DEF_C99_ATTR (snprintf, ATTR_FORMAT_PRINTF_3_4)
+DEF_C99_ATTR (vsnprintf, ATTR_FORMAT_PRINTF_3_0)
+DEF_C99_ATTR (vscanf, ATTR_FORMAT_SCANF_1_0)
+DEF_C99_ATTR (vfscanf, ATTR_FORMAT_SCANF_2_0)
+DEF_C99_ATTR (vsscanf, ATTR_FORMAT_SCANF_2_0)
+#undef DEF_C99_ATTR
+
+/* Functions not in any version of ISO C. */
+#define DEF_EXT_ATTR(NAME, ATTRS) \
+ DEF_FN_ATTR_IDENT (NAME, ATTRS, \
+ flag_hosted && flag_noniso_default_format_attributes)
+/* Uniforum/GNU gettext functions. */
+DEF_EXT_ATTR (gettext, ATTR_FORMAT_ARG_1)
+DEF_EXT_ATTR (dgettext, ATTR_FORMAT_ARG_2)
+DEF_EXT_ATTR (dcgettext, ATTR_FORMAT_ARG_2)
+/* X/Open strfmon function. */
+DEF_EXT_ATTR (strfmon, ATTR_FORMAT_STRFMON_3_4)
+#undef DEF_EXT_ATTR
+#undef DEF_FN_ATTR_IDENT
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 190c338d5f9..a3314ff1fac 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -2324,6 +2324,18 @@ c_alignof_expr (expr)
return fold (build1 (NOP_EXPR, c_size_type_node, t));
}
+/* Give the specifications for the format attributes, used by C and all
+ descendents. */
+
+static const struct attribute_spec c_format_attribute_table[] =
+{
+ { "format", 3, 3, true, false, false,
+ handle_format_attribute },
+ { "format_arg", 1, 1, true, false, false,
+ handle_format_arg_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
/* Build tree nodes and builtin functions common to both C and C++ language
frontends. */
@@ -2369,6 +2381,10 @@ c_common_nodes_and_builtins ()
tree va_list_ref_type_node;
tree va_list_arg_type_node;
+ /* We must initialize this before any builtin functions (which might have
+ attributes) are declared. (c_common_lang_init is too late.) */
+ format_attribute_table = c_format_attribute_table;
+
/* Define `int' and `char' first so that dbx will output them first. */
record_builtin_type (RID_INT, NULL, integer_type_node);
record_builtin_type (RID_CHAR, "char", char_type_node);
@@ -3774,24 +3790,34 @@ boolean_increment (code, arg)
return val;
}
-/* Give the specifications for the format attributes, used by C and all
- descendents. */
-
-static const struct attribute_spec c_format_attribute_table[] =
-{
- { "format", 3, 3, true, false, false,
- handle_format_attribute },
- { "format_arg", 1, 1, true, false, false,
- handle_format_arg_attribute },
- { NULL, 0, 0, false, false, false, NULL }
+/* Handle C and C++ default attributes. */
+
+enum built_in_attribute
+{
+#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
+#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
+#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) /* No entry needed in enum. */
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
+ ATTR_LAST
};
+static tree built_in_attributes[(int) ATTR_LAST];
+
+static bool c_attrs_initialized = false;
+
+static void c_init_attributes PARAMS ((void));
+
/* Do the parts of lang_init common to C and C++. */
void
c_common_lang_init ()
{
- format_attribute_table = c_format_attribute_table;
-
/* If still "unspecified", make it match -fbounded-pointers. */
if (flag_bounds_check < 0)
flag_bounds_check = flag_bounded_pointers;
@@ -3808,4 +3834,60 @@ c_common_lang_init ()
warning ("-Wformat-security ignored without -Wformat");
if (warn_missing_format_attribute && !warn_format)
warning ("-Wmissing-format-attribute ignored without -Wformat");
+
+ if (!c_attrs_initialized)
+ c_init_attributes ();
+}
+
+static void
+c_init_attributes ()
+{
+ /* Fill in the built_in_attributes array. */
+#define DEF_ATTR_NULL_TREE(ENUM) \
+ built_in_attributes[(int) ENUM] = NULL_TREE;
+#define DEF_ATTR_INT(ENUM, VALUE) \
+ built_in_attributes[(int) ENUM] = build_int_2 (VALUE, VALUE < 0 ? -1 : 0);
+#define DEF_ATTR_IDENT(ENUM, STRING) \
+ built_in_attributes[(int) ENUM] = get_identifier (STRING);
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
+ built_in_attributes[(int) ENUM] \
+ = tree_cons (built_in_attributes[(int) PURPOSE], \
+ built_in_attributes[(int) VALUE], \
+ built_in_attributes[(int) CHAIN]);
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) /* No initialization needed. */
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
+ ggc_add_tree_root (built_in_attributes, (int) ATTR_LAST);
+ c_attrs_initialized = true;
+}
+
+/* Depending on the name of DECL, apply default attributes to it. */
+
+void
+c_common_insert_default_attributes (decl)
+ tree decl;
+{
+ tree name = DECL_NAME (decl);
+
+ if (!c_attrs_initialized)
+ c_init_attributes ();
+
+#define DEF_ATTR_NULL_TREE(ENUM) /* Nothing needed after initialization. */
+#define DEF_ATTR_INT(ENUM, VALUE)
+#define DEF_ATTR_IDENT(ENUM, STRING)
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN)
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) \
+ if ((PREDICATE) && name == built_in_attributes[(int) NAME]) \
+ decl_attributes (&decl, built_in_attributes[(int) ATTRS], \
+ ATTR_FLAG_BUILT_IN);
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
}
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 3681ed222f0..66df266a1e0 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -503,13 +503,13 @@ extern const char *fname_as_string PARAMS ((int));
extern tree fname_decl PARAMS ((unsigned, tree));
extern const char *fname_string PARAMS ((unsigned));
-extern void init_function_format_info PARAMS ((void));
extern void check_function_format PARAMS ((int *, tree, tree, tree));
extern void set_Wformat PARAMS ((int));
extern tree handle_format_attribute PARAMS ((tree *, tree, tree,
int, bool *));
extern tree handle_format_arg_attribute PARAMS ((tree *, tree, tree,
int, bool *));
+extern void c_common_insert_default_attributes PARAMS ((tree));
extern void c_apply_type_quals_to_decl PARAMS ((int, tree));
extern tree c_sizeof PARAMS ((tree));
extern tree c_alignof PARAMS ((tree));
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 4652267c667..f3ad82ea79c 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -2505,7 +2505,7 @@ tree
implicitly_declare (functionid)
tree functionid;
{
- register tree decl;
+ tree decl;
int traditional_warning = 0;
/* Only one "implicit declaration" warning per identifier. */
int implicit_warning;
@@ -2555,6 +2555,9 @@ implicitly_declare (functionid)
gen_aux_info_record (decl, 0, 1, 0);
+ /* Possibly apply some default attributes to this implicit declaration. */
+ decl_attributes (&decl, NULL_TREE, 0);
+
return decl;
}
@@ -3056,9 +3059,6 @@ init_decl_processing ()
make_fname_decl = c_make_fname_decl;
start_fname_decls ();
- /* Prepare to check format strings against argument lists. */
- init_function_format_info ();
-
incomplete_decl_finalize_hook = finish_incomplete_decl;
/* Record our roots. */
@@ -3152,8 +3152,23 @@ builtin_function (name, type, function_code, class, library_name)
if (name[0] != '_' || name[1] != '_')
C_DECL_ANTICIPATED (decl) = 1;
+ /* Possibly apply some default attributes to this built-in function. */
+ decl_attributes (&decl, NULL_TREE, 0);
+
return decl;
}
+
+/* Apply default attributes to a function, if a system function with default
+ attributes. */
+
+void
+insert_default_attributes (decl)
+ tree decl;
+{
+ if (!TREE_PUBLIC (decl))
+ return;
+ c_common_insert_default_attributes (decl);
+}
/* Called when a declaration is seen that contains no names to declare.
If its type is a reference to a structure, union or enum inherited
diff --git a/gcc/c-format.c b/gcc/c-format.c
index 3cc880e870e..4ee3b3d44a2 100644
--- a/gcc/c-format.c
+++ b/gcc/c-format.c
@@ -89,7 +89,7 @@ handle_format_attribute (node, name, args, flags, no_add_attrs)
tree *node;
tree name ATTRIBUTE_UNUSED;
tree args;
- int flags ATTRIBUTE_UNUSED;
+ int flags;
bool *no_add_attrs;
{
tree decl = *node;
@@ -177,7 +177,8 @@ handle_format_attribute (node, name, args, flags, no_add_attrs)
|| (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
!= char_type_node))
{
- error ("format string arg not a string type");
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ error ("format string arg not a string type");
*no_add_attrs = true;
return NULL_TREE;
}
@@ -191,7 +192,8 @@ handle_format_attribute (node, name, args, flags, no_add_attrs)
if (arg_num != first_arg_num)
{
- error ("args to be formatted is not '...'");
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ error ("args to be formatted is not '...'");
*no_add_attrs = true;
return NULL_TREE;
}
@@ -218,7 +220,7 @@ handle_format_arg_attribute (node, name, args, flags, no_add_attrs)
tree *node;
tree name ATTRIBUTE_UNUSED;
tree args;
- int flags ATTRIBUTE_UNUSED;
+ int flags;
bool *no_add_attrs;
{
tree decl = *node;
@@ -268,7 +270,8 @@ handle_format_arg_attribute (node, name, args, flags, no_add_attrs)
|| (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
!= char_type_node))
{
- error ("format string arg not a string type");
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ error ("format string arg not a string type");
*no_add_attrs = true;
return NULL_TREE;
}
@@ -278,7 +281,8 @@ handle_format_arg_attribute (node, name, args, flags, no_add_attrs)
|| (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_TYPE (decl))))
!= char_type_node))
{
- error ("function does not return string type");
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ error ("function does not return string type");
*no_add_attrs = true;
return NULL_TREE;
}
@@ -310,80 +314,6 @@ typedef struct international_format_info
static international_format_info *international_format_list = NULL;
-/* Initialize the table of functions to perform format checking on.
- The ISO C functions are always checked (whether <stdio.h> is
- included or not), since it is common to call printf without
- including <stdio.h>. There shouldn't be a problem with this,
- since ISO C reserves these function names whether you include the
- header file or not. In any case, the checking is harmless. With
- -ffreestanding, these default attributes are disabled, and must be
- specified manually if desired.
-
- Also initialize the name of function that modify the format string for
- internationalization purposes. */
-
-void
-init_function_format_info ()
-{
- /* __builtin functions should be checked unconditionally, even with
- -ffreestanding. */
- record_function_format (get_identifier ("__builtin_printf"), NULL_TREE,
- printf_format_type, 1, 2);
- record_function_format (get_identifier ("__builtin_fprintf"), NULL_TREE,
- printf_format_type, 2, 3);
-
- if (flag_hosted)
- {
- /* Functions from ISO/IEC 9899:1990. */
- record_function_format (get_identifier ("printf"), NULL_TREE,
- printf_format_type, 1, 2);
- record_function_format (get_identifier ("fprintf"), NULL_TREE,
- printf_format_type, 2, 3);
- record_function_format (get_identifier ("sprintf"), NULL_TREE,
- printf_format_type, 2, 3);
- record_function_format (get_identifier ("scanf"), NULL_TREE,
- scanf_format_type, 1, 2);
- record_function_format (get_identifier ("fscanf"), NULL_TREE,
- scanf_format_type, 2, 3);
- record_function_format (get_identifier ("sscanf"), NULL_TREE,
- scanf_format_type, 2, 3);
- record_function_format (get_identifier ("vprintf"), NULL_TREE,
- printf_format_type, 1, 0);
- record_function_format (get_identifier ("vfprintf"), NULL_TREE,
- printf_format_type, 2, 0);
- record_function_format (get_identifier ("vsprintf"), NULL_TREE,
- printf_format_type, 2, 0);
- record_function_format (get_identifier ("strftime"), NULL_TREE,
- strftime_format_type, 3, 0);
- }
-
- if (flag_hosted && (flag_isoc99 || flag_noniso_default_format_attributes))
- {
- /* ISO C99 adds the snprintf and vscanf family functions. */
- record_function_format (get_identifier ("snprintf"), NULL_TREE,
- printf_format_type, 3, 4);
- record_function_format (get_identifier ("vsnprintf"), NULL_TREE,
- printf_format_type, 3, 0);
- record_function_format (get_identifier ("vscanf"), NULL_TREE,
- scanf_format_type, 1, 0);
- record_function_format (get_identifier ("vfscanf"), NULL_TREE,
- scanf_format_type, 2, 0);
- record_function_format (get_identifier ("vsscanf"), NULL_TREE,
- scanf_format_type, 2, 0);
- }
-
- if (flag_hosted && flag_noniso_default_format_attributes)
- {
- /* Uniforum/GNU gettext functions, not in ISO C. */
- record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
- record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
- record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2);
- /* X/Open strfmon function. */
- record_function_format (get_identifier ("strfmon"), NULL_TREE,
- strfmon_format_type, 3, 4);
- }
-}
-
/* Record information for argument format checking. FUNCTION_IDENT is
the identifier node for the name of the function to check (its decl
need not exist yet).
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index b65644ad058..6e3ebaf2a08 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+2001-10-02 Joseph S. Myers <jsm28@cam.ac.uk>
+
+ * decl.c (init_decl_processing): Don't call
+ init_function_format_info. Initialize lang_attribute_table
+ earlier.
+ (builtin_function): Call decl_attributes.
+ (insert_default_attributes): New.
+
2001-10-01 Jason Merrill <jason_merrill@redhat.com>
* decl.c (grokdeclarator): Copy array typedef handling from C
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index dc4eb8116e9..905784e59fe 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6350,6 +6350,8 @@ init_decl_processing ()
std_node = current_namespace;
pop_namespace ();
+ lang_attribute_table = cp_attribute_table;
+
c_common_nodes_and_builtins ();
java_byte_type_node = record_builtin_java_type ("__java_byte", 8);
@@ -6487,14 +6489,9 @@ init_decl_processing ()
make_fname_decl = cp_make_fname_decl;
start_fname_decls ();
- /* Prepare to check format strings against argument lists. */
- init_function_format_info ();
-
/* Show we use EH for cleanups. */
using_eh_for_cleanups ();
- lang_attribute_table = cp_attribute_table;
-
/* Maintain consistency. Perhaps we should just complain if they
say -fwritable-strings? */
if (flag_writable_strings)
@@ -6643,6 +6640,9 @@ builtin_function (name, type, code, class, libname)
if (name[0] != '_' || name[1] != '_')
DECL_ANTICIPATED (decl) = 1;
+ /* Possibly apply some default attributes to this built-in function. */
+ decl_attributes (&decl, NULL_TREE, 0);
+
return decl;
}
@@ -6765,6 +6765,20 @@ push_throw_library_fn (name, type)
TREE_NOTHROW (fn) = 0;
return fn;
}
+
+/* Apply default attributes to a function, if a system function with default
+ attributes. */
+
+void
+insert_default_attributes (decl)
+ tree decl;
+{
+ if (!DECL_EXTERN_C_FUNCTION_P (decl))
+ return;
+ if (!TREE_PUBLIC (decl))
+ return;
+ c_common_insert_default_attributes (decl);
+}
/* When we call finish_struct for an anonymous union, we create
default copy constructors and such. But, an anonymous union
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 997762c4fdb..3c027b7319b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,9 @@
2001-10-02 Joseph S. Myers <jsm28@cam.ac.uk>
+ * gcc.dg/format/attr-5.c, gcc.dg/format/attr-6.c: New tests.
+
+2001-10-02 Joseph S. Myers <jsm28@cam.ac.uk>
+
* g++.dg/warn/format1.C: New test.
2001-10-01 Neil Booth <neil@daikokuya.demon.co.uk>
diff --git a/gcc/testsuite/gcc.dg/format/attr-5.c b/gcc/testsuite/gcc.dg/format/attr-5.c
new file mode 100644
index 00000000000..a4e96344b61
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/format/attr-5.c
@@ -0,0 +1,28 @@
+/* Test for format attributes: test default attributes are silently ignored
+ when a function is redeclared in an inappropriate manner. */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+/* We can't #include "format.h" here. */
+
+/* This scanf declaration is static, so can't be the system function. */
+static int scanf(const char *restrict, ...);
+
+/* This sscanf declaration doesn't have variable arguments, so isn't
+ compatible with a format attribute. */
+extern int sscanf(const char *restrict, const char *restrict, int *);
+
+void
+foo (const char *s, int *p)
+{
+ scanf("%ld", p); /* { dg-bogus "format" "static" } */
+ sscanf(s, "%ld", p); /* { dg-bogus "format" "wrong type" } */
+}
+
+/* Dummy definition of scanf. */
+static int
+scanf (const char *restrict fmt, ...)
+{
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/format/attr-6.c b/gcc/testsuite/gcc.dg/format/attr-6.c
new file mode 100644
index 00000000000..4e95cfb00f6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/format/attr-6.c
@@ -0,0 +1,21 @@
+/* Test for format attributes: test default attributes are applied
+ to implicit declarations. */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89 -Wformat" } */
+
+/* We can't #include "format.h" here. */
+
+/* Technically, none of the format functions should be implicitly declared;
+ either the implicit type is wrong, the function has variable arguments
+ or it requires a type declared in a header. However, some bad programming
+ practice uses implicit declarations of some of these functions.
+
+ Note that printf is not used in this test because of the declaration
+ of it as a built-in function. */
+
+void
+foo (const char *s, int *p)
+{
+ scanf("%ld", p); /* { dg-warning "format" "implicit scanf" } */
+}
diff --git a/gcc/tree.h b/gcc/tree.h
index d4306a88eda..efa0b83c684 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2140,7 +2140,11 @@ enum attribute_flags
ATTR_FLAG_ARRAY_NEXT = 4,
/* The type passed in is a structure, union or enumeration type being
created, and should be modified in place. */
- ATTR_FLAG_TYPE_IN_PLACE = 8
+ ATTR_FLAG_TYPE_IN_PLACE = 8,
+ /* The attributes are being applied by default to a library function whose
+ name indicates known behavior, and should be silently ignored if they
+ are not in fact compatible with the function type. */
+ ATTR_FLAG_BUILT_IN = 16
};
/* Default versions of target-overridable functions. */
@@ -2920,6 +2924,13 @@ extern int setjmp_call_p PARAMS ((tree));
a decl attribute to the declaration rather than to its type). */
extern tree decl_attributes PARAMS ((tree *, tree, int));
+/* The following function must be provided by front ends
+ using attribs.c. */
+
+/* Possibly apply default attributes to a function (represented by
+ a FUNCTION_DECL). */
+extern void insert_default_attributes PARAMS ((tree));
+
/* Table of machine-independent attributes for checking formats, if used. */
extern const struct attribute_spec *format_attribute_table;
OpenPOWER on IntegriCloud