head	1.3;
access;
symbols
	RELEASE_8_0_0:1.2
	RELEASE_7_2_0:1.2
	RELEASE_7_1_0:1.2
	RELEASE_6_4_0:1.2
	RELEASE_5_EOL:1.2
	RELEASE_7_0_0:1.2
	RELEASE_6_3_0:1.2
	PRE_XORG_7:1.2
	RELEASE_4_EOL:1.2
	RELEASE_6_2_0:1.2
	RELEASE_6_1_0:1.2
	RELEASE_5_5_0:1.2
	RELEASE_6_0_0:1.2
	RELEASE_5_4_0:1.2
	RELEASE_4_11_0:1.2
	RELEASE_5_3_0:1.2
	RELEASE_4_10_0:1.2
	RELEASE_5_2_1:1.2
	RELEASE_5_2_0:1.2
	RELEASE_4_9_0:1.2
	RELEASE_5_1_0:1.2
	RELEASE_4_8_0:1.2
	RELEASE_5_0_0:1.2
	RELEASE_4_7_0:1.2
	RELEASE_4_6_2:1.2
	RELEASE_4_6_1:1.2
	RELEASE_4_6_0:1.2
	RELEASE_5_0_DP1:1.2
	RELEASE_4_5_0:1.2
	RELEASE_4_4_0:1.2
	RELEASE_4_3_0:1.2
	gcc_2_95_3:1.2
	gcc_2_95_3_test1:1.2
	gcc_2_95_2_inital:1.1
	RELEASE_4_2_0:1.1
	RELEASE_4_1_1:1.1
	RELEASE_4_1_0:1.1
	RELEASE_3_5_0:1.1
	RELEASE_4_0_0:1.1
	RELEASE_3_4_0:1.1
	gcc_2_95_2:1.2
	RELEASE_3_3_0:1.1
	gcc_2_95_1:1.1
	gcc_2_95:1.1
	egcs_1_1_2:1.1
	RELEASE_3_2_0:1.1;
locks; strict;
comment	@# @;


1.3
date	2009.11.21.22.00.18;	author gerald;	state dead;
branches;
next	1.2;

1.2
date	2000.11.27.01.12.33;	author obrien;	state Exp;
branches;
next	1.1;

1.1
date	99.03.30.18.15.39;	author obrien;	state Exp;
branches;
next	;


desc
@@


1.3
log
@Remove lang/gcc295 which is not used by any other port and had been
unused/unusable for most of last year.  Recommend lang/gcc44 instead.

Approved by:	maintainer
@
text
@--- gcc/c-common.c.orig	Tue Sep  7 01:11:16 1999
+++ gcc/c-common.c	Sun Nov 26 15:35:38 2000
@@@@ -64,7 +64,7 @@@@
 					       int, int, int));
 static void init_attributes		PROTO((void));
 static void record_function_format	PROTO((tree, tree, enum format_type,
-					       int, int));
+					       int, int, int));
 static void record_international_format	PROTO((tree, tree, int));
 static tree c_find_base_decl            PROTO((tree));
 static int default_valid_lang_attribute PROTO ((tree, tree, tree, tree));
@@@@ -715,6 +715,7 @@@@
 	      = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
 	    int format_num;
 	    int first_arg_num;
+	    int null_format_ok;
 	    enum format_type format_type;
 	    tree argument;
 	    int arg_num;
@@@@ -728,7 +729,7 @@@@
 	
 	    if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
 	      {
-		error ("unrecognized format specifier");
+		error_with_decl (decl, "unrecognized format specifier");
 		continue;
 	      }
 	    else
@@@@ -736,12 +737,26 @@@@
 		const char *p = IDENTIFIER_POINTER (format_type_id);
 		
 		if (!strcmp (p, "printf") || !strcmp (p, "__printf__"))
+		  {
+		  format_type = printf_format_type;
+		  null_format_ok = 0;
+		  }
+		else if (!strcmp (p, "printf0") || !strcmp (p, "__printf0__"))
+		  {
 		  format_type = printf_format_type;
+		  null_format_ok = 1;
+		  }
 		else if (!strcmp (p, "scanf") || !strcmp (p, "__scanf__"))
+		  {
 		  format_type = scanf_format_type;
+		  null_format_ok = 0;
+		  }
 		else if (!strcmp (p, "strftime")
 			 || !strcmp (p, "__strftime__"))
