From: Joseph Myers Date: Mon, 2 May 2005 19:39:04 +0000 (+0100) Subject: re PR c/15698 (no error in presence of broken builtin fn + K&R declaration) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6fb58bba49ae8e0afaf502975e6fa30cbc288ed0;p=gcc.git re PR c/15698 (no error in presence of broken builtin fn + K&R declaration) 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: * 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. From-SVN: r99118 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3d0b8c2bace..4183ec0f5df 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2005-05-02 Joseph S. Myers + + 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 * ggc.h (ggc_alloc_zone_pass_stat): New macro. diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 3578862269f..c8516c7501b 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -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", - ¤t_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", + ¤t_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", - ¤t_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", + ¤t_function_prototype_locus); + } } } else { - error ("argument %qD doesn%'t match prototype", parm); - error ("%Hprototype declaration", - ¤t_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", + ¤t_function_prototype_locus); + } } } } diff --git a/gcc/c-tree.h b/gcc/c-tree.h index c7cbd133065..c22ae8ab8d1 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -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 --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 46c9e1db3ee..d39b39b755b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2005-05-02 Joseph S. Myers + + 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 PR tree-optimization/21294 diff --git a/gcc/testsuite/gcc.dg/builtins-30.c b/gcc/testsuite/gcc.dg/builtins-30.c index 7c700c514dc..d65b8948ee1 100644 --- a/gcc/testsuite/gcc.dg/builtins-30.c +++ b/gcc/testsuite/gcc.dg/builtins-30.c @@ -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 index 00000000000..6b1c4e2ee3f --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr15698-1.c @@ -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 index 00000000000..c0d635aba62 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr15698-2.c @@ -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 */ +/* { 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 index 00000000000..15d998a8c5a --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr15698-3.c @@ -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 */ +/* { 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 index 00000000000..b1554f48b4d --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr15698-4.c @@ -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 */ +/* { 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 index 00000000000..c87e133c5f1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr15698-5.c @@ -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 */ +/* { 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 index 00000000000..bca51f28c7a --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr15698-6.c @@ -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 */ +/* { 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 index 00000000000..b75f8153dec --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr15698-7.c @@ -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 */ +/* { 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 index 00000000000..b9b6595a7fa --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr15698-8.c @@ -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 */ +/* { 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" } */