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]

Format checking cleanup patch


This patch does some more cleaning up of the checking of format types.
It also adds a testcase for a tree-checking bug in format checking
fixed by my previous format checking patch.

Bootstrapped with no regressions on i686-pc-linux-gnu.  OK to commit?

gcc/ChangeLog:
2000-09-16  Joseph S. Myers  <jsm28@cam.ac.uk>

	* c-common.c (check_format_types): Reorganise and clean up,
	checking earlier for ERROR_MARKs and making cur_type into its
	TYPE_MAIN_VARIANT where convenient.

gcc/testsuite/ChangeLog:
2000-09-16  Joseph S. Myers  <jsm28@cam.ac.uk>

	* gcc.dg/format-errmk-1.c: New test.

--- c-common.c.orig	Fri Sep 15 21:14:23 2000
+++ c-common.c	Sat Sep 16 08:06:45 2000
@@ -2489,16 +2489,25 @@
     {
       tree cur_param;
       tree cur_type;
+      tree orig_cur_type;
       tree wanted_type;
       int arg_num;
       int i;
       int char_type_flag;
       cur_param = types->param;
       cur_type = TREE_TYPE (cur_param);
+      if (TREE_CODE (cur_type) == ERROR_MARK)
+	continue;
       char_type_flag = 0;
       wanted_type = types->wanted_type;
       arg_num = types->arg_num;
 
+      /* The following should not occur here.  */
+      if (wanted_type == 0)
+	abort ();
+      if (wanted_type == void_type_node && types->pointer_count == 0)
+	abort ();
+
       STRIP_NOPS (cur_param);
 
       /* Check the types of any additional pointer arguments
@@ -2508,6 +2517,8 @@
 	  if (TREE_CODE (cur_type) == POINTER_TYPE)
 	    {
 	      cur_type = TREE_TYPE (cur_type);
+	      if (TREE_CODE (cur_type) == ERROR_MARK)
+		break;
 
 	      if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR)
 		cur_param = TREE_OPERAND (cur_param, 0);
@@ -2521,7 +2532,6 @@
 		 const void ** is simply passing an incompatible type.  */
 	      if (types->writing_in_flag
 		  && i == 0
-		  && TREE_CODE (cur_type) != ERROR_MARK
 		  && (TYPE_READONLY (cur_type)
 		      || (cur_param != 0
 			  && (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'c'
@@ -2534,117 +2544,118 @@
 		 incompatible.  */
 	      if (i > 0
 		  && pedantic
-		  && TREE_CODE (cur_type) != ERROR_MARK
 		  && (TYPE_READONLY (cur_type)
 		      || TYPE_VOLATILE (cur_type)
 		      || TYPE_RESTRICT (cur_type)))
 		warning ("extra type qualifiers in format argument (arg %d)",
 			 arg_num);
 
-	      continue;
 	    }
-	  if (TREE_CODE (cur_type) != ERROR_MARK)
+	  else
 	    {
 	      if (types->pointer_count == 1)
 		warning ("format argument is not a pointer (arg %d)", arg_num);
 	      else
 		warning ("format argument is not a pointer to a pointer (arg %d)", arg_num);
+	      break;
 	    }
-	  break;
 	}
 
+      if (i < types->pointer_count)
+	continue;
+
+      orig_cur_type = cur_type;
+      cur_type = TYPE_MAIN_VARIANT (cur_type);
+
       /* Check whether the argument type is a character type.  This leniency
 	 only applies to certain formats, flagged with 'c'.
       */
-      if (TREE_CODE (cur_type) != ERROR_MARK && types->char_lenient_flag)
-	char_type_flag = (TYPE_MAIN_VARIANT (cur_type) == char_type_node
-			  || TYPE_MAIN_VARIANT (cur_type) == signed_char_type_node
-			  || TYPE_MAIN_VARIANT (cur_type) == unsigned_char_type_node);
+      if (types->char_lenient_flag)
+	char_type_flag = (cur_type == char_type_node
+			  || cur_type == signed_char_type_node
+			  || cur_type == unsigned_char_type_node);
 
       /* Check the type of the "real" argument, if there's a type we want.  */
-      if (i == types->pointer_count && wanted_type != 0
-	  && TREE_CODE (cur_type) != ERROR_MARK
-	  && wanted_type != TYPE_MAIN_VARIANT (cur_type)
-	  /* If we want `void *', allow any pointer type.
-	     (Anything else would already have got a warning.)
-	     With -pedantic, only allow pointers to void and to character
-	     types.
-	  */
-	  && ! (wanted_type == void_type_node
-		&& types->pointer_count > 0
-		&& (! pedantic
-		    || TYPE_MAIN_VARIANT (cur_type) == void_type_node
-		    || (i == 1 && char_type_flag)))
-	  /* Don't warn about differences merely in signedness, unless
-	     -pedantic.  With -pedantic, warn if the type is a pointer
-	     target and not a character type, and for character types at
-	     a second level of indirection.
-	  */
-	  && !(TREE_CODE (wanted_type) == INTEGER_TYPE
-	       && TREE_CODE (TYPE_MAIN_VARIANT (cur_type)) == INTEGER_TYPE
-	       && (! pedantic || i == 0 || (i == 1 && char_type_flag))
-	       && (TREE_UNSIGNED (wanted_type)
-		   ? wanted_type == (cur_type = unsigned_type (cur_type))
-		   : wanted_type == (cur_type = signed_type (cur_type))))
-	  /* Likewise, "signed char", "unsigned char" and "char" are
-	     equivalent but the above test won't consider them equivalent.  */
-	  && ! (wanted_type == char_type_node
-		&& (! pedantic || i < 2)
-		&& char_type_flag))
-	{
-	  register const char *this;
-	  register const char *that;
-
-	  this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type)));
-	  that = 0;
-	  if (TREE_CODE (cur_type) != ERROR_MARK
-	      && TYPE_NAME (cur_type) != 0
-	      && TREE_CODE (cur_type) != INTEGER_TYPE
-	      && !(TREE_CODE (cur_type) == POINTER_TYPE
-		   && TREE_CODE (TREE_TYPE (cur_type)) == INTEGER_TYPE))
-	    {
-	      if (TREE_CODE (TYPE_NAME (cur_type)) == TYPE_DECL
-		  && DECL_NAME (TYPE_NAME (cur_type)) != 0)
-		that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type)));
-	      else
-		that = IDENTIFIER_POINTER (TYPE_NAME (cur_type));
-	    }
-
-	  /* A nameless type can't possibly match what the format wants.
-	     So there will be a warning for it.
-	     Make up a string to describe vaguely what it is.  */
-	  if (that == 0)
-	    {
-	      if (TREE_CODE (cur_type) == POINTER_TYPE)
-		that = "pointer";
-	      else
-		that = "different type";
-	    }
-
-	  /* Make the warning better in case of mismatch of int vs long.  */
-	  if (TREE_CODE (cur_type) == INTEGER_TYPE
-	      && TREE_CODE (wanted_type) == INTEGER_TYPE
-	      && TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type)
-	      && TYPE_NAME (cur_type) != 0
-	      && TREE_CODE (TYPE_NAME (cur_type)) == TYPE_DECL)
-	    that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type)));
-
-	  if (strcmp (this, that) != 0)
-	    {
-	      /* There may be a better name for the format, e.g. size_t,
-		 but we should allow for programs with a perverse typedef
-		 making size_t something other than what the compiler
-		 thinks.  */
-	      if (types->wanted_type_name != 0
-		  && strcmp (types->wanted_type_name, that) != 0)
-		this = types->wanted_type_name;
-	      if (types->name != 0)
-		warning ("%s is not type %s (arg %d)", types->name, this,
-			 arg_num);
-	      else
-		warning ("%s format, %s arg (arg %d)", this, that, arg_num);
-	    }
-	}
+      if (wanted_type == cur_type)
+	continue;
+      /* If we want `void *', allow any pointer type.
+	 (Anything else would already have got a warning.)
+	 With -pedantic, only allow pointers to void and to character
+	 types.  */
+      if (wanted_type == void_type_node
+	  && (!pedantic || (i == 1 && char_type_flag)))
+	continue;
+      /* Don't warn about differences merely in signedness, unless
+	 -pedantic.  With -pedantic, warn if the type is a pointer
+	 target and not a character type, and for character types at
+	 a second level of indirection.  */
+      if (TREE_CODE (wanted_type) == INTEGER_TYPE
+	  && TREE_CODE (cur_type) == INTEGER_TYPE
+	  && (! pedantic || i == 0 || (i == 1 && char_type_flag))
+	  && (TREE_UNSIGNED (wanted_type)
+	      ? wanted_type == unsigned_type (cur_type)
+	      : wanted_type == signed_type (cur_type)))
+	continue;
+      /* Likewise, "signed char", "unsigned char" and "char" are
+	 equivalent but the above test won't consider them equivalent.  */
+      if (wanted_type == char_type_node
+	  && (! pedantic || i < 2)
+	  && char_type_flag)
+	continue;
+      /* Now we have a type mismatch.  */
+      {
+	register const char *this;
+	register const char *that;
+
+	this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type)));
+	that = 0;
+	if (TYPE_NAME (orig_cur_type) != 0
+	    && TREE_CODE (orig_cur_type) != INTEGER_TYPE
+	    && !(TREE_CODE (orig_cur_type) == POINTER_TYPE
+		 && TREE_CODE (TREE_TYPE (orig_cur_type)) == INTEGER_TYPE))
+	  {
+	    if (TREE_CODE (TYPE_NAME (orig_cur_type)) == TYPE_DECL
+		&& DECL_NAME (TYPE_NAME (orig_cur_type)) != 0)
+	      that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (orig_cur_type)));
+	    else
+	      that = IDENTIFIER_POINTER (TYPE_NAME (orig_cur_type));
+	  }
+
+	/* A nameless type can't possibly match what the format wants.
+	   So there will be a warning for it.
+	   Make up a string to describe vaguely what it is.  */
+	if (that == 0)
+	  {
+	    if (TREE_CODE (orig_cur_type) == POINTER_TYPE)
+	      that = "pointer";
+	    else
+	      that = "different type";
+	  }
+
+	/* Make the warning better in case of mismatch of int vs long.  */
+	if (TREE_CODE (orig_cur_type) == INTEGER_TYPE
+	    && TREE_CODE (wanted_type) == INTEGER_TYPE
+	    && TYPE_PRECISION (orig_cur_type) == TYPE_PRECISION (wanted_type)
+	    && TYPE_NAME (orig_cur_type) != 0
+	    && TREE_CODE (TYPE_NAME (orig_cur_type)) == TYPE_DECL)
+	  that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (orig_cur_type)));
+
+	if (strcmp (this, that) != 0)
+	  {
+	    /* There may be a better name for the format, e.g. size_t,
+	       but we should allow for programs with a perverse typedef
+	       making size_t something other than what the compiler
+	       thinks.  */
+	    if (types->wanted_type_name != 0
+		&& strcmp (types->wanted_type_name, that) != 0)
+	      this = types->wanted_type_name;
+	    if (types->name != 0)
+	      warning ("%s is not type %s (arg %d)", types->name, this,
+		       arg_num);
+	    else
+	      warning ("%s format, %s arg (arg %d)", this, that, arg_num);
+	  }
+      }
     }
 }
 
--- /dev/null	Fri Sep 11 11:31:59 1998
+++ format-errmk-1.c	Fri Sep 15 21:18:41 2000
@@ -0,0 +1,12 @@
+/* Test for format checking not giving tree checking errors.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-Wformat" } */
+
+extern int printf (const char *, ...);
+
+void
+foo (int t)
+{
+  printf ("%*d", u, t); /* { dg-error "undeclared|function" "u undeclared error" } */
+}

-- 
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]