+		  {
 		  format_type = strftime_format_type;
+		  null_format_ok = 0;
+		  }
 		else
 		  {
 		    warning ("`%s' is an unrecognized format function type", p);
@@@@ -812,7 +827,8 @@@@
 
 	    record_function_format (DECL_NAME (decl),
 				    DECL_ASSEMBLER_NAME (decl),
-				    format_type, format_num, first_arg_num);
+				    format_type,  null_format_ok, format_num,
+				    first_arg_num);
 	    break;
 	  }
 
@@@@ -1090,6 +1106,11 @@@@
 } format_char_info;
 
 static format_char_info print_char_table[] = {
+/* FreeBSD kernel extensions.  */
+  { "D",	1,	T_C,	T_C,	NULL,	NULL,	NULL,	NULL,	NULL,	"-wp"		},
+  { "b",	1,	T_C,	T_C,	NULL,	NULL,	NULL,	NULL,	NULL,	"-wp"		},
+  { "rz",	0,	NULL,	T_I,	T_I,	T_L,	NULL,	NULL,	NULL,	"-wp0 +#"	},
+#define unextended_print_char_table	(print_char_table + 3)
   { "di",	0,	T_I,	T_I,	T_I,	T_L,	T_LL,	T_LL,	T_ST,	"-wp0 +"	},
   { "oxX",	0,	T_UI,	T_UI,	T_UI,	T_UL,	T_ULL,	T_ULL,	T_ST,	"-wp0#"		},
   { "u",	0,	T_UI,	T_UI,	T_UI,	T_UL,	T_ULL,	T_ULL,	T_ST,	"-wp0"		},
@@@@ -1150,6 +1171,7 @@@@
   tree name;			/* identifier such as "printf" */
   tree assembler_name;		/* optional mangled identifier (for C++) */
   enum format_type format_type;	/* type of format (printf, scanf, etc.) */
+  int null_format_ok;		/* TRUE if the format string may be NULL */
   int format_num;		/* number of format argument */
   int first_arg_num;		/* number of first arg (zero for varargs) */
 } function_format_info;
@@@@ -1182,25 +1204,25 @@@@
 init_function_format_info ()
 {
   record_function_format (get_identifier ("printf"), NULL_TREE,
-			  printf_format_type, 1, 2);
+			  printf_format_type, 0, 1, 2);
   record_function_format (get_identifier ("fprintf"), NULL_TREE,
-			  printf_format_type, 2, 3);
+			  printf_format_type, 0, 2, 3);
   record_function_format (get_identifier ("sprintf"), NULL_TREE,
-			  printf_format_type, 2, 3);
+			  printf_format_type, 0, 2, 3);
   record_function_format (get_identifier ("scanf"), NULL_TREE,
-			  scanf_format_type, 1, 2);
+			  scanf_format_type, 0, 1, 2);
   record_function_format (get_identifier ("fscanf"), NULL_TREE,
-			  scanf_format_type, 2, 3);
+			  scanf_format_type, 0, 2, 3);
   record_function_format (get_identifier ("sscanf"), NULL_TREE,
-			  scanf_format_type, 2, 3);
+			  scanf_format_type, 0, 2, 3);
   record_function_format (get_identifier ("vprintf"), NULL_TREE,
-			  printf_format_type, 1, 0);
+			  printf_format_type, 0, 1, 0);
   record_function_format (get_identifier ("vfprintf"), NULL_TREE,
-			  printf_format_type, 2, 0);
+			  printf_format_type, 0, 2, 0);
   record_function_format (get_identifier ("vsprintf"), NULL_TREE,
-			  printf_format_type, 2, 0);
+			  printf_format_type, 0, 2, 0);
   record_function_format (get_identifier ("strftime"), NULL_TREE,
-			  strftime_format_type, 3, 0);
+			  strftime_format_type, 0, 3, 0);
 
   record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
   record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
@@@@ -1217,11 +1239,12 @@@@
    (e.g. for varargs such as vfprintf).  */
 
 static void
-record_function_format (name, assembler_name, format_type,
+record_function_format (name, assembler_name, format_type, null_format_ok,
 			format_num, first_arg_num)
       tree name;
       tree assembler_name;
       enum format_type format_type;
+      int null_format_ok;
       int format_num;
       int first_arg_num;
 {
@@@@ -1245,6 +1268,7 @@@@
     }
 
   info->format_type = format_type;
+  info->null_format_ok = null_format_ok;
   info->format_num = format_num;
   info->first_arg_num = first_arg_num;
 }
@@@@ -1292,6 +1316,21 @@@@
   warning ("too few arguments for format");
 }
 
