OSDN Git Service

PR c/15698
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 2 May 2005 19:39:04 +0000 (19:39 +0000)
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 2 May 2005 19:39:04 +0000 (19:39 +0000)
* 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:
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@99118 138bc75d-0d04-0410-961f-82ee72b054a4

13 files changed:
gcc/ChangeLog
gcc/c-decl.c
gcc/c-tree.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-30.c
gcc/testsuite/gcc.dg/pr15698-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr15698-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr15698-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr15698-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr15698-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr15698-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr15698-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr15698-8.c [new file with mode: 0644]

index 3d0b8c2..4183ec0 100644 (file)
@@ -1,3 +1,22 @@
+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).
+
 2005-05-02  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * ggc.h (ggc_alloc_zone_pass_stat): New macro.
index 3578862..c8516c7 100644 (file)
@@ -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, tree newtype, tree oldtype)
 {
   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, tree newtype, tree oldtype)
   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, tree newtype, tree oldtype)
          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 type, int function_code,
   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 *declspecs, struct c_declarator *declarator,
   /* 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, const struct c_arg_info *arg_info)
      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, const struct c_arg_info *arg_info)
          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, const struct c_arg_info *arg_info)
 
                  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);
+                   }
                }
            }
        }
index c7cbd13..c22ae8a 100644 (file)
@@ -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.  */
index 46c9e1d..d39b39b 100644 (file)
@@ -1,3 +1,11 @@
+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.
+
 2005-05-02  Kazu Hirata  <kazu@cs.umass.edu>
 
        PR tree-optimization/21294
index 7c700c5..d65b894 100644 (file)
@@ -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 --git a/gcc/testsuite/gcc.dg/pr15698-1.c b/gcc/testsuite/gcc.dg/pr15698-1.c
new file mode 100644 (file)
index 0000000..6b1c4e2
--- /dev/null
@@ -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 --git a/gcc/testsuite/gcc.dg/pr15698-2.c b/gcc/testsuite/gcc.dg/pr15698-2.c
new file mode 100644 (file)
index 0000000..c0d635a
--- /dev/null
@@ -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 --git a/gcc/testsuite/gcc.dg/pr15698-3.c b/gcc/testsuite/gcc.dg/pr15698-3.c
new file mode 100644 (file)
index 0000000..15d998a
--- /dev/null
@@ -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 --git a/gcc/testsuite/gcc.dg/pr15698-4.c b/gcc/testsuite/gcc.dg/pr15698-4.c
new file mode 100644 (file)
index 0000000..b1554f4
--- /dev/null
@@ -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 --git a/gcc/testsuite/gcc.dg/pr15698-5.c b/gcc/testsuite/gcc.dg/pr15698-5.c
new file mode 100644 (file)
index 0000000..c87e133
--- /dev/null
@@ -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 --git a/gcc/testsuite/gcc.dg/pr15698-6.c b/gcc/testsuite/gcc.dg/pr15698-6.c
new file mode 100644 (file)
index 0000000..bca51f2
--- /dev/null
@@ -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 --git a/gcc/testsuite/gcc.dg/pr15698-7.c b/gcc/testsuite/gcc.dg/pr15698-7.c
new file mode 100644 (file)
index 0000000..b75f815
--- /dev/null
@@ -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 --git a/gcc/testsuite/gcc.dg/pr15698-8.c b/gcc/testsuite/gcc.dg/pr15698-8.c
new file mode 100644 (file)
index 0000000..b9b6595
--- /dev/null
@@ -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" } */