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]
Other format: [Raw text]

Patch for bug 15698


This patch fixes bug 15698, a regression in 4.0 and 4.1.  (The
testcases show several related issues where 4.0/4.1 were missing
diagnostics or had them in the wrong place.  These vary in whether and
how they were regressions.  The original bug was a misplaced
diagnostic; the diagnostic then disappeared as fallout from my fix of
bug 13801.  There are more issues I know of or found in the course of
this fix which are fallout from that fix; I'll file separate
regression bugs for those.  All these issues of missing diagnostics
relate to cases where the C standard does not require a diagnostic but
the behavior is compile-time undefined and we try to issue a
diagnostic as a quality-of-implementation matter.  The residual cases
of missing diagnostics left after this patch are obscure cases of
types being refined incompatibly in different scopes.)

As with other diagnostics for conflicts with built-in functions, those
in this patch for old-style definitions conflicting with a built-in
function are warnings not errors.  (It was also already the case that
in such cases we discard the built-in definition, but previously we
only warned with -Wshadow or if the return type was wrong or if the
built-in function had unpromoted argument types which could not be
compatible with an old-style function definition; not where the return
type was correct but the arguments disagreed.)

Bootstrapped with no regressions on x86_64-unknown-linux-gnu, mainline
and (with appropriate changes to the parameters of "warning") 4.0
branch.  Applied to mainline and 4.0 branch.

Remaining 4.0 component "c" regressions after this patch:

12245 memory consumption, not fixable for 4.0
17913 residual cases of jumping into statement expressions, under discussion
18715 has a disputed patch, may need reposting for further discussion
      of the comments made on the last version
21160 documentation out of date
(and I'll shortly file two more for the obscure cases arising from
the fix of bug 13801)

-- 
Joseph S. Myers               http://www.srcf.ucam.org/~jsm28/gcc/
    jsm@polyomino.org.uk (personal mail)
    joseph@codesourcery.com (CodeSourcery mail)
    jsm28@gcc.gnu.org (Bugzilla assignments and CCs)

2005-05-02  Joseph S. Myers  <joseph@codesourcery.com>

	PR c/15698
	* c-tree.h (C_DECL_BUILTIN_PROTOTYPE): New.
	* c-decl.c (current_function_prototype_built_in,
	current_function_prototype_arg_types): New.
	(merge_decls): Keep source location of prototype followed by
	nonprototype declaration.  Update C_DECL_BUILTIN_PROTOTYPE.
	(builtin_function): Set C_DECL_BUILTIN_PROTOTYPE.
	(start_function): Always set current_function_prototype_locus,
	current_function_prototype_built_in and
	current_function_prototype_arg_types.  Check for external
	prototype whether or not visible for external function and set
	current_function_prototype_arg_types accordingly.
	(store_parm_decls_oldstyle): Use
	current_function_prototype_arg_types for checking old-style
	definition against prototype.  Give warnings only if
	current_function_prototype_built_in).

testsuite:
2005-05-02  Joseph S. Myers  <joseph@codesourcery.com>

	PR c/15698
	* gcc.dg/builtins-30.c: Update expected messages.
	* gcc.dg/pr15698-1.c, gcc.dg/pr15698-2.c, gcc.dg/pr15698-3.c,
	gcc.dg/pr15698-4.c, gcc.dg/pr15698-5.c, gcc.dg/pr15698-6.c,
	gcc.dg/pr15698-7.c, pr15698-8.c: New tests.

diff -rupN GCC.orig/gcc/c-decl.c GCC/gcc/c-decl.c
--- GCC.orig/gcc/c-decl.c	2005-04-27 00:43:56.000000000 +0000
+++ GCC/gcc/c-decl.c	2005-05-02 13:36:57.000000000 +0000
@@ -98,6 +98,14 @@ static int enum_overflow;
 
 static location_t current_function_prototype_locus;
 
+/* Whether this prototype was built-in.  */
+
+static bool current_function_prototype_built_in;
+
+/* The argument type information of this prototype.  */
+
+static tree current_function_prototype_arg_types;
+
 /* The argument information structure for the function currently being
    defined.  */
 