+static function_format_info *
+find_function_format (name, assembler_name)
+     tree name;
+     tree assembler_name;
+{
+  function_format_info *info;
+
+  for (info = function_format_list; info; info = info->next)
+    if (info->assembler_name
+	? (info->assembler_name == assembler_name)
+	: (info->name == name))
+      return info;
+  return 0;
+}
+
 /* Check the argument list of a call to printf, scanf, etc.
    NAME is the function identifier.
    ASSEMBLER_NAME is the function's assembler identifier.
@@@@ -1307,17 +1346,10 @@@@
   function_format_info *info;
 
   /* See if this function is a format function.  */
-  for (info = function_format_list; info; info = info->next)
-    {
-      if (info->assembler_name
-	  ? (info->assembler_name == assembler_name)
-	  : (info->name == name))
-	{
-	  /* Yup; check it.  */
-	  check_format_info (info, params);
-	  break;
-	}
-    }
+  info = find_function_format (name, assembler_name);
+
+  if (info)
+    check_format_info (info, params);
 }
 
 /* Check the argument list of a call to printf, scanf, etc.
@@@@ -1361,6 +1393,7 @@@@
     return;
 
   /* We can only check the format if it's a string constant.  */
+ again:
   while (TREE_CODE (format_tree) == NOP_EXPR)
     format_tree = TREE_OPERAND (format_tree, 0); /* strip coercion */
 
@@@@ -1396,16 +1429,73 @@@@
 	  }
     }
 
+  if (TREE_CODE (format_tree) == COND_EXPR) 
+    {
+      format_tree = TREE_OPERAND(format_tree, 1);
+      goto again;
+    }
+
   if (integer_zerop (format_tree))
     {
-      warning ("null format string");
+      if (!info->null_format_ok)
+	warning ("null format string");
+      return;
+    }
+  if (TREE_CODE (format_tree) != ADDR_EXPR) 
+    {
+      if ((info->first_arg_num == 0) &&
+	  (TREE_CODE(format_tree) == PARM_DECL)) 
+	{
+	  function_format_info *i2;
+	  tree p;
+	  int n;
+
+	  /* Now, we need to determine if the current function is printf-like,
+	     and, if so, if the parameter we have here is as a parameter of 
+	     the current function and is in the argument slot declared to 
+	     contain the format argument. */
+
+	  p = current_function_decl;
+
+	  i2 = find_function_format (p->decl.name, p->decl.assembler_name);
+
+	  if (i2 == NULL) 
+	    {
+	      if (warn_format > 1)
+		warning("non-constant format parameter");
+	    }
+	  else
+	    {
+	      for (n = 1, p = current_function_decl->decl.arguments;
+		   (n < i2->format_num) && (p != NULL); 
+		   n++, p = TREE_CHAIN(p)) 
+		;
+	      if ((p == NULL) || (n != i2->format_num)) 
+		warning("can't find format arg for current format function");
+	      else if (p != format_tree)
+		warning("format argument passed here is not declared as format argument");
+	    }
+	}
+      else if ((info->format_type != strftime_format_type) &&
+	       (warn_format > 1))
+	warning("non-constant format parameter");
       return;
     }
-  if (TREE_CODE (format_tree) != ADDR_EXPR)
-    return;
   format_tree = TREE_OPERAND (format_tree, 0);
-  if (TREE_CODE (format_tree) != STRING_CST)
-    return;
+  if (warn_format > 1 &&
+      (TREE_CODE (format_tree) == VAR_DECL) &&
+      TREE_READONLY(format_tree) &&
+      (DECL_INITIAL(format_tree) != NULL) && 
+      TREE_CODE(DECL_INITIAL(format_tree)) == STRING_CST)
+    format_tree = DECL_INITIAL(format_tree);
+       
+  if (TREE_CODE (format_tree) != STRING_CST) 
+    {
+      if ((info->format_type != strftime_format_type) &&
+	  (warn_format > 1))
+	warning("non-constant format parameter");
+      return;
+    }
   format_chars = TREE_STRING_POINTER (format_tree);
   format_length = TREE_STRING_LENGTH (format_tree);
   if (format_length <= 1)
@@@@ -1433,7 +1523,10 @@@@
 	  if (format_chars - TREE_STRING_POINTER (format_tree) != format_length)
 	    warning ("embedded `\\0' in format");
 	  if (info->first_arg_num != 0 && params != 0 && ! has_operand_number)
-	    warning ("too many arguments for format");
+	    {
+	      if (warn_format_extra_args)
+		warning ("too many arguments for format");
+	    }
 	  return;
 	}
       if (*format_chars++ != '%')
@@@@ -1569,12 +1662,13 @@@@
 		     It will work on most machines, because size_t and int
 		     have the same mode.  But might as well warn anyway,
 		     since it will fail on other machines.  */
