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]

Lazy default attributes patch


This patch implements lazy default attributes: instead of applying
various format attributes to function names at startup, they are
applied to the decls when the functions are declared.  This is a
prerequisite to changing from format attributes going on a list of
format function names to them just getting applied to the function
type, so allowing them to work with function pointers.

This mechanism can (and should) also be used for the default noreturn
attributes presently handled through built-in functions for exit /
abort / _exit / _Exit, and for the default malloc attributes for
malloc, calloc, strdup (and _, __, __x prefixed versions of these) in
special_function_p as well as the other special treatment of function
names in special_function_p (which may require additional
__attribute__ names to be made available, e.g. to describe setjmp-like
functions).  This patch just gets things started by doing the format
and format_arg attributes.  The patch to projects/beginner.html at the
bottom updates the relevant entry there to mention builtin-attrs.def.

Bootstrapped with no regressions on i686-pc-linux-gnu.  OK to commit
(both the code patch and the patch to projects/beginner.html)?

2001-09-23  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.

cp:
2001-09-23  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.

testsuite:
2001-09-23  Joseph S. Myers  <jsm28@cam.ac.uk>

	* gcc.dg/format/attr-5.c, gcc.dg/attr-6.c: New tests.

diff -rupN gcc.orig/Makefile.in gcc/Makefile.in
--- gcc.orig/Makefile.in	Sat Sep 22 15:22:12 2001
+++ gcc/Makefile.in	Sun Sep 23 00:29:28 2001
@@ -1248,7 +1248,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 -rupN gcc.orig/attribs.c gcc/attribs.c
--- gcc.orig/attribs.c	Sat Sep 22 13:14:34 2001
+++ gcc/attribs.c	Sun Sep 23 00:29:39 2001
@@ -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)
@@ -255,6 +259,10 @@ decl_attributes (node, attributes, flags
     init_attributes ();
 
   (*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))
     {
diff -rupN gcc.orig/builtin-attrs.def gcc/builtin-attrs.def
--- gcc.orig/builtin-attrs.def	Thu Jan  1 00:00:00 1970
+++ gcc/builtin-attrs.def	Sun Sep 23 00:14:52 2001
@@ -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 -rupN gcc.orig/c-common.c gcc/c-common.c
--- gcc.orig/c-common.c	Sat Sep 22 15:22:22 2001
+++ gcc/c-common.c	Sun Sep 23 01:04:07 2001
@@ -2322,6 +2322,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.  */
 
@@ -2367,6 +2379,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);
@@ -3772,24 +3788,34 @@ boolean_increment (code, arg)
   return val;
 }
 
-/* Give the specifications for the format attributes, used by C and all
-   descendents.  */
+/* Handle C and C++ default attributes.  */
 
-static const struct attribute_spec c_format_attribute_table[] =
+enum built_in_attribute
 {
-  { "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 }
+#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;
@@ -3806,4 +3832,59 @@ 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
+  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 -rupN gcc.orig/c-common.h gcc/c-common.h
--- gcc.orig/c-common.h	Sat Sep 22 15:22:22 2001
+++ gcc/c-common.h	Sun Sep 23 00:25:55 2001
@@ -503,13 +503,13 @@ extern const char *fname_as_string		PARA
 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 -rupN gcc.orig/c-decl.c gcc/c-decl.c
--- gcc.orig/c-decl.c	Fri Sep 21 01:15:16 2001
+++ gcc/c-decl.c	Sun Sep 23 00:32:00 2001
@@ -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,7 +3152,22 @@ builtin_function (name, type, function_c
   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.
diff -rupN gcc.orig/c-format.c gcc/c-format.c
--- gcc.orig/c-format.c	Sat Sep 22 12:49:46 2001
+++ gcc/c-format.c	Sat Sep 22 18:09:23 2001
@@ -89,7 +89,7 @@ handle_format_attribute (node, name, arg
      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, arg
 	  || (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, arg
 
 	  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,
      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,
 	  || (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,
       || (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;
     }
@@ -309,80 +313,6 @@ typedef struct international_format_info
 } 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
diff -rupN gcc.orig/cp/decl.c gcc/cp/decl.c
--- gcc.orig/cp/decl.c	Fri Sep 21 07:38:50 2001
+++ gcc/cp/decl.c	Sun Sep 23 12:28:18 2001
@@ -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, clas
   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;
 }
 
@@ -6764,6 +6764,20 @@ push_throw_library_fn (name, type)
   TREE_THIS_VOLATILE (fn) = 1;
   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
diff -rupN gcc.orig/testsuite/gcc.dg/format/attr-5.c gcc/testsuite/gcc.dg/format/attr-5.c
--- gcc.orig/testsuite/gcc.dg/format/attr-5.c	Thu Jan  1 00:00:00 1970
+++ gcc/testsuite/gcc.dg/format/attr-5.c	Sun Sep 23 00:06:05 2001
@@ -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 -rupN gcc.orig/testsuite/gcc.dg/format/attr-6.c gcc/testsuite/gcc.dg/format/attr-6.c
--- gcc.orig/testsuite/gcc.dg/format/attr-6.c	Thu Jan  1 00:00:00 1970
+++ gcc/testsuite/gcc.dg/format/attr-6.c	Sun Sep 23 09:38:41 2001
@@ -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 -rupN gcc.orig/tree.h gcc/tree.h
--- gcc.orig/tree.h	Sat Sep 22 15:22:22 2001
+++ gcc/tree.h	Sun Sep 23 00:22:37 2001
@@ -2138,7 +2138,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.  */
@@ -2917,6 +2921,13 @@ extern int setjmp_call_p		PARAMS ((tree)
    returned to be applied at a later stage (for example, to apply
    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;
--- beginner.html.orig	Mon Sep 17 20:36:55 2001
+++ beginner.html	Sun Sep 23 10:03:58 2001
@@ -1197,10 +1197,12 @@
 presuming anything about its semantics within the compiler.  All this
 special handing should be disabled by <samp>-ffreestanding</samp>.</p>
 
-<p>There should be a unified way of attaching attributes to functions
+<p>There is now a unified way of attaching attributes to functions
 with known semantics when they are declared (explicitly or
-implicitly), which should also be used for "builtins" such as exit and
-abort that only exist for this purpose.</p></li>
+implicitly); see <code>builtin-attrs.def</code>.
+This should be used for "builtins" such as exit and
+abort that only exist for this purpose as well as for functions such
+as <code>malloc</code> handled by <code>special_function_p</code>.</p></li>
 
 <li>Move all flags shared between C and C++ to <code>c-common.[ch]</code>.
 

-- 
Joseph S. Myers
jsm28@cam.ac.uk


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