@@ -1574,6 +1582,10 @@ merge_decls (tree newdecl, tree olddecl,
 {
   int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
 			   && DECL_INITIAL (newdecl) != 0);
+  int new_is_prototype = (TREE_CODE (newdecl) == FUNCTION_DECL
+			  && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0);
+  int old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL
+			  && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) != 0);
 
   /* For real parm decl following a forward decl, rechain the old decl
      in its new location and clear TREE_ASM_WRITTEN (it's not a
@@ -1647,8 +1659,12 @@ merge_decls (tree newdecl, tree olddecl,
   if (TREE_DEPRECATED (newdecl))
     TREE_DEPRECATED (olddecl) = 1;
 
-  /* Keep source location of definition rather than declaration.  */
-  if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
+  /* Keep source location of definition rather than declaration and of
+     prototype rather than non-prototype unless that prototype is
+     built-in.  */
+  if ((DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
+      || (old_is_prototype && !new_is_prototype
+	  && !C_DECL_BUILTIN_PROTOTYPE (olddecl)))
     DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl);
 
   /* Merge the unused-warning information.  */
@@ -1764,6 +1780,11 @@ merge_decls (tree newdecl, tree olddecl,
 	  DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
 	  DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
 	  C_DECL_DECLARED_BUILTIN (newdecl) = 1;
+	  if (new_is_prototype)
+	    C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0;
+	  else
+	    C_DECL_BUILTIN_PROTOTYPE (newdecl)
+	      = C_DECL_BUILTIN_PROTOTYPE (olddecl);
 	}
 
       /* Also preserve various other info from the definition.  */
