From: Zack Weinberg Date: Sun, 11 Jan 2004 01:18:58 +0000 (+0000) Subject: c-decl.c (duplicate_decls): Break apart into... X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3c6e6fbf11745d2c583c15a18f53f63cd889d301;p=platform%2Fupstream%2Fgcc.git c-decl.c (duplicate_decls): Break apart into... * c-decl.c (duplicate_decls): Break apart into... (diagnose_arglist_conflict, validate_proto_after_old_defn) (locate_old_defn, diagnose_mismatched_decls, merge_decls): ... these new functions. Restructure for comprehensibility. Remove various archaic special cases. Always report the location of the previous declaration when a diagnostic is issued. (redeclaration_error_message): Fold into diagnose_mismatched_decls. (match_builtin_function_types): Delete unnecessary forward declaration. testsuite: * gcc.dg/Wshadow-1.c, gcc.dg/attr-noinline.c, gcc.dg/decl3.c * gcc.dg/redecl-1.c, gcc.dg/visibility-7.c, gcc.dg/wtr-static-1.c * gcc.dg/noncompile/20020220-1.c, objc.dg/method-1.m: Update dg-error regexps. From-SVN: r75667 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2ac7526..4c0fa09 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,16 @@ 2004-01-10 Zack Weinberg + * c-decl.c (duplicate_decls): Break apart into... + (diagnose_arglist_conflict, validate_proto_after_old_defn) + (locate_old_defn, diagnose_mismatched_decls, merge_decls): + ... these new functions. Restructure for comprehensibility. + Remove various archaic special cases. Always report the + location of the previous declaration when a diagnostic is issued. + (redeclaration_error_message): Fold into diagnose_mismatched_decls. + (match_builtin_function_types): Delete unnecessary forward declaration. + +2004-01-10 Zack Weinberg + * genautomata.c (make_automaton, NDFA_to_DFA): Print progress bars with '.' characters instead of '*'. (build_automaton): Change notes to match. diff --git a/gcc/c-decl.c b/gcc/c-decl.c index b41ed86..639ad22 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -306,9 +306,6 @@ tree static_ctors, static_dtors; static struct c_scope *make_scope (void); static void pop_scope (void); -static tree match_builtin_function_types (tree, tree); -static int duplicate_decls (tree, tree, int, int); -static int redeclaration_error_message (tree, tree); static tree make_label (tree, location_t); static void bind_label (tree, tree, struct c_scope *); static void implicit_decl_warning (tree); @@ -755,12 +752,12 @@ pushtag (tree name, tree type) TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (type)); } -/* Subroutine of duplicate_decls. Allow harmless mismatches in return +/* Subroutine of compare_decls. Allow harmless mismatches in return and argument types provided that the type modes match. This function return a unified type given a suitable match, and 0 otherwise. */ static tree -match_builtin_function_types (tree oldtype, tree newtype) +match_builtin_function_types (tree newtype, tree oldtype) { tree newrettype, oldrettype; tree newargs, oldargs; @@ -795,121 +792,227 @@ match_builtin_function_types (tree oldtype, tree newtype) return build_type_attribute_variant (trytype, TYPE_ATTRIBUTES (oldtype)); } -/* Handle when a new declaration NEWDECL - has the same name as an old one OLDDECL - in the same binding contour. - Prints an error message if appropriate. +/* Subroutine of diagnose_mismathed_decls. Check for function type + mismatch involving an empty arglist vs a nonempty one and give clearer + diagnostics. */ +static void +diagnose_arglist_conflict (tree newdecl, tree olddecl, + tree newtype, tree oldtype) +{ + tree t; - If safely possible, alter OLDDECL to look like NEWDECL, and return 1. - Otherwise, return 0. + if (TREE_CODE (olddecl) != FUNCTION_DECL + || !comptypes (TREE_TYPE (oldtype), TREE_TYPE (newtype), COMPARE_STRICT) + || !((TYPE_ARG_TYPES (oldtype) == 0 && DECL_INITIAL (olddecl) == 0) + || + (TYPE_ARG_TYPES (newtype) == 0 && DECL_INITIAL (newdecl) == 0))) + return; - When DIFFERENT_BINDING_LEVEL is true, NEWDECL is an external declaration, - and OLDDECL is in an outer scope and should thus not be changed. */ + t = TYPE_ARG_TYPES (oldtype); + if (t == 0) + t = TYPE_ARG_TYPES (newtype); + for (; t; t = TREE_CHAIN (t)) + { + tree type = TREE_VALUE (t); -static int -duplicate_decls (tree newdecl, tree olddecl, int different_binding_level, - int different_tu) -{ - int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), - COMPARE_STRICT); - int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL - && DECL_INITIAL (newdecl) != 0); - tree oldtype = TREE_TYPE (olddecl); - tree newtype = TREE_TYPE (newdecl); - int errmsg = 0; + if (TREE_CHAIN (t) == 0 + && TYPE_MAIN_VARIANT (type) != void_type_node) + { + inform ("a parameter list with an ellipsis can't match" + "an empty parameter name list declaration"); + break; + } - if (DECL_P (olddecl)) - { - if (TREE_CODE (newdecl) == FUNCTION_DECL - && TREE_CODE (olddecl) == FUNCTION_DECL - && (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl))) + if (c_type_promotes_to (type) != type) { - if (DECL_DECLARED_INLINE_P (newdecl) - && DECL_UNINLINABLE (newdecl) - && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) - /* Already warned elsewhere. */; - else if (DECL_DECLARED_INLINE_P (olddecl) - && DECL_UNINLINABLE (olddecl) - && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) - /* Already warned. */; - else if (DECL_DECLARED_INLINE_P (newdecl) - && ! DECL_DECLARED_INLINE_P (olddecl) - && DECL_UNINLINABLE (olddecl) - && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) - { - warning ("%Jfunction '%D' redeclared as inline", - newdecl, newdecl); - warning ("%Jprevious declaration of function '%D' " - "with attribute noinline", olddecl, olddecl); - } - else if (DECL_DECLARED_INLINE_P (olddecl) - && DECL_UNINLINABLE (newdecl) - && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) - { - warning ("%Jfunction '%D' redeclared with attribute noinline", - newdecl, newdecl); - warning ("%Jprevious declaration of function '%D' was inline", - olddecl, olddecl); - } + inform ("an argument type that has a default promotion can't match" + "an empty parameter name list declaration"); + break; } + } +} - DECL_ATTRIBUTES (newdecl) - = (*targetm.merge_decl_attributes) (olddecl, newdecl); +/* Another subroutine of diagnose_mismatched_decls. OLDDECL is an + old-style function definition, NEWDECL is a prototype declaration. + Diagnose inconsistencies in the argument list. Returns TRUE if + the prototype is compatible, FALSE if not. */ +static bool +validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype) +{ + tree type, parm; + int nargs; + /* Prototype decl follows defn w/o prototype. */ + + for (parm = TYPE_ACTUAL_ARG_TYPES (oldtype), + type = TYPE_ARG_TYPES (newtype), + nargs = 1; + ; + parm = TREE_CHAIN (parm), type = TREE_CHAIN (type), nargs++) + { + if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node + && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node) + { + /* End of list. */ + warning ("%Jprototype for '%D' follows non-prototype definition", + newdecl, newdecl); + return true; + } + + if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node + || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node) + { + error ("%Jprototype for '%D' with different number of arguments " + "follows non-prototype definition", newdecl, newdecl); + return false; + } + /* Type for passing arg must be consistent + with that declared for the arg. */ + if (! comptypes (TREE_VALUE (parm), TREE_VALUE (type), + COMPARE_STRICT)) + { + error ("%Jprototype for '%D' with incompatible argument %d " + "follows non-prototype definition", newdecl, newdecl, nargs); + return false; + } } +} + +/* Subroutine of diagnose_mismatched_decls. Report the location of DECL, + first in a pair of mismatched declarations, using the diagnostic + function DIAG. */ +static void +locate_old_decl (tree decl, void (*diag)(const char *, ...)) +{ + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl)) + ; + else if (DECL_INITIAL (decl)) + diag (N_("%Jprevious definition of '%D' was here"), decl, decl); + else if (C_DECL_IMPLICIT (decl)) + diag (N_("%Jprevious implicit declaration of '%D' was here"), decl, decl); + else + diag (N_("%Jprevious declaration of '%D' was here"), decl, decl); +} - if (TREE_CODE (newtype) == ERROR_MARK - || TREE_CODE (oldtype) == ERROR_MARK) - types_match = 0; +/* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL. + Returns true if the caller should proceed to merge the two, false + if OLDDECL should simply be discarded. As a side effect, issues + all necessary diagnostics for invalid or poor-style combinations. + If it returns true, writes the types of NEWDECL and OLDDECL to + *NEWTYPEP and *OLDTYPEP - these may have been adjusted from + TREE_TYPE (NEWDECL, OLDDECL) respectively. */ - /* New decl is completely inconsistent with the old one => - tell caller to replace the old one. - This is always an error except in the case of shadowing a builtin. */ +static bool +diagnose_mismatched_decls (tree newdecl, tree olddecl, + tree *newtypep, tree *oldtypep) +{ + tree newtype, oldtype; + bool pedwarned = false; + bool warned = false; + + /* If we have error_mark_node for either decl or type, just discard + the previous decl - we're in an error cascade already. */ + if (olddecl == error_mark_node || newdecl == error_mark_node) + return false; + oldtype = TREE_TYPE (olddecl); + newtype = TREE_TYPE (newdecl); + if (oldtype == error_mark_node || newtype == error_mark_node) + return false; + + /* Two different categories of symbol altogether. This is an error + unless OLDDECL is a builtin. OLDDECL will be discarded in any case. */ if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) { - if (TREE_CODE (olddecl) == FUNCTION_DECL - && DECL_BUILT_IN (olddecl)) + if (TREE_CODE (olddecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl)) { - /* If you declare a built-in or predefined function name as static, - the old definition is overridden, - but optionally warn this was a bad choice of name. */ - if (!TREE_PUBLIC (newdecl)) + error ("%J'%D' redeclared as different kind of symbol", + newdecl, newdecl); + locate_old_decl (olddecl, error); + } + else if (TREE_PUBLIC (newdecl)) + warning ("%Jbuilt-in function '%D' declared as non-function", + newdecl, newdecl); + else if (warn_shadow) + warning ("%Jshadowing built-in function '%D'", + newdecl, newdecl); + return false; + } + + if (!comptypes (oldtype, newtype, COMPARE_STRICT)) + { + if (TREE_CODE (olddecl) == FUNCTION_DECL && DECL_BUILT_IN (olddecl)) + { + /* Accept harmless mismatch in function types. + This is for the ffs and fprintf builtins. */ + tree trytype = match_builtin_function_types (newtype, oldtype); + + if (trytype && comptypes (newtype, trytype, COMPARE_STRICT)) + oldtype = trytype; + else { - if (warn_shadow) - warning ("%Jshadowing built-in function '%D'", - newdecl, newdecl); + /* If types don't match for a built-in, throw away the + built-in. No point in calling locate_old_decl here, it + won't print anything. */ + warning ("%Jconflicting types for built-in function '%D'", + newdecl, newdecl); + return false; } - else - warning ("%Jbuilt-in function '%D' declared as non-function", - newdecl, newdecl); + } + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_SOURCE_LINE (olddecl) == 0) + { + /* A conflicting function declaration for a predeclared + function that isn't actually built in. Objective C uses + these. The new declaration silently overrides everything + but the volatility (i.e. noreturn) indication. See also + below. FIXME: Make Objective C use normal builtins. */ + TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); + return false; + } + /* Permit void foo (...) to match int foo (...) if the latter is + the definition and implicit int was used. See + c-torture/compile/920625-2.c. */ + else if (TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) + && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == void_type_node + && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node + && C_FUNCTION_IMPLICIT_INT (newdecl)) + { + pedwarn ("%Jconflicting types for '%D'", newdecl, newdecl); + /* Make sure we keep void as the return type. */ + TREE_TYPE (newdecl) = newtype = oldtype; + C_FUNCTION_IMPLICIT_INT (newdecl) = 0; + pedwarned = true; } else { - error ("%J'%D' redeclared as different kind of symbol", - newdecl, newdecl); - error ("%Jprevious declaration of '%D'", olddecl, olddecl); + error ("%Jconflicting types for '%D'", newdecl, newdecl); + diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype); + locate_old_decl (olddecl, error); + return false; } - - return 0; } - /* For real parm decl following a forward decl, return 1 so old decl - will be reused. Only allow this to happen once. */ - if (types_match && TREE_CODE (newdecl) == PARM_DECL - && TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl)) + /* Redeclaration of a type is a constraint violation (6.7.2.3p1), + but silently ignore the redeclaration if either is in a system + header. (Conflicting redeclarations were handled above.) */ + if (TREE_CODE (newdecl) == TYPE_DECL) { - TREE_ASM_WRITTEN (olddecl) = 0; - return 1; + if (DECL_IN_SYSTEM_HEADER (newdecl) || DECL_IN_SYSTEM_HEADER (olddecl)) + return true; /* allow OLDDECL to continue in use */ + + error ("%Jredefinition of typedef '%D'", newdecl, newdecl); + locate_old_decl (olddecl, error); + return false; } - /* The new declaration is the same kind of object as the old one. - The declarations may partially match. Print warnings if they don't - match enough. Ultimately, copy most of the information from the new - decl to the old one, and keep using the old one. */ - - if (TREE_CODE (olddecl) == FUNCTION_DECL && DECL_BUILT_IN (olddecl)) + /* Function declarations can either be 'static' or 'extern' (no + qualifier is equivalent to 'extern' - C99 6.2.2p5) and therefore + can never conflict with each other on account of linkage (6.2.2p4). + Multiple definitions are not allowed (6.9p3,5) but GCC permits + two definitions if one is 'extern inline' and one is not. The non- + extern-inline definition supersedes the extern-inline definition. */ + else if (TREE_CODE (newdecl) == FUNCTION_DECL) { - /* A function declaration for a built-in function. */ - if (!TREE_PUBLIC (newdecl)) + if (DECL_BUILT_IN (olddecl) && !TREE_PUBLIC (newdecl)) { /* If you declare a built-in function name as static, the built-in definition is overridden, @@ -917,458 +1020,355 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level, if (warn_shadow) warning ("%Jshadowing built-in function '%D'", newdecl, newdecl); /* Discard the old built-in function. */ - return 0; + return false; } - if (!types_match) + + if (DECL_INITIAL (newdecl)) { - /* Accept harmless mismatch in function types. - This is for the ffs and fprintf builtins. */ - tree trytype = match_builtin_function_types (oldtype, newtype); - - if (trytype) + if (DECL_INITIAL (olddecl) + && !(DECL_DECLARED_INLINE_P (olddecl) + && DECL_EXTERNAL (olddecl) + && !(DECL_DECLARED_INLINE_P (newdecl) + && DECL_EXTERNAL (newdecl)))) { - types_match = comptypes (newtype, trytype, COMPARE_STRICT); - if (types_match) - oldtype = trytype; - if (! different_binding_level) - TREE_TYPE (olddecl) = oldtype; + error ("%Jredefinition of '%D'", newdecl, newdecl); + locate_old_decl (olddecl, error); + return false; } } - if (!types_match) + /* If we have a prototype after an old-style function definition, + the argument types must be checked specially. */ + else if (DECL_INITIAL (olddecl) + && !TYPE_ARG_TYPES (oldtype) && TYPE_ARG_TYPES (newtype) + && TYPE_ACTUAL_ARG_TYPES (oldtype) + && !validate_proto_after_old_defn (newdecl, newtype, oldtype)) { - /* If types don't match for a built-in, throw away the built-in. */ - warning ("%Jconflicting types for built-in function '%D'", - newdecl, newdecl); - return 0; + locate_old_decl (olddecl, error); + return false; + } + /* Mismatched non-static and static is considered poor style. + We only diagnose static then non-static if -Wtraditional, + because it is the most convenient way to get some effects + (see e.g. what unwind-dw2-fde-glibc.c does to the definition + of _Unwind_Find_FDE in unwind-dw2-fde.c). Revisit? */ + if (TREE_PUBLIC (olddecl) && !TREE_PUBLIC (newdecl)) + { + /* A static function declaration for a predeclared function + that isn't actually built in, silently overrides the + default. Objective C uses these. See also above. + FIXME: Make Objective C use normal builtins. */ + if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_SOURCE_LINE (olddecl) == 0) + return false; + else + { + warning ("%Jstatic declaration of '%D' follows " + "non-static declaration", newdecl, newdecl); + warned = true; + } + } + else if (TREE_PUBLIC (newdecl) && !TREE_PUBLIC (olddecl) + && warn_traditional) + { + warning ("%Jnon-static declaration of '%D' follows " + "static declaration", newdecl, newdecl); + warned = true; } } - else if (TREE_CODE (olddecl) == FUNCTION_DECL - && DECL_SOURCE_LINE (olddecl) == 0) + else if (TREE_CODE (newdecl) == VAR_DECL) { - /* A function declaration for a predeclared function - that isn't actually built in. */ - if (!TREE_PUBLIC (newdecl)) + /* Only variables can be thread-local, and all declarations must + agree on this property. */ + if (DECL_THREAD_LOCAL (newdecl) != DECL_THREAD_LOCAL (olddecl)) { - /* If you declare it as static, the - default definition is overridden. */ - return 0; + if (DECL_THREAD_LOCAL (newdecl)) + error ("%Jthread-local declaration of '%D' follows " + "non-thread-local declaration", newdecl, newdecl); + else + error ("%Jnon-thread-local declaration of '%D' follows " + "thread-local declaration", newdecl, newdecl); + + locate_old_decl (olddecl, error); + return false; } - else if (!types_match) + + /* Multiple initialized definitions are not allowed (6.9p3,5). */ + if (DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl)) { - /* If the types don't match, preserve volatility indication. - Later on, we will discard everything else about the - default declaration. */ - TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); + error ("%Jredefinition of '%D'", newdecl, newdecl); + locate_old_decl (olddecl, error); + return false; } - } - /* Permit char *foo () to match void *foo (...) if not pedantic, - if one of them came from a system header file. */ - else if (!types_match - && TREE_CODE (olddecl) == FUNCTION_DECL - && TREE_CODE (newdecl) == FUNCTION_DECL - && TREE_CODE (TREE_TYPE (oldtype)) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (newtype)) == POINTER_TYPE - && (DECL_IN_SYSTEM_HEADER (olddecl) - || DECL_IN_SYSTEM_HEADER (newdecl)) - && ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (newtype))) == void_type_node - && TYPE_ARG_TYPES (oldtype) == 0 - && self_promoting_args_p (TYPE_ARG_TYPES (newtype)) - && TREE_TYPE (TREE_TYPE (oldtype)) == char_type_node) - || - (TREE_TYPE (TREE_TYPE (newtype)) == char_type_node - && TYPE_ARG_TYPES (newtype) == 0 - && self_promoting_args_p (TYPE_ARG_TYPES (oldtype)) - && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (oldtype))) == void_type_node))) - { - if (pedantic) - pedwarn ("%Jconflicting types for '%D'", newdecl, newdecl); - /* Make sure we keep void * as ret type, not char *. */ - if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (oldtype))) == void_type_node) - TREE_TYPE (newdecl) = newtype = oldtype; - - /* Set DECL_IN_SYSTEM_HEADER, so that if we see another declaration - we will come back here again. */ - DECL_IN_SYSTEM_HEADER (newdecl) = 1; - } - /* Permit void foo (...) to match int foo (...) if the latter is the - definition and implicit int was used. See c-torture/compile/920625-2.c. */ - else if (!types_match && new_is_definition - && TREE_CODE (olddecl) == FUNCTION_DECL - && TREE_CODE (newdecl) == FUNCTION_DECL - && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == void_type_node - && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node - && C_FUNCTION_IMPLICIT_INT (newdecl)) - { - pedwarn ("%Jconflicting types for '%D'", newdecl, newdecl); - /* Make sure we keep void as the return type. */ - TREE_TYPE (newdecl) = newtype = oldtype; - C_FUNCTION_IMPLICIT_INT (newdecl) = 0; - } - else if (!types_match - /* Permit char *foo (int, ...); followed by char *foo (); - if not pedantic. */ - && ! (TREE_CODE (olddecl) == FUNCTION_DECL - && ! pedantic - /* Return types must still match. */ - && comptypes (TREE_TYPE (oldtype), - TREE_TYPE (newtype), COMPARE_STRICT) - && TYPE_ARG_TYPES (newtype) == 0)) - { - error ("%Jconflicting types for '%D'", newdecl, newdecl); - /* Check for function type mismatch - involving an empty arglist vs a nonempty one. */ - if (TREE_CODE (olddecl) == FUNCTION_DECL - && comptypes (TREE_TYPE (oldtype), - TREE_TYPE (newtype), COMPARE_STRICT) - && ((TYPE_ARG_TYPES (oldtype) == 0 - && DECL_INITIAL (olddecl) == 0) - || - (TYPE_ARG_TYPES (newtype) == 0 - && DECL_INITIAL (newdecl) == 0))) + + /* Objects declared at file scope: if at least one is 'extern', + it's fine (6.2.2p4); otherwise the linkage must agree (6.2.2p7). */ + if (DECL_FILE_SCOPE_P (newdecl)) { - /* Classify the problem further. */ - tree t = TYPE_ARG_TYPES (oldtype); - if (t == 0) - t = TYPE_ARG_TYPES (newtype); - for (; t; t = TREE_CHAIN (t)) + if (!DECL_EXTERNAL (newdecl) + && !DECL_EXTERNAL (olddecl) + && TREE_PUBLIC (newdecl) != TREE_PUBLIC (olddecl)) { - tree type = TREE_VALUE (t); - - if (TREE_CHAIN (t) == 0 - && TYPE_MAIN_VARIANT (type) != void_type_node) - { - error ("a parameter list with an ellipsis can't match an empty parameter name list declaration"); - break; - } + if (TREE_PUBLIC (newdecl)) + error ("%Jnon-static declaration of '%D' follows " + "static declaration", newdecl, newdecl); + else + error ("%Jstatic declaration of '%D' follows " + "non-static declaration", newdecl, newdecl); - if (c_type_promotes_to (type) != type) - { - error ("an argument type that has a default promotion can't match an empty parameter name list declaration"); - break; - } + locate_old_decl (olddecl, error); + return false; } } - if (C_DECL_IMPLICIT (olddecl)) - error ("%Jprevious implicit declaration of '%D'", olddecl, olddecl); - else - error ("%Jprevious declaration of '%D'", olddecl, olddecl); + /* Two objects with the same name declared at the same block + scope must both be external references (6.7p3). */ + else if (DECL_CONTEXT (newdecl) == DECL_CONTEXT (olddecl) + && (!DECL_EXTERNAL (newdecl) || !DECL_EXTERNAL (olddecl))) + { + if (DECL_EXTERNAL (newdecl)) + error ("%Jextern declaration of '%D' follows " + "declaration with no linkage", newdecl, newdecl); + else if (DECL_EXTERNAL (olddecl)) + error ("%Jdeclaration of '%D' with no linkage follows " + "extern declaration", newdecl, newdecl); + else + error ("%Jredeclaration of '%D' with no linkage", + newdecl, newdecl); - /* This is safer because the initializer might contain references - to variables that were declared between olddecl and newdecl. This - will make the initializer invalid for olddecl in case it gets - assigned to olddecl below. */ - if (TREE_CODE (newdecl) == VAR_DECL) - DECL_INITIAL (newdecl) = 0; - } - /* TLS cannot follow non-TLS declaration. */ - else if (TREE_CODE (olddecl) == VAR_DECL && TREE_CODE (newdecl) == VAR_DECL - && !DECL_THREAD_LOCAL (olddecl) && DECL_THREAD_LOCAL (newdecl)) - { - error ("%Jthread-local declaration of '%D' follows non thread-local " - "declaration", newdecl, newdecl); - error ("%Jprevious declaration of '%D'", olddecl, olddecl); + locate_old_decl (olddecl, error); + return false; + } } - /* non-TLS declaration cannot follow TLS declaration. */ - else if (TREE_CODE (olddecl) == VAR_DECL && TREE_CODE (newdecl) == VAR_DECL - && DECL_THREAD_LOCAL (olddecl) && !DECL_THREAD_LOCAL (newdecl)) + + /* warnings */ + /* All decls must agree on a non-default visibility. */ + if (DECL_VISIBILITY (newdecl) != VISIBILITY_DEFAULT + && DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT + && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl)) { - error ("%Jnon thread-local declaration of '%D' follows " - "thread-local declaration", newdecl, newdecl); - error ("%Jprevious declaration of '%D'", olddecl, olddecl); + warning ("%Jredeclaration of '%D' with different visibility " + "(old visibility preserved)", newdecl, newdecl); + warned = true; } - else + + if (TREE_CODE (newdecl) == FUNCTION_DECL) { - errmsg = redeclaration_error_message (newdecl, olddecl); - if (errmsg) + /* Diagnose inline __attribute__ ((noinline)) which is silly. */ + if (DECL_DECLARED_INLINE_P (newdecl) + && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) { - switch (errmsg) - { - case 1: - error ("%Jredefinition of '%D'", newdecl, newdecl); - break; - case 2: - error ("%Jredeclaration of '%D'", newdecl, newdecl); - break; - case 3: - error ("%Jconflicting declarations of '%D'", newdecl, newdecl); - break; - default: - abort (); - } - - if (DECL_INITIAL (olddecl) - && current_scope == global_scope) - error ("%J'%D' previously defined here", olddecl, olddecl); - else - error ("%J'%D' previously declared here", olddecl, olddecl); - return 0; + warning ("%Jinline declaration of '%D' follows " + "declaration with attribute noinline", newdecl, newdecl); + warned = true; } - else if (TREE_CODE (newdecl) == TYPE_DECL - && (DECL_IN_SYSTEM_HEADER (olddecl) - || DECL_IN_SYSTEM_HEADER (newdecl))) + else if (DECL_DECLARED_INLINE_P (olddecl) + && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) { - warning ("%Jredefinition of '%D'", newdecl, newdecl); - if (DECL_INITIAL (olddecl) && current_scope == global_scope) - warning ("%J'%D' previously defined here", olddecl, olddecl); - else - warning ("%J'%D' previously declared here", olddecl, olddecl); + warning ("%Jdeclaration of '%D' with attribute noinline follows " + "inline declaration ", newdecl, newdecl); + warned = true; } - else if (TREE_CODE (olddecl) == FUNCTION_DECL - && DECL_INITIAL (olddecl) != 0 - && TYPE_ARG_TYPES (oldtype) == 0 - && TYPE_ARG_TYPES (newtype) != 0 - && TYPE_ACTUAL_ARG_TYPES (oldtype) != 0) + + /* Inline declaration after use or definition. + ??? Should we still warn about this now we have unit-at-a-time + mode and can get it right? */ + if (DECL_DECLARED_INLINE_P (newdecl) && !DECL_DECLARED_INLINE_P (olddecl)) { - tree type, parm; - int nargs; - /* Prototype decl follows defn w/o prototype. */ - - for (parm = TYPE_ACTUAL_ARG_TYPES (oldtype), - type = TYPE_ARG_TYPES (newtype), - nargs = 1; - ; - parm = TREE_CHAIN (parm), type = TREE_CHAIN (type), nargs++) + if (TREE_USED (olddecl)) { - if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node - && TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node) - { - warning ("%Jprototype for '%D' follows", newdecl, newdecl); - warning ("%Jnon-prototype definition here", olddecl); - break; - } - if (TYPE_MAIN_VARIANT (TREE_VALUE (parm)) == void_type_node - || TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node) - { - error ("%Jprototype for '%D' follows and number of " - "arguments doesn't match", newdecl, newdecl); - error ("%Jnon-prototype definition here", olddecl); - errmsg = 1; - break; - } - /* Type for passing arg must be consistent - with that declared for the arg. */ - if (! comptypes (TREE_VALUE (parm), TREE_VALUE (type), - COMPARE_STRICT)) - { - error ("%Jprototype for '%D' follows and argument %d " - "doesn't match", newdecl, newdecl, nargs); - error ("%Jnon-prototype definition here", olddecl); - errmsg = 1; - break; - } + warning ("%J'%D' declared inline after being called"); + warned = true; + } + else if (DECL_INITIAL (olddecl)) + { + warning ("%J'%D' declared inline after its definition"); + warned = true; } } - /* Warn about mismatches in various flags. */ - else + } + else /* VAR_DECL */ + { + /* These bits are only type qualifiers when applied to objects. */ + if (TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl)) { - /* Warn if function is now inline - but was previously declared not inline and has been called. */ - if (TREE_CODE (olddecl) == FUNCTION_DECL - && ! DECL_DECLARED_INLINE_P (olddecl) - && DECL_DECLARED_INLINE_P (newdecl) - && TREE_USED (olddecl)) - warning ("%J'%D' declared inline after being called", - newdecl, newdecl); - if (TREE_CODE (olddecl) == FUNCTION_DECL - && ! DECL_DECLARED_INLINE_P (olddecl) - && DECL_DECLARED_INLINE_P (newdecl) - && DECL_INITIAL (olddecl) != 0) - warning ("%J'%D' declared inline after its definition", - newdecl, newdecl); - - /* If pedantic, warn when static declaration follows a non-static - declaration. Otherwise, do so only for functions. */ - if ((pedantic || TREE_CODE (olddecl) == FUNCTION_DECL) - && TREE_PUBLIC (olddecl) - && !TREE_PUBLIC (newdecl)) - warning ("%Jstatic declaration for '%D' follows non-static", - newdecl, newdecl); - - /* If warn_traditional, warn when a non-static function - declaration follows a static one. */ - if (warn_traditional && !in_system_header - && TREE_CODE (olddecl) == FUNCTION_DECL - && !TREE_PUBLIC (olddecl) - && TREE_PUBLIC (newdecl)) - warning ("%Jnon-static declaration for '%D' follows static", - newdecl, newdecl); - - /* Warn when const declaration follows a non-const - declaration, but not for functions. */ - if (TREE_CODE (olddecl) != FUNCTION_DECL - && !TREE_READONLY (olddecl) - && TREE_READONLY (newdecl)) - warning ("%Jconst declaration for '%D' follows non-const", - newdecl, newdecl); - /* These bits are logically part of the type, for variables. - But not for functions - (where qualifiers are not valid ANSI anyway). */ - else if (pedantic && TREE_CODE (olddecl) != FUNCTION_DECL - && (TREE_READONLY (newdecl) != TREE_READONLY (olddecl) - || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl))) - pedwarn ("%Jtype qualifiers for '%D' conflict with previous " - "declaration", newdecl, newdecl); + if (TREE_THIS_VOLATILE (newdecl)) + pedwarn ("%Jvolatile declaration of '%D' follows " + "non-volatile declaration", newdecl, newdecl); + else + pedwarn ("%Jnon-volatile declaration of '%D' follows " + "volatile declaration", newdecl, newdecl); + pedwarned = true; + } + if (TREE_READONLY (newdecl) != TREE_READONLY (olddecl)) + { + if (TREE_READONLY (newdecl)) + pedwarn ("%Jconst declaration of '%D' follows " + "non-const declaration", newdecl, newdecl); + else + pedwarn ("%Jnon-const declaration of '%D' follows " + "const declaration", newdecl, newdecl); + pedwarned = true; } } - /* Optionally warn about more than one declaration for the same name. */ - if (errmsg == 0 && warn_redundant_decls && DECL_SOURCE_LINE (olddecl) != 0 - /* Don't warn about a function declaration - followed by a definition. */ - && !(TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) != 0 - && DECL_INITIAL (olddecl) == 0) - /* Don't warn about extern decl followed by (tentative) definition. */ - && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl))) + /* Optional warning for completely redundant decls. */ + if (!warned && !pedwarned + && warn_redundant_decls + /* Don't warn about a function declaration followed by a + definition. */ + && !(TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl)) + /* Don't warn about an extern followed by a definition. */ + && !(DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl))) { - warning ("%Jredundant redeclaration of '%D' in same scope", - newdecl, newdecl); - warning ("%Jprevious declaration of '%D'", olddecl, olddecl); + warning ("%Jredundant redeclaration of '%D'", newdecl, newdecl); + warned = true; } - /* Copy all the DECL_... slots specified in the new decl - except for any that we copy here from the old type. + /* Report location of previous decl/defn in a consistent manner. */ + if (warned || pedwarned) + locate_old_decl (olddecl, pedwarned ? pedwarn : warning); + + *newtypep = newtype; + *oldtypep = oldtype; + return true; +} - Past this point, we don't change OLDTYPE and NEWTYPE - even if we change the types of NEWDECL and OLDDECL. */ +/* Subroutine of duplicate_decls. NEWDECL has been found to be + consistent with OLDDECL, but carries new information. Merge the + new information into OLDDECL. If DIFFERENT_BINDING_LEVEL or + DIFFERENT_TU is true, avoid completely merging the decls, as this + will break assumptions elsewhere. This function issues no + diagnostics. */ - if (types_match) +static void +merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype, + bool different_binding_level, bool different_tu) +{ + int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_INITIAL (newdecl) != 0); + + /* When copying info to olddecl, we store into write_olddecl + instead. This allows us to avoid modifying olddecl when + different_binding_level is true. */ + tree write_olddecl = different_binding_level ? newdecl : olddecl; + + /* For real parm decl following a forward decl, return 1 so old decl + will be reused. Only allow this to happen once. */ + if (TREE_CODE (newdecl) == PARM_DECL + && TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl)) { - /* When copying info to olddecl, we store into write_olddecl - instead. This allows us to avoid modifying olddecl when - different_binding_level is true. */ - tree write_olddecl = different_binding_level ? newdecl : olddecl; + TREE_ASM_WRITTEN (olddecl) = 0; + return; + } + + DECL_ATTRIBUTES (newdecl) + = (*targetm.merge_decl_attributes) (olddecl, newdecl); - /* Merge the data types specified in the two decls. */ - if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl)) + /* Merge the data types specified in the two decls. */ + if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl)) + { + if (different_binding_level) { - if (different_binding_level) - { - if (TYPE_ARG_TYPES (oldtype) != 0 - && TYPE_ARG_TYPES (newtype) == 0) - TREE_TYPE (newdecl) = common_type (newtype, oldtype); - else - TREE_TYPE (newdecl) - = build_type_attribute_variant - (newtype, - merge_attributes (TYPE_ATTRIBUTES (newtype), - TYPE_ATTRIBUTES (oldtype))); - } + if (TYPE_ARG_TYPES (oldtype) != 0 + && TYPE_ARG_TYPES (newtype) == 0) + TREE_TYPE (newdecl) = common_type (newtype, oldtype); else TREE_TYPE (newdecl) - = TREE_TYPE (olddecl) - = common_type (newtype, oldtype); - } - - /* Lay the type out, unless already done. */ - if (oldtype != TREE_TYPE (newdecl)) - { - if (TREE_TYPE (newdecl) != error_mark_node) - layout_type (TREE_TYPE (newdecl)); - if (TREE_CODE (newdecl) != FUNCTION_DECL - && TREE_CODE (newdecl) != TYPE_DECL - && TREE_CODE (newdecl) != CONST_DECL) - layout_decl (newdecl, 0); + = build_type_attribute_variant + (newtype, + merge_attributes (TYPE_ATTRIBUTES (newtype), + TYPE_ATTRIBUTES (oldtype))); } else - { - /* Since the type is OLDDECL's, make OLDDECL's size go with. */ - DECL_SIZE (newdecl) = DECL_SIZE (olddecl); - DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl); - DECL_MODE (newdecl) = DECL_MODE (olddecl); - if (TREE_CODE (olddecl) != FUNCTION_DECL) - if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) - { - DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl); - DECL_USER_ALIGN (newdecl) |= DECL_ALIGN (olddecl); - } - } + TREE_TYPE (newdecl) + = TREE_TYPE (olddecl) + = common_type (newtype, oldtype); + } - /* Keep the old rtl since we can safely use it. */ - COPY_DECL_RTL (olddecl, newdecl); + /* Lay the type out, unless already done. */ + if (oldtype != TREE_TYPE (newdecl)) + { + if (TREE_TYPE (newdecl) != error_mark_node) + layout_type (TREE_TYPE (newdecl)); + if (TREE_CODE (newdecl) != FUNCTION_DECL + && TREE_CODE (newdecl) != TYPE_DECL + && TREE_CODE (newdecl) != CONST_DECL) + layout_decl (newdecl, 0); + } + else + { + /* Since the type is OLDDECL's, make OLDDECL's size go with. */ + DECL_SIZE (newdecl) = DECL_SIZE (olddecl); + DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl); + DECL_MODE (newdecl) = DECL_MODE (olddecl); + if (TREE_CODE (olddecl) != FUNCTION_DECL) + if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) + { + DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl); + DECL_USER_ALIGN (newdecl) |= DECL_ALIGN (olddecl); + } + } - /* Merge the type qualifiers. */ - if (TREE_READONLY (newdecl)) - TREE_READONLY (write_olddecl) = 1; + /* Keep the old rtl since we can safely use it. */ + COPY_DECL_RTL (olddecl, newdecl); - if (TREE_THIS_VOLATILE (newdecl)) - { - TREE_THIS_VOLATILE (write_olddecl) = 1; - if (TREE_CODE (newdecl) == VAR_DECL - /* If an automatic variable is re-declared in the same - function scope, but the old declaration was not - volatile, make_var_volatile() would crash because the - variable would have been assigned to a pseudo, not a - MEM. Since this duplicate declaration is invalid - anyway, we just skip the call. */ - && errmsg == 0) - make_var_volatile (newdecl); - } + /* Merge the type qualifiers. */ + if (TREE_READONLY (newdecl)) + TREE_READONLY (write_olddecl) = 1; - /* Keep source location of definition rather than declaration. */ - /* When called with different_binding_level set, keep the old - information so that meaningful diagnostics can be given. */ - if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0 - && ! different_binding_level) - DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl); - - /* Merge the unused-warning information. */ - if (DECL_IN_SYSTEM_HEADER (olddecl)) - DECL_IN_SYSTEM_HEADER (newdecl) = 1; - else if (DECL_IN_SYSTEM_HEADER (newdecl)) - DECL_IN_SYSTEM_HEADER (write_olddecl) = 1; - - /* Merge the initialization information. */ - /* When called with different_binding_level set, don't copy over - DECL_INITIAL, so that we don't accidentally change function - declarations into function definitions. */ - if (DECL_INITIAL (newdecl) == 0 && ! different_binding_level) - DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); - - /* Merge the section attribute. - We want to issue an error if the sections conflict but that must be - done later in decl_attributes since we are called before attributes - are assigned. */ - if (DECL_SECTION_NAME (newdecl) == NULL_TREE) - DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl); - - /* Copy the assembler name. - Currently, it can only be defined in the prototype. */ - COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl); - - /* If either declaration has a nondefault visibility, use it. */ - if (DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT) - { - if (DECL_VISIBILITY (newdecl) != VISIBILITY_DEFAULT - && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl)) - { - warning ("%J'%D': visibility attribute ignored because it", - newdecl, newdecl); - warning ("%Jconflicts with previous declaration here", olddecl); - } - DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl); - } + if (TREE_THIS_VOLATILE (newdecl)) + { + TREE_THIS_VOLATILE (write_olddecl) = 1; + if (TREE_CODE (newdecl) == VAR_DECL) + make_var_volatile (newdecl); + } + + /* Keep source location of definition rather than declaration. */ + /* When called with different_binding_level set, keep the old + information so that meaningful diagnostics can be given. */ + if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0 + && ! different_binding_level) + DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl); + + /* Merge the unused-warning information. */ + if (DECL_IN_SYSTEM_HEADER (olddecl)) + DECL_IN_SYSTEM_HEADER (newdecl) = 1; + else if (DECL_IN_SYSTEM_HEADER (newdecl)) + DECL_IN_SYSTEM_HEADER (write_olddecl) = 1; + + /* Merge the initialization information. */ + /* When called with different_binding_level set, don't copy over + DECL_INITIAL, so that we don't accidentally change function + declarations into function definitions. */ + if (DECL_INITIAL (newdecl) == 0 && ! different_binding_level) + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); + + /* Merge the section attribute. + We want to issue an error if the sections conflict but that must be + done later in decl_attributes since we are called before attributes + are assigned. */ + if (DECL_SECTION_NAME (newdecl) == NULL_TREE) + DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl); + + /* Copy the assembler name. + Currently, it can only be defined in the prototype. */ + COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl); + + /* If either declaration has a nondefault visibility, use it. */ + if (DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT) + DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl); - if (TREE_CODE (newdecl) == FUNCTION_DECL) - { - DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl); - DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); - DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl); - DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl) - |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl); - TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); - TREE_READONLY (newdecl) |= TREE_READONLY (olddecl); - DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl); - DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl); - } - } - /* If cannot merge, then use the new type and qualifiers, - and don't preserve the old rtl. */ - else if (! different_binding_level) + if (TREE_CODE (newdecl) == FUNCTION_DECL) { - TREE_TYPE (olddecl) = TREE_TYPE (newdecl); - TREE_READONLY (olddecl) = TREE_READONLY (newdecl); - TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl); - TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl); + DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl); + DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); + DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl); + DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl) + |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl); + TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); + TREE_READONLY (newdecl) |= TREE_READONLY (olddecl); + DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl); + DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl); } /* Merge the storage class information. */ @@ -1448,9 +1448,9 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level, if (DECL_BUILT_IN (olddecl)) { - /* Get rid of any built-in function if new arg types don't match it - or if we have a function definition. */ - if (! types_match || new_is_definition) + /* Get rid of any built-in function if we have a function + definition. */ + if (new_is_definition) { if (! different_binding_level) { @@ -1502,7 +1502,7 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level, } } if (different_binding_level) - return 0; + return; /* Copy most of the decl-specific fields of NEWDECL into OLDDECL. But preserve OLDDECL's DECL_UID. */ @@ -1515,10 +1515,6 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level, DECL_UID (olddecl) = olddecl_uid; } - /* NEWDECL contains the merged attribute lists. - Update OLDDECL to be the same. */ - DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl); - /* If OLDDECL had its DECL_RTL instantiated, re-invoke make_decl_rtl so that encode_section_info has a chance to look at the new decl flags and attributes. */ @@ -1527,10 +1523,34 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level, || (TREE_CODE (olddecl) == VAR_DECL && TREE_STATIC (olddecl)))) make_decl_rtl (olddecl, NULL); - - return 1; } +/* Handle when a new declaration NEWDECL has the same name as an old + one OLDDECL in the same binding contour. Prints an error message + if appropriate. + + If safely possible, alter OLDDECL to look like NEWDECL, and return + true. Otherwise, return false. + + When DIFFERENT_BINDING_LEVEL is true, NEWDECL is an external + declaration, and OLDDECL is in an outer scope and should thus not + be changed. */ + +static bool +duplicate_decls (tree newdecl, tree olddecl, + bool different_binding_level, bool different_tu) +{ + tree newtype, oldtype; + + if (!diagnose_mismatched_decls (newdecl, olddecl, &newtype, &oldtype)) + return false; + + merge_decls (newdecl, olddecl, newtype, oldtype, + different_binding_level, different_tu); + return !different_binding_level; +} + + /* Return any external DECL associated with ID, whether or not it is currently in scope. */ @@ -1890,69 +1910,6 @@ implicit_decl_warning (tree id) warning ("implicit declaration of function `%s'", name); } -/* Return zero if the declaration NEWDECL is valid - when the declaration OLDDECL (assumed to be for the same name) - has already been seen. - Otherwise return 1 if NEWDECL is a redefinition, 2 if it is a redeclaration, - and 3 if it is a conflicting declaration. */ - -static int -redeclaration_error_message (tree newdecl, tree olddecl) -{ - if (TREE_CODE (newdecl) == TYPE_DECL) - { - /* Do not complain about type redeclarations where at least one - declaration was in a system header. */ - if (DECL_IN_SYSTEM_HEADER (olddecl) || DECL_IN_SYSTEM_HEADER (newdecl)) - return 0; - return 1; - } - else if (TREE_CODE (newdecl) == FUNCTION_DECL) - { - /* Declarations of functions can insist on internal linkage - but they can't be inconsistent with internal linkage, - so there can be no error on that account. - However defining the same name twice is no good. */ - if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0 - /* However, defining once as extern inline and a second - time in another way is ok. */ - && ! (DECL_DECLARED_INLINE_P (olddecl) && DECL_EXTERNAL (olddecl) - && ! (DECL_DECLARED_INLINE_P (newdecl) - && DECL_EXTERNAL (newdecl)))) - return 1; - return 0; - } - else if (DECL_FILE_SCOPE_P (newdecl)) - { - /* Objects declared at file scope: */ - /* If at least one is a reference, it's ok. */ - if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl)) - return 0; - /* Reject two definitions. */ - if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0) - return 1; - /* Now we have two tentative defs, or one tentative and one real def. */ - /* Insist that the linkage match. */ - if (TREE_PUBLIC (olddecl) != TREE_PUBLIC (newdecl)) - return 3; - return 0; - } - else if (current_scope->parm_flag - && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl)) - return 0; - else - { - /* Newdecl has block scope. If olddecl has block scope also, then - reject two definitions, and reject a definition together with an - external reference. Otherwise, it is OK, because newdecl must - be an extern reference to olddecl. */ - if (!(DECL_EXTERNAL (newdecl) && DECL_EXTERNAL (olddecl)) - && DECL_CONTEXT (newdecl) == DECL_CONTEXT (olddecl)) - return 2; - return 0; - } -} - /* Issue an error message for a reference to an undeclared variable ID, including a reference to a builtin outside of function-call context. Establish a binding of the identifier to error_mark_node diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ac1ae07..2d7b506 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,12 @@ 2004-01-10 Zack Weinberg + * gcc.dg/Wshadow-1.c, gcc.dg/attr-noinline.c, gcc.dg/decl3.c + * gcc.dg/redecl-1.c, gcc.dg/visibility-7.c, gcc.dg/wtr-static-1.c + * gcc.dg/noncompile/20020220-1.c, objc.dg/method-1.m: + Update dg-error regexps. + +2004-01-10 Zack Weinberg + * gcc.c-torture/compile/20021123-2.c: Delete; dup of 20021120-1.c. * gcc.c-torture/compile/20021123-3.c: Delete; dup of 20021120-2.c. diff --git a/gcc/testsuite/gcc.dg/Wshadow-1.c b/gcc/testsuite/gcc.dg/Wshadow-1.c index c9c3acb..c4553a4 100644 --- a/gcc/testsuite/gcc.dg/Wshadow-1.c +++ b/gcc/testsuite/gcc.dg/Wshadow-1.c @@ -10,7 +10,7 @@ void foo (double decl1) /* { dg-warning "shadows a global decl" } */ { } -void foo1 (int d) /* { dg-warning "previous declaration" } */ +void foo1 (int d) /* { dg-warning "previous definition" } */ { double d; /* { dg-bogus "warning" "warning in place of error" } */ /* { dg-error "redeclared as different" "" { target *-*-* } 15 } */ diff --git a/gcc/testsuite/gcc.dg/attr-noinline.c b/gcc/testsuite/gcc.dg/attr-noinline.c index ee48eb9..9124e4f 100644 --- a/gcc/testsuite/gcc.dg/attr-noinline.c +++ b/gcc/testsuite/gcc.dg/attr-noinline.c @@ -13,33 +13,33 @@ static inline void __attribute__((__noinline__)) function_declaration_both_after static void function_declaration_both_after(void) {} -static void function_declaration_noinline_before(void) __attribute__((__noinline__)); /* { dg-warning "previous declaration \[^\n\]* with attribute noinline" "" } */ +static void function_declaration_noinline_before(void) __attribute__((__noinline__)); /* { dg-warning "previous declaration" "" } */ -static inline void function_declaration_noinline_before(void) {} /* { dg-warning "function \[^\n\]* redeclared as inline" "" } */ +static inline void function_declaration_noinline_before(void) {} /* { dg-warning "follows declaration with attribute noinline" "" } */ -static inline void function_declaration_noinline_after(void) {} /* { dg-warning "previous declaration \[^\n\]* was inline" "" } */ +static inline void function_declaration_noinline_after(void) {} /* { dg-warning "previous definition" "" } */ -static void function_declaration_noinline_after(void) __attribute__((__noinline__)); /* { dg-warning "function \[^\n\]* redeclared with attribute noinline" "" } */ +static void function_declaration_noinline_after(void) __attribute__((__noinline__)); /* { dg-warning "follows inline declaration" "" } */ -static inline void function_declaration_inline_before(void); /* { dg-warning "previous declaration \[^\n\]* was inline" "" } */ +static inline void function_declaration_inline_before(void); /* { dg-warning "previous declaration" "" } */ -static void __attribute__((__noinline__)) function_declaration_inline_before(void) {} /* { dg-warning "function \[^\n\]* redeclared with attribute noinline" "" } */ +static void __attribute__((__noinline__)) function_declaration_inline_before(void) {} /* { dg-warning "follows inline declaration" "" } */ -static inline void function_declaration_inline_noinline_before(void); /* { dg-warning "previous declaration \[^\n\]* was inline" "" } */ +static inline void function_declaration_inline_noinline_before(void); /* { dg-warning "previous declaration" "" } */ -static void function_declaration_inline_noinline_before(void) __attribute__((__noinline__)); /* { dg-warning "function \[^\n\]* redeclared with attribute noinline" "" } */ +static void function_declaration_inline_noinline_before(void) __attribute__((__noinline__)); /* { dg-warning "follows inline declaration" "" } */ static void function_declaration_inline_noinline_before(void) {} static inline void function_declaration_inline_noinline_after(void); -static void function_declaration_inline_noinline_after(void) {} /* { dg-warning "previous declaration \[^\n\]* was inline" "" } */ +static void function_declaration_inline_noinline_after(void) {} /* { dg-warning "previous definition" "" } */ -static void function_declaration_inline_noinline_after(void) __attribute__((__noinline__)); /* { dg-warning "function \[^\n\]* redeclared with attribute noinline" "" } */ +static void function_declaration_inline_noinline_after(void) __attribute__((__noinline__)); /* { dg-warning "follows inline declaration" "" } */ -static void function_declaration_noinline_inline_before(void) __attribute__((__noinline__)); /* { dg-warning "previous declaration\[^\n\]* with attribute noinline" "" } */ +static void function_declaration_noinline_inline_before(void) __attribute__((__noinline__)); /* { dg-warning "previous declaration" "" } */ -static inline void function_declaration_noinline_inline_before(void); /* { dg-warning "function \[^\n\]* redeclared as inline" "" } */ +static inline void function_declaration_noinline_inline_before(void); /* { dg-warning "follows declaration with attribute noinline" "" } */ static void function_declaration_noinline_inline_before(void) {} diff --git a/gcc/testsuite/gcc.dg/decl-3.c b/gcc/testsuite/gcc.dg/decl-3.c index b8d00d0..2bfac89 100644 --- a/gcc/testsuite/gcc.dg/decl-3.c +++ b/gcc/testsuite/gcc.dg/decl-3.c @@ -1,5 +1,5 @@ /* PR c/9928 */ /* { dg-do compile } */ -enum { CODES }; /* { dg-error "previous declaration" } */ +enum { CODES }; /* { dg-error "previous definition" } */ enum { CODES }; /* { dg-error "conflicting types" } */ diff --git a/gcc/testsuite/gcc.dg/noncompile/20020213-1.c b/gcc/testsuite/gcc.dg/noncompile/20020213-1.c index 77798b5..079daf0 100644 --- a/gcc/testsuite/gcc.dg/noncompile/20020213-1.c +++ b/gcc/testsuite/gcc.dg/noncompile/20020213-1.c @@ -24,7 +24,6 @@ int main () return 0; } -/* { dg-warning "passing arg 2 of" "2nd incompatible" { target *-*-* } 15 } */ /* { dg-warning "passing arg 1 of" "1st incompatible" { target *-*-* } 16 } */ /* { dg-warning "passing arg 2 of" "2nd incompatible" { target *-*-* } 16 } */ /* { dg-warning "passing arg 1 of" "1st incompatible" { target *-*-* } 18 } */ diff --git a/gcc/testsuite/gcc.dg/noncompile/20020220-1.c b/gcc/testsuite/gcc.dg/noncompile/20020220-1.c index c455f7e..aa57dc3 100644 --- a/gcc/testsuite/gcc.dg/noncompile/20020220-1.c +++ b/gcc/testsuite/gcc.dg/noncompile/20020220-1.c @@ -6,7 +6,7 @@ int foo (const char*, const char*); void bar (void) { const char *s = "bar"; - int i; /* { dg-error "previously declared here" } */ + int i; /* { dg-error "previous declaration" } */ int size = 2; int i = foo (s, s + size); /* { dg-error "redeclaration of" } */ } diff --git a/gcc/testsuite/gcc.dg/redecl-1.c b/gcc/testsuite/gcc.dg/redecl-1.c index d2355ba..09b70d7 100644 --- a/gcc/testsuite/gcc.dg/redecl-1.c +++ b/gcc/testsuite/gcc.dg/redecl-1.c @@ -74,7 +74,7 @@ void test5(void) /* Extern then static, both at file scope. */ -extern int test6(int); /* { dg-warning "previous" "" { xfail *-*-* } } */ +extern int test6(int); /* { dg-warning "previous" "" } */ static int test6(int x) { return x; } /* { dg-warning "follows non-static" } */ @@ -83,7 +83,7 @@ static int test6(int x) void prime7(void) { - extern int test7(int); /* { dg-warning "previous" "" { xfail *-*-* } } */ + extern int test7(int); /* { dg-warning "previous" "" } */ } static int test7(int x) @@ -93,7 +93,7 @@ static int test7(int x) void prime8(void) { - test8(); /* { dg-warning "previous" "" { xfail *-*-* } } */ + test8(); /* { dg-warning "previous" "" } */ /* { dg-warning "implicit" "" { target *-*-* } 96 } */ } diff --git a/gcc/testsuite/gcc.dg/visibility-7.c b/gcc/testsuite/gcc.dg/visibility-7.c index e98b432..5bdc2b0 100644 --- a/gcc/testsuite/gcc.dg/visibility-7.c +++ b/gcc/testsuite/gcc.dg/visibility-7.c @@ -5,8 +5,8 @@ extern int __attribute__((visibility ("hidden"))) -xyzzy; /* { dg-warning "previous declaration here" "" } */ +xyzzy; /* { dg-warning "previous declaration" "" } */ int __attribute__((visibility ("protected"))) -xyzzy = 5; /* { dg-warning "visibility attribute ignored" "" } */ +xyzzy = 5; /* { dg-warning "different visibility" "" } */ diff --git a/gcc/testsuite/gcc.dg/wtr-static-1.c b/gcc/testsuite/gcc.dg/wtr-static-1.c index 310c1ea..42760e8 100644 --- a/gcc/testsuite/gcc.dg/wtr-static-1.c +++ b/gcc/testsuite/gcc.dg/wtr-static-1.c @@ -4,7 +4,7 @@ /* { dg-do compile } */ /* { dg-options "-Wtraditional" } */ -static void testfunc1(void); +static void testfunc1(void); /* { dg-warning "previous declaration" } */ void testfunc1() {} /* { dg-warning "non-static.*follows static" "non-static follows static" } */ # 11 "sys-header.h" 3 diff --git a/gcc/testsuite/objc.dg/method-1.m b/gcc/testsuite/objc.dg/method-1.m index 391ee62..a73a0f4 100644 --- a/gcc/testsuite/objc.dg/method-1.m +++ b/gcc/testsuite/objc.dg/method-1.m @@ -16,9 +16,8 @@ @end @implementation class3 -- (int) meth1 { return 0; } +- (int) meth1 { return 0; } /* { dg-error "previous definition" } */ - (int) meth1 { return 0; } /* { dg-error "redefinition of" } */ -/* { dg-error "previously defined here" "" { target *-*-* } 19 } */ @end @interface class4 @@ -26,7 +25,6 @@ @end @implementation class4 -+ (void) meth1 {} ++ (void) meth1 {} /* { dg-error "previous definition" } */ + (void) meth1 {} /* { dg-error "redefinition of" } */ -/* { dg-error "previously defined here" "" { target *-*-* } 29 } */ @end