+		  /* XXX should we allow unsigned ints here?  */
 		  if ((TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
 		       != integer_type_node)
 		      &&
 		      (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
 		       != unsigned_type_node))
-		    warning ("field width is not type int (arg %d)", arg_num);
+		    warning ("precision is not type int (arg %d)", arg_num);
 		}
 	    }
 	  else
@@@@ -1619,6 +1713,53 @@@@
 		}
 	    }
 	}
+      if (*format_chars == 'b')
+	{
+	  /* There should be an int arg to control the string arg.  */
+	  if (params == 0)
+	    {
+	      warning (tfaff);
+	      return;
+	    }
+	    if (info->first_arg_num != 0)
+	    {
+	      cur_param = TREE_VALUE (params);
+	      params = TREE_CHAIN (params);
+	      ++arg_num;
+	      if ((TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
+		   != integer_type_node)
+		  &&
+		  (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
+		   != unsigned_type_node))
+		{
+		  warning ("bitmap is not type int (arg %d)", arg_num);
+		}
+	    }
+	}
+      if (*format_chars == 'D')
+	{
+	  /* There should be an unsigned char * arg before the string arg.  */
+	  if (params == 0)
+	    {
+	      warning (tfaff);
+	      return;
+	    }
+	    if (info->first_arg_num != 0)
+	    {
+	      cur_param = TREE_VALUE (params);
+	      params = TREE_CHAIN (params);
+	      ++arg_num;
+	      cur_type = TREE_TYPE (cur_param);
+	      if (TREE_CODE (cur_type) != POINTER_TYPE
+		  || TYPE_MAIN_VARIANT (TREE_TYPE (cur_type))
+		     != unsigned_char_type_node)
+		{
+		  warning ("ethernet address is not type unsigned char *"
+			   " (arg %d)",
+			   arg_num);
+		}
+	    }
+	}
 
       aflag = 0;
 
@@@@ -1688,7 +1829,8 @@@@
       switch (info->format_type)
 	{
 	case printf_format_type:
-	  fci = print_char_table;
+	  fci = flag_format_extensions ? print_char_table
+	  	: unextended_print_char_table;
 	  break;
 	case scanf_format_type:
 	  fci = scan_char_table;
@@@@ -1787,7 +1929,6 @@@@
 	warning ("use of `%c' length character with `%c' type character",
 		 length_char, format_char);
 
-      /* Finally. . .check type of argument against desired type!  */
       if (info->first_arg_num == 0)
 	continue;
       if (fci->pointer_count == 0 && wanted_type == void_type_node)
@


1.2
log
@Add "-Wnon-const-format" which checks for non-constant format strings for
auditing purposes.

Submitted by:	kris
Obtained from:	NetBSD
@
text
@@


1.1
log
@Add FreeBSD's ``-fformat-extensions''.  Taken from 4.0-CURRENT, this allows
2.x/3.x people to compile kernels and world with EGCS.
@
text
@d1 3
a3 3
--- gcc/c-common.c.orig	Mon Feb 15 16:40:05 1999
+++ gcc/c-common.c	Tue Mar 30 03:35:22 1999
@@@@ -61,7 +61,7 @@@@
d10 3
a12 3
 
 /* Keep a stack of if statements.  We record the number of compound
@@@@ -669,6 +669,7 @@@@
d20 1
a20 1
@@@@ -682,7 +683,7 @@@@
d29 2
a30 2
@@@@ -690,12 +691,26 @@@@
 		char *p = IDENTIFIER_POINTER (format_type_id);
d55 2
a56 2
 		    error ("`%s' is an unrecognized format function type", p);
@@@@ -766,7 +781,8 @@@@
d66 1
a66 1
@@@@ -1010,6 +1026,11 @@@@
d78 1
a78 1
@@@@ -1070,6 +1091,7 @@@@
d86 1
a86 1
@@@@ -1102,25 +1124,25 @@@@
d122 1
a122 1
@@@@ -1137,11 +1159,12 @@@@
d136 1
a136 1
@@@@ -1165,6 +1188,7 @@@@
d144 46
a189 1
@@@@ -1314,7 +1338,8 @@@@
d191 15
d211 40
d253 35
a287 2
   if (TREE_CODE (format_tree) != ADDR_EXPR)
@@@@ -1485,12 +1510,13 @@@@
d302 1
a302 1
@@@@ -1535,6 +1561,53 @@@@
d356 1
a356 1
@@@@ -1604,7 +1677,8 @@@@
d366 8
@

