]> gcc.gnu.org Git - gcc.git/commitdiff
attribs.c (decl_attributes): Possibly call insert_default_attributes to insert defaul...
authorJoseph Myers <jsm28@cam.ac.uk>
Tue, 2 Oct 2001 07:12:25 +0000 (08:12 +0100)
committerJoseph Myers <jsm28@gcc.gnu.org>
Tue, 2 Oct 2001 07:12:25 +0000 (08:12 +0100)
* 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.

From-SVN: r45942

14 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/attribs.c
gcc/builtin-attrs.def [new file with mode: 0644]
gcc/c-common.c
gcc/c-common.h
gcc/c-decl.c
gcc/c-format.c
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/format/attr-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/format/attr-6.c [new file with mode: 0644]
gcc/tree.h

index afccd79e46502e9575db16c079be32b3f3cd4c24..7a10bfa342c0addf89e3108b5230cf752194a9d7 100644 (file)
@@ -1,3 +1,32 @@
+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.
index 301b6e7144c938353b9bffb4389a07a10dc98255..5cd0610d804f7f5952c65113b56143a3ea9fed96 100644 (file)
@@ -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.
 
index 1413dc267f9a8393d29d5e0a4bd99d8d3072491d..29982dec52972c7ab76ff2598203b7b4cb2272d1 100644 (file)
@@ -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 (file)
index 0000000..de98501
--- /dev/null
@@ -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
index 190c338d5f96010615118ad38c20dd2b1a7212a9..a3314ff1fac7faa8c7b400edc9825e7966fa4dfd 100644 (file)
@@ -2324,6 +2324,18 @@ c_alignof_expr (expr)
   return fold (build1 (NOP_EXPR, c_size_type_node, t));
 }
 \f
+/* 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;
 }
 \f
-/* 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
 }
index 3681ed222f02430f2f2654bd5777347f76221ee9..66df266a1e03344d68284bbbfb4c2b09c73e3a39 100644 (file)
@@ -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));
index 4652267c667916d20a67a240d13f9ac1faa36ec5..f3ad82ea79c94bd21f53d390f86b1d82a8708f9f 100644 (file)
@@ -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);
+}
 \f
 /* 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
index 3cc880e870e07e89bcb3eaf18f309bb3df035c4c..4ee3b3d44a28f6e45b39a5a320267a88a4fb5494 100644 (file)
@@ -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).
index b65644ad0589bcc4035d03fbdf288716144b00c9..6e3ebaf2a0838ada19f96721a3e87bd06fbba5b1 100644 (file)
@@ -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
index dc4eb8116e941abd5391b101c2883a0edb78d925..905784e59fec75253da6af4d9b441a9b25399d88 100644 (file)
@@ -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);
+}
 \f
 /* When we call finish_struct for an anonymous union, we create
    default copy constructors and such.  But, an anonymous union
index 997762c4fdbe028f005b10866f603c672fcd6119..3c027b7319b1b6e4d9921d130cc2b002caed70cb 100644 (file)
@@ -1,3 +1,7 @@
+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.
diff --git a/gcc/testsuite/gcc.dg/format/attr-5.c b/gcc/testsuite/gcc.dg/format/attr-5.c
new file mode 100644 (file)
index 0000000..a4e9634
--- /dev/null
@@ -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 (file)
index 0000000..4e95cfb
--- /dev/null
@@ -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" } */
+}
index d4306a88eda7b8a2ef4164ec3b173348df218d03..efa0b83c684e664b356557b6548e82ad38cde782 100644 (file)
@@ -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;
 
This page took 0.138375 seconds and 5 git commands to generate.