@@ -2706,6 +2727,7 @@ builtin_function (const char *name, tree
   DECL_LANG_SPECIFIC (decl) = GGC_CNEW (struct lang_decl);
   DECL_BUILT_IN_CLASS (decl) = cl;
   DECL_FUNCTION_CODE (decl) = function_code;
+  C_DECL_BUILTIN_PROTOTYPE (decl) = (TYPE_ARG_TYPES (type) != 0);
   if (library_name)
     SET_DECL_ASSEMBLER_NAME (decl, get_identifier (library_name));
 
@@ -5716,14 +5738,53 @@ start_function (struct c_declspecs *decl
   /* If this definition isn't a prototype and we had a prototype declaration
      before, copy the arg type info from that prototype.  */
   old_decl = lookup_name_in_scope (DECL_NAME (decl1), current_scope);
-  if (old_decl != 0 && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE
-      && comptypes (TREE_TYPE (TREE_TYPE (decl1)),
-		    TREE_TYPE (TREE_TYPE (old_decl)))
-      && TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0)
-    {
-      TREE_TYPE (decl1) = composite_type (TREE_TYPE (old_decl),
-					  TREE_TYPE (decl1));
-      current_function_prototype_locus = DECL_SOURCE_LOCATION (old_decl);
+  current_function_prototype_locus = UNKNOWN_LOCATION;
+  current_function_prototype_built_in = false;
+  current_function_prototype_arg_types = NULL_TREE;
+  if (TYPE_ARG_TYPES (TREE_TYPE (decl1)) == 0)
+    {
+      if (old_decl != 0 && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE
+	  && comptypes (TREE_TYPE (TREE_TYPE (decl1)),
+			TREE_TYPE (TREE_TYPE (old_decl))))
+	{
+	  TREE_TYPE (decl1) = composite_type (TREE_TYPE (old_decl),
+					      TREE_TYPE (decl1));
+	  current_function_prototype_locus = DECL_SOURCE_LOCATION (old_decl);
+	  current_function_prototype_built_in
+	    = C_DECL_BUILTIN_PROTOTYPE (old_decl);
+	  current_function_prototype_arg_types
+	    = TYPE_ARG_TYPES (TREE_TYPE (decl1));
+	}
+      if (TREE_PUBLIC (decl1))
+	{
+	  /* If there is an external prototype declaration of this
+	     function, record its location but do not copy information
+	     to this decl.  This may be an invisible declaration
+	     (built-in or in a scope which has finished) or simply
+	     have more refined argument types than any declaration
+	     found above.  */
+	  struct c_binding *b;
+	  for (b = I_SYMBOL_BINDING (DECL_NAME (decl1)); b; b = b->shadowed)
+	    if (B_IN_SCOPE (b, external_scope))
+	      break;
+	  if (b)
+	    {
+	      tree ext_decl, ext_type;
+	      ext_decl = b->decl;
+	      ext_type = b->type ? b->type : TREE_TYPE (ext_decl);
+	      if (TREE_CODE (ext_type) == FUNCTION_TYPE
+		  && comptypes (TREE_TYPE (TREE_TYPE (decl1)),
+				TREE_TYPE (ext_type)))
+		{
+		  current_function_prototype_locus
+		    = DECL_SOURCE_LOCATION (ext_decl);
+		  current_function_prototype_built_in
+		    = C_DECL_BUILTIN_PROTOTYPE (ext_decl);
+		  current_function_prototype_arg_types
+		    = TYPE_ARG_TYPES (ext_type);
+		}
+	    }
+	}
     }
 
   /* Optionally warn of old-fashioned def with no previous prototype.  */
@@ -6063,11 +6124,11 @@ store_parm_decls_oldstyle (tree fndecl, 
      set the DECL_ARG_TYPE of each argument according to
      the type previously specified, and report any mismatches.  */
 
-  if (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
+  if (current_function_prototype_arg_types)
     {
       tree type;
       for (parm = DECL_ARGUMENTS (fndecl),
-	     type = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+	     type = current_function_prototype_arg_types;
 	   parm || (type && (TYPE_MAIN_VARIANT (TREE_VALUE (type))
 			     != void_type_node));
 	   parm = TREE_CHAIN (parm), type = TREE_CHAIN (type))
@@ -6075,9 +6136,15 @@ store_parm_decls_oldstyle (tree fndecl, 
 	  if (parm == 0 || type == 0
 	      || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node)
 	    {
-	      error ("number of arguments doesn%'t match prototype");
-	      error ("%Hprototype declaration",
-		     &current_function_prototype_locus);
+	      if (current_function_prototype_built_in)
+		warning (0, "number of arguments doesn%'t match "
+			 "built-in prototype");
+	      else
+		{
+		  error ("number of arguments doesn%'t match prototype");
+		  error ("%Hprototype declaration",
+			 &current_function_prototype_locus);
+		}
 	      break;
 	    }
 	  /* Type for passing arg must be consistent with that
@@ -6104,17 +6171,33 @@ store_parm_decls_oldstyle (tree fndecl, 
 
 		  if (pedantic)
 		    {
-		      pedwarn ("promoted argument %qD "
-			       "doesn%'t match prototype", parm);
-		      pedwarn ("%Hprototype declaration",
-			       &current_function_prototype_locus);
+		      /* ??? Is it possible to get here with a
+			 built-in prototype or will it always have
+			 been diagnosed as conflicting with an
+			 old-style definition and discarded?  */
+		      if (current_function_prototype_built_in)
+			warning (0, "promoted argument %qD "
+				 "doesn%'t match built-in prototype", parm);
+		      else
+			{
+			  pedwarn ("promoted argument %qD "
+				   "doesn%'t match prototype", parm);
+			  pedwarn ("%Hprototype declaration",
+				   &current_function_prototype_locus);
+			}
 		    }
 		}
 	      else
 		{
-		  error ("argument %qD doesn%'t match prototype", parm);
-		  error ("%Hprototype declaration",
-			 &current_function_prototype_locus);
+		  if (current_function_prototype_built_in)
+		    warning (0, "argument %qD doesn%'t match "
+			     "built-in prototype", parm);
+		  else
+		    {
+		      error ("argument %qD doesn%'t match prototype", parm);
+		      error ("%Hprototype declaration",
+			     &current_function_prototype_locus);
+		    }
 		}
 	    }
 	}
diff -rupN GCC.orig/gcc/c-tree.h GCC/gcc/c-tree.h
--- GCC.orig/gcc/c-tree.h	2005-04-20 16:36:09.000000000 +0000
+++ GCC/gcc/c-tree.h	2005-05-02 00:28:58.000000000 +0000
@@ -89,6 +89,11 @@ struct lang_type GTY(())
 #define C_DECL_DECLARED_BUILTIN(EXP)		\
   DECL_LANG_FLAG_3 (FUNCTION_DECL_CHECK (EXP))
 
+/* For FUNCTION_DECLs, evaluates true if the decl is built-in, has a
+   built-in prototype and does not have a non-built-in prototype.  */
+#define C_DECL_BUILTIN_PROTOTYPE(EXP)		\
+  DECL_LANG_FLAG_6 (FUNCTION_DECL_CHECK (EXP))
+
 /* Record whether a decl was declared register.  This is strictly a
    front-end flag, whereas DECL_REGISTER is used for code generation;
    they may differ for structures with volatile fields.  */
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/builtins-30.c GCC/gcc/testsuite/gcc.dg/builtins-30.c
--- GCC.orig/gcc/testsuite/gcc.dg/builtins-30.c	2004-03-24 10:50:44.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/builtins-30.c	2005-05-02 15:48:19.000000000 +0000
@@ -8,13 +8,14 @@ extern double strtod (const char *, char
    specifying too few arguments... */
 double cos ()
 {  /* { dg-warning "shadows a built-in" } */
+  /* { dg-warning "warning: number of arguments doesn't match built-in prototype" "built-in" { target *-*-* } 10 } */
   return strtod ("nan", 0);
 }
 
 /* the right number, but the wrong type, arguments... */
 double sin (foo)
      int foo UNUSED;  /* { dg-warning "shadows a built-in" } */
-{
+{  /* { dg-warning "warning: argument 'foo' doesn't match built-in prototype" } */
   return strtod ("nan", 0);
 }
 
@@ -22,6 +23,7 @@ double sin (foo)
 long double cosl (foo, bar)
      const char *foo UNUSED;  /* { dg-warning "shadows a built-in" } */
      int bar UNUSED;
-{
+{  /* { dg-warning "warning: number of arguments doesn't match built-in prototype" } */
+  /* { dg-warning "warning: argument 'foo' doesn't match built-in prototype" "foo" { target *-*-* } 26 } */
   return strtod ("nan", 0);
 }
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/pr15698-1.c GCC/gcc/testsuite/gcc.dg/pr15698-1.c
--- GCC.orig/gcc/testsuite/gcc.dg/pr15698-1.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/pr15698-1.c	2005-05-02 13:20:54.000000000 +0000
@@ -0,0 +1,23 @@
+/* Test diagnostics for old-style definition not matching prior
+   prototype are present and give correct location for that prototype
+   (bug 15698).  Original test.  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+int	foobar ();
+
+int func (int blah)
+{
+  char *rindex();
+}
+
+int foobar ()
+{
+  return 0;
+}
+
+char *rindex(a, b)
+     register char *a, b;
+{ /* { dg-warning "warning: argument 'a' doesn't match built-in prototype" } */
+  return 0;
+}
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/pr15698-2.c GCC/gcc/testsuite/gcc.dg/pr15698-2.c
--- GCC.orig/gcc/testsuite/gcc.dg/pr15698-2.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/pr15698-2.c	2005-05-02 00:01:47.000000000 +0000
@@ -0,0 +1,9 @@
+/* Test diagnostics for old-style definition not matching prior
+   prototype are present and give correct location for that prototype
+   (bug 15698).  Prototype at inner scope.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+void f() { void g(void); } /* { dg-error "error: prototype declaration" } */
+void g(a) int a; {} /* { dg-error "error: number of arguments doesn't match prototype" } */
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/pr15698-3.c GCC/gcc/testsuite/gcc.dg/pr15698-3.c
--- GCC.orig/gcc/testsuite/gcc.dg/pr15698-3.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/pr15698-3.c	2005-05-02 00:04:11.000000000 +0000
@@ -0,0 +1,11 @@
+/* Test diagnostics for old-style definition not matching prior
+   prototype are present and give correct location for that prototype
+   (bug 15698).  Prototype not last declaration.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+void f();
+void f(int); /* { dg-error "error: prototype declaration" } */
+void f();
+void f(a) long a; {} /* { dg-error "error: argument 'a' doesn't match prototype" } */
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/pr15698-4.c GCC/gcc/testsuite/gcc.dg/pr15698-4.c
--- GCC.orig/gcc/testsuite/gcc.dg/pr15698-4.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/pr15698-4.c	2005-05-02 00:05:25.000000000 +0000
@@ -0,0 +1,9 @@
+/* Test diagnostics for old-style definition not matching prior
+   prototype are present and give correct location for that prototype
+   (bug 15698).  Unprototyped built-in function with user prototype.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+int isnan(void); /* { dg-error "error: prototype declaration" } */
+int isnan(a) int a; {} /* { dg-error "error: number of arguments doesn't match prototype" } */
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/pr15698-5.c GCC/gcc/testsuite/gcc.dg/pr15698-5.c
--- GCC.orig/gcc/testsuite/gcc.dg/pr15698-5.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/pr15698-5.c	2005-05-02 00:05:58.000000000 +0000
@@ -0,0 +1,10 @@
+/* Test diagnostics for old-style definition not matching prior
+   prototype are present and give correct location for that prototype
+   (bug 15698).  Unprototyped built-in function with user prototype at
+   inner scope.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+void f(void) { int isnan(void); } /* { dg-error "error: prototype declaration" } */
+int isnan(a) int a; {} /* { dg-error "error: number of arguments doesn't match prototype" } */
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/pr15698-6.c GCC/gcc/testsuite/gcc.dg/pr15698-6.c
--- GCC.orig/gcc/testsuite/gcc.dg/pr15698-6.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/pr15698-6.c	2005-05-02 13:21:15.000000000 +0000
@@ -0,0 +1,9 @@
+/* Test diagnostics for old-style definition not matching prior
+   prototype are present and give correct location for that prototype
+   (bug 15698).  Prototyped built-in function, wrong number of
+   arguments.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+char *strchr(a) const char *a; { return 0; } /* { dg-warning "warning: number of arguments doesn't match built-in prototype" } */
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/pr15698-7.c GCC/gcc/testsuite/gcc.dg/pr15698-7.c
--- GCC.orig/gcc/testsuite/gcc.dg/pr15698-7.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/pr15698-7.c	2005-05-02 00:11:12.000000000 +0000
@@ -0,0 +1,10 @@
+/* Test diagnostics for old-style definition not matching prior
+   prototype are present and give correct location for that prototype
+   (bug 15698).  Prototyped built-in function, wrong number of
+   arguments, with explicit prototype as well.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+char *strchr(const char *, int); /* { dg-error "error: prototype declaration" } */
+char *strchr(a) const char *a; { return 0; } /* { dg-error "error: number of arguments doesn't match prototype" } */
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/pr15698-8.c GCC/gcc/testsuite/gcc.dg/pr15698-8.c
--- GCC.orig/gcc/testsuite/gcc.dg/pr15698-8.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/pr15698-8.c	2005-05-02 01:29:39.000000000 +0000
@@ -0,0 +1,11 @@
+/* Test diagnostics for old-style definition not matching prior
+   prototype are present and give correct location for that prototype
+   (bug 15698).  Prototype refined at inner scope with only refinement
+   conflicting with definition.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+int f(int (*)[]);
+int g() { int f(int (*)[2]); } /* { dg-error "error: prototype declaration" } */
+int f(a) int (*a)[3]; { return 0; } /* { dg-error "error: argument 'a' doesn't match prototype" } */


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