Commit 3c6e6fbf by Zack Weinberg Committed by Zack Weinberg

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
parent 1e8dcb41
2004-01-10 Zack Weinberg <zack@codesourcery.com> 2004-01-10 Zack Weinberg <zack@codesourcery.com>
* 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 <zack@codesourcery.com>
* genautomata.c (make_automaton, NDFA_to_DFA): * genautomata.c (make_automaton, NDFA_to_DFA):
Print progress bars with '.' characters instead of '*'. Print progress bars with '.' characters instead of '*'.
(build_automaton): Change notes to match. (build_automaton): Change notes to match.
......
...@@ -306,9 +306,6 @@ tree static_ctors, static_dtors; ...@@ -306,9 +306,6 @@ tree static_ctors, static_dtors;
static struct c_scope *make_scope (void); static struct c_scope *make_scope (void);
static void pop_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 tree make_label (tree, location_t);
static void bind_label (tree, tree, struct c_scope *); static void bind_label (tree, tree, struct c_scope *);
static void implicit_decl_warning (tree); static void implicit_decl_warning (tree);
...@@ -755,12 +752,12 @@ pushtag (tree name, tree type) ...@@ -755,12 +752,12 @@ pushtag (tree name, tree type)
TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (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 and argument types provided that the type modes match. This function
return a unified type given a suitable match, and 0 otherwise. */ return a unified type given a suitable match, and 0 otherwise. */
static tree static tree
match_builtin_function_types (tree oldtype, tree newtype) match_builtin_function_types (tree newtype, tree oldtype)
{ {
tree newrettype, oldrettype; tree newrettype, oldrettype;
tree newargs, oldargs; tree newargs, oldargs;
...@@ -795,121 +792,227 @@ match_builtin_function_types (tree oldtype, tree newtype) ...@@ -795,121 +792,227 @@ match_builtin_function_types (tree oldtype, tree newtype)
return build_type_attribute_variant (trytype, TYPE_ATTRIBUTES (oldtype)); return build_type_attribute_variant (trytype, TYPE_ATTRIBUTES (oldtype));
} }
/* Handle when a new declaration NEWDECL /* Subroutine of diagnose_mismathed_decls. Check for function type
has the same name as an old one OLDDECL mismatch involving an empty arglist vs a nonempty one and give clearer
in the same binding contour. diagnostics. */
Prints an error message if appropriate. 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. if (TREE_CODE (olddecl) != FUNCTION_DECL
Otherwise, return 0. || !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, t = TYPE_ARG_TYPES (oldtype);
and OLDDECL is in an outer scope and should thus not be changed. */ if (t == 0)
t = TYPE_ARG_TYPES (newtype);
for (; t; t = TREE_CHAIN (t))
{
tree type = TREE_VALUE (t);
static int if (TREE_CHAIN (t) == 0
duplicate_decls (tree newdecl, tree olddecl, int different_binding_level, && TYPE_MAIN_VARIANT (type) != void_type_node)
int different_tu) {
{ inform ("a parameter list with an ellipsis can't match"
int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), "an empty parameter name list declaration");
COMPARE_STRICT); break;
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 (DECL_P (olddecl)) if (c_type_promotes_to (type) != type)
{
if (TREE_CODE (newdecl) == FUNCTION_DECL
&& TREE_CODE (olddecl) == FUNCTION_DECL
&& (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl)))
{ {
if (DECL_DECLARED_INLINE_P (newdecl) inform ("an argument type that has a default promotion can't match"
&& DECL_UNINLINABLE (newdecl) "an empty parameter name list declaration");
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) break;
/* 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);
}
} }
}
}
DECL_ATTRIBUTES (newdecl) /* Another subroutine of diagnose_mismatched_decls. OLDDECL is an
= (*targetm.merge_decl_attributes) (olddecl, newdecl); 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 /* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL.
|| TREE_CODE (oldtype) == ERROR_MARK) Returns true if the caller should proceed to merge the two, false
types_match = 0; 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 => static bool
tell caller to replace the old one. diagnose_mismatched_decls (tree newdecl, tree olddecl,
This is always an error except in the case of shadowing a builtin. */ 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) != TREE_CODE (newdecl))
{ {
if (TREE_CODE (olddecl) == FUNCTION_DECL if (TREE_CODE (olddecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
&& DECL_BUILT_IN (olddecl))
{ {
/* If you declare a built-in or predefined function name as static, error ("%J'%D' redeclared as different kind of symbol",
the old definition is overridden, newdecl, newdecl);
but optionally warn this was a bad choice of name. */ locate_old_decl (olddecl, error);
if (!TREE_PUBLIC (newdecl)) }
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) /* If types don't match for a built-in, throw away the
warning ("%Jshadowing built-in function '%D'", built-in. No point in calling locate_old_decl here, it
newdecl, newdecl); 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", else if (TREE_CODE (olddecl) == FUNCTION_DECL
newdecl, newdecl); && 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 else
{ {
error ("%J'%D' redeclared as different kind of symbol", error ("%Jconflicting types for '%D'", newdecl, newdecl);
newdecl, newdecl); diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype);
error ("%Jprevious declaration of '%D'", olddecl, olddecl); locate_old_decl (olddecl, error);
return false;
} }
return 0;
} }
/* For real parm decl following a forward decl, return 1 so old decl /* Redeclaration of a type is a constraint violation (6.7.2.3p1),
will be reused. Only allow this to happen once. */ but silently ignore the redeclaration if either is in a system
if (types_match && TREE_CODE (newdecl) == PARM_DECL header. (Conflicting redeclarations were handled above.) */
&& TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl)) if (TREE_CODE (newdecl) == TYPE_DECL)
{ {
TREE_ASM_WRITTEN (olddecl) = 0; if (DECL_IN_SYSTEM_HEADER (newdecl) || DECL_IN_SYSTEM_HEADER (olddecl))
return 1; 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. /* Function declarations can either be 'static' or 'extern' (no
The declarations may partially match. Print warnings if they don't qualifier is equivalent to 'extern' - C99 6.2.2p5) and therefore
match enough. Ultimately, copy most of the information from the new can never conflict with each other on account of linkage (6.2.2p4).
decl to the old one, and keep using the old one. */ Multiple definitions are not allowed (6.9p3,5) but GCC permits
two definitions if one is 'extern inline' and one is not. The non-
if (TREE_CODE (olddecl) == FUNCTION_DECL && DECL_BUILT_IN (olddecl)) extern-inline definition supersedes the extern-inline definition. */
else if (TREE_CODE (newdecl) == FUNCTION_DECL)
{ {
/* A function declaration for a built-in function. */ if (DECL_BUILT_IN (olddecl) && !TREE_PUBLIC (newdecl))
if (!TREE_PUBLIC (newdecl))
{ {
/* If you declare a built-in function name as static, the /* If you declare a built-in function name as static, the
built-in definition is overridden, built-in definition is overridden,
...@@ -917,458 +1020,355 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level, ...@@ -917,458 +1020,355 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level,
if (warn_shadow) if (warn_shadow)
warning ("%Jshadowing built-in function '%D'", newdecl, newdecl); warning ("%Jshadowing built-in function '%D'", newdecl, newdecl);
/* Discard the old built-in function. */ /* Discard the old built-in function. */
return 0; return false;
} }
if (!types_match)
if (DECL_INITIAL (newdecl))
{ {
/* Accept harmless mismatch in function types. if (DECL_INITIAL (olddecl)
This is for the ffs and fprintf builtins. */ && !(DECL_DECLARED_INLINE_P (olddecl)
tree trytype = match_builtin_function_types (oldtype, newtype); && DECL_EXTERNAL (olddecl)
&& !(DECL_DECLARED_INLINE_P (newdecl)
if (trytype) && DECL_EXTERNAL (newdecl))))
{ {
types_match = comptypes (newtype, trytype, COMPARE_STRICT); error ("%Jredefinition of '%D'", newdecl, newdecl);
if (types_match) locate_old_decl (olddecl, error);
oldtype = trytype; return false;
if (! different_binding_level)
TREE_TYPE (olddecl) = oldtype;
} }
} }
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. */ locate_old_decl (olddecl, error);
warning ("%Jconflicting types for built-in function '%D'", return false;
newdecl, newdecl); }
return 0; /* 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 else if (TREE_CODE (newdecl) == VAR_DECL)
&& DECL_SOURCE_LINE (olddecl) == 0)
{ {
/* A function declaration for a predeclared function /* Only variables can be thread-local, and all declarations must
that isn't actually built in. */ agree on this property. */
if (!TREE_PUBLIC (newdecl)) if (DECL_THREAD_LOCAL (newdecl) != DECL_THREAD_LOCAL (olddecl))
{ {
/* If you declare it as static, the if (DECL_THREAD_LOCAL (newdecl))
default definition is overridden. */ error ("%Jthread-local declaration of '%D' follows "
return 0; "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. error ("%Jredefinition of '%D'", newdecl, newdecl);
Later on, we will discard everything else about the locate_old_decl (olddecl, error);
default declaration. */ return false;
TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
} }
}
/* Permit char *foo () to match void *foo (...) if not pedantic, /* Objects declared at file scope: if at least one is 'extern',
if one of them came from a system header file. */ it's fine (6.2.2p4); otherwise the linkage must agree (6.2.2p7). */
else if (!types_match if (DECL_FILE_SCOPE_P (newdecl))
&& 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)))
{ {
/* Classify the problem further. */ if (!DECL_EXTERNAL (newdecl)
tree t = TYPE_ARG_TYPES (oldtype); && !DECL_EXTERNAL (olddecl)
if (t == 0) && TREE_PUBLIC (newdecl) != TREE_PUBLIC (olddecl))
t = TYPE_ARG_TYPES (newtype);
for (; t; t = TREE_CHAIN (t))
{ {
tree type = TREE_VALUE (t); if (TREE_PUBLIC (newdecl))
error ("%Jnon-static declaration of '%D' follows "
if (TREE_CHAIN (t) == 0 "static declaration", newdecl, newdecl);
&& TYPE_MAIN_VARIANT (type) != void_type_node) else
{ error ("%Jstatic declaration of '%D' follows "
error ("a parameter list with an ellipsis can't match an empty parameter name list declaration"); "non-static declaration", newdecl, newdecl);
break;
}
if (c_type_promotes_to (type) != type) locate_old_decl (olddecl, error);
{ return false;
error ("an argument type that has a default promotion can't match an empty parameter name list declaration");
break;
}
} }
} }
if (C_DECL_IMPLICIT (olddecl)) /* Two objects with the same name declared at the same block
error ("%Jprevious implicit declaration of '%D'", olddecl, olddecl); scope must both be external references (6.7p3). */
else else if (DECL_CONTEXT (newdecl) == DECL_CONTEXT (olddecl)
error ("%Jprevious declaration of '%D'", olddecl, 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 locate_old_decl (olddecl, error);
to variables that were declared between olddecl and newdecl. This return false;
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);
} }
/* non-TLS declaration cannot follow TLS declaration. */
else if (TREE_CODE (olddecl) == VAR_DECL && TREE_CODE (newdecl) == VAR_DECL /* warnings */
&& DECL_THREAD_LOCAL (olddecl) && !DECL_THREAD_LOCAL (newdecl)) /* 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 " warning ("%Jredeclaration of '%D' with different visibility "
"thread-local declaration", newdecl, newdecl); "(old visibility preserved)", newdecl, newdecl);
error ("%Jprevious declaration of '%D'", olddecl, olddecl); warned = true;
} }
else
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{ {
errmsg = redeclaration_error_message (newdecl, olddecl); /* Diagnose inline __attribute__ ((noinline)) which is silly. */
if (errmsg) if (DECL_DECLARED_INLINE_P (newdecl)
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
{ {
switch (errmsg) warning ("%Jinline declaration of '%D' follows "
{ "declaration with attribute noinline", newdecl, newdecl);
case 1: warned = true;
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;
} }
else if (TREE_CODE (newdecl) == TYPE_DECL else if (DECL_DECLARED_INLINE_P (olddecl)
&& (DECL_IN_SYSTEM_HEADER (olddecl) && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
|| DECL_IN_SYSTEM_HEADER (newdecl)))
{ {
warning ("%Jredefinition of '%D'", newdecl, newdecl); warning ("%Jdeclaration of '%D' with attribute noinline follows "
if (DECL_INITIAL (olddecl) && current_scope == global_scope) "inline declaration ", newdecl, newdecl);
warning ("%J'%D' previously defined here", olddecl, olddecl); warned = true;
else
warning ("%J'%D' previously declared here", olddecl, olddecl);
} }
else if (TREE_CODE (olddecl) == FUNCTION_DECL
&& DECL_INITIAL (olddecl) != 0 /* Inline declaration after use or definition.
&& TYPE_ARG_TYPES (oldtype) == 0 ??? Should we still warn about this now we have unit-at-a-time
&& TYPE_ARG_TYPES (newtype) != 0 mode and can get it right? */
&& TYPE_ACTUAL_ARG_TYPES (oldtype) != 0) if (DECL_DECLARED_INLINE_P (newdecl) && !DECL_DECLARED_INLINE_P (olddecl))
{ {
tree type, parm; if (TREE_USED (olddecl))
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 warning ("%J'%D' declared inline after being called");
&& TYPE_MAIN_VARIANT (TREE_VALUE (type)) == void_type_node) warned = true;
{ }
warning ("%Jprototype for '%D' follows", newdecl, newdecl); else if (DECL_INITIAL (olddecl))
warning ("%Jnon-prototype definition here", olddecl); {
break; warning ("%J'%D' declared inline after its definition");
} warned = true;
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;
}
} }
} }
/* 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 if (TREE_THIS_VOLATILE (newdecl))
but was previously declared not inline and has been called. */ pedwarn ("%Jvolatile declaration of '%D' follows "
if (TREE_CODE (olddecl) == FUNCTION_DECL "non-volatile declaration", newdecl, newdecl);
&& ! DECL_DECLARED_INLINE_P (olddecl) else
&& DECL_DECLARED_INLINE_P (newdecl) pedwarn ("%Jnon-volatile declaration of '%D' follows "
&& TREE_USED (olddecl)) "volatile declaration", newdecl, newdecl);
warning ("%J'%D' declared inline after being called", pedwarned = true;
newdecl, newdecl); }
if (TREE_CODE (olddecl) == FUNCTION_DECL if (TREE_READONLY (newdecl) != TREE_READONLY (olddecl))
&& ! DECL_DECLARED_INLINE_P (olddecl) {
&& DECL_DECLARED_INLINE_P (newdecl) if (TREE_READONLY (newdecl))
&& DECL_INITIAL (olddecl) != 0) pedwarn ("%Jconst declaration of '%D' follows "
warning ("%J'%D' declared inline after its definition", "non-const declaration", newdecl, newdecl);
newdecl, newdecl); else
pedwarn ("%Jnon-const declaration of '%D' follows "
/* If pedantic, warn when static declaration follows a non-static "const declaration", newdecl, newdecl);
declaration. Otherwise, do so only for functions. */ pedwarned = true;
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);
} }
} }
/* Optionally warn about more than one declaration for the same name. */ /* Optional warning for completely redundant decls. */
if (errmsg == 0 && warn_redundant_decls && DECL_SOURCE_LINE (olddecl) != 0 if (!warned && !pedwarned
/* Don't warn about a function declaration && warn_redundant_decls
followed by a definition. */ /* Don't warn about a function declaration followed by a
&& !(TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) != 0 definition. */
&& DECL_INITIAL (olddecl) == 0) && !(TREE_CODE (newdecl) == FUNCTION_DECL
/* Don't warn about extern decl followed by (tentative) definition. */ && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl))
&& !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl))) /* Don't warn about an extern followed by a definition. */
&& !(DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl)))
{ {
warning ("%Jredundant redeclaration of '%D' in same scope", warning ("%Jredundant redeclaration of '%D'", newdecl, newdecl);
newdecl, newdecl); warned = true;
warning ("%Jprevious declaration of '%D'", olddecl, olddecl);
} }
/* Copy all the DECL_... slots specified in the new decl /* Report location of previous decl/defn in a consistent manner. */
except for any that we copy here from the old type. 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 /* Subroutine of duplicate_decls. NEWDECL has been found to be
even if we change the types of NEWDECL and OLDDECL. */ 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 TREE_ASM_WRITTEN (olddecl) = 0;
instead. This allows us to avoid modifying olddecl when return;
different_binding_level is true. */ }
tree write_olddecl = different_binding_level ? newdecl : olddecl;
DECL_ATTRIBUTES (newdecl)
= (*targetm.merge_decl_attributes) (olddecl, newdecl);
/* Merge the data types specified in the two decls. */ /* Merge the data types specified in the two decls. */
if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl)) 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)
if (TYPE_ARG_TYPES (oldtype) != 0 TREE_TYPE (newdecl) = common_type (newtype, oldtype);
&& 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)));
}
else else
TREE_TYPE (newdecl) TREE_TYPE (newdecl)
= TREE_TYPE (olddecl) = build_type_attribute_variant
= common_type (newtype, oldtype); (newtype,
} merge_attributes (TYPE_ATTRIBUTES (newtype),
TYPE_ATTRIBUTES (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);
} }
else else
{ TREE_TYPE (newdecl)
/* Since the type is OLDDECL's, make OLDDECL's size go with. */ = TREE_TYPE (olddecl)
DECL_SIZE (newdecl) = DECL_SIZE (olddecl); = common_type (newtype, oldtype);
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);
}
}
/* Keep the old rtl since we can safely use it. */ /* Lay the type out, unless already done. */
COPY_DECL_RTL (olddecl, newdecl); 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. */ /* Keep the old rtl since we can safely use it. */
if (TREE_READONLY (newdecl)) COPY_DECL_RTL (olddecl, newdecl);
TREE_READONLY (write_olddecl) = 1;
if (TREE_THIS_VOLATILE (newdecl)) /* Merge the type qualifiers. */
{ if (TREE_READONLY (newdecl))
TREE_THIS_VOLATILE (write_olddecl) = 1; TREE_READONLY (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);
}
/* Keep source location of definition rather than declaration. */ if (TREE_THIS_VOLATILE (newdecl))
/* When called with different_binding_level set, keep the old {
information so that meaningful diagnostics can be given. */ TREE_THIS_VOLATILE (write_olddecl) = 1;
if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0 if (TREE_CODE (newdecl) == VAR_DECL)
&& ! different_binding_level) make_var_volatile (newdecl);
DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl); }
/* Merge the unused-warning information. */ /* Keep source location of definition rather than declaration. */
if (DECL_IN_SYSTEM_HEADER (olddecl)) /* When called with different_binding_level set, keep the old
DECL_IN_SYSTEM_HEADER (newdecl) = 1; information so that meaningful diagnostics can be given. */
else if (DECL_IN_SYSTEM_HEADER (newdecl)) if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0
DECL_IN_SYSTEM_HEADER (write_olddecl) = 1; && ! different_binding_level)
DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl);
/* Merge the initialization information. */
/* When called with different_binding_level set, don't copy over /* Merge the unused-warning information. */
DECL_INITIAL, so that we don't accidentally change function if (DECL_IN_SYSTEM_HEADER (olddecl))
declarations into function definitions. */ DECL_IN_SYSTEM_HEADER (newdecl) = 1;
if (DECL_INITIAL (newdecl) == 0 && ! different_binding_level) else if (DECL_IN_SYSTEM_HEADER (newdecl))
DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); DECL_IN_SYSTEM_HEADER (write_olddecl) = 1;
/* Merge the section attribute. /* Merge the initialization information. */
We want to issue an error if the sections conflict but that must be /* When called with different_binding_level set, don't copy over
done later in decl_attributes since we are called before attributes DECL_INITIAL, so that we don't accidentally change function
are assigned. */ declarations into function definitions. */
if (DECL_SECTION_NAME (newdecl) == NULL_TREE) if (DECL_INITIAL (newdecl) == 0 && ! different_binding_level)
DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl); DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
/* Copy the assembler name. /* Merge the section attribute.
Currently, it can only be defined in the prototype. */ We want to issue an error if the sections conflict but that must be
COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl); done later in decl_attributes since we are called before attributes
are assigned. */
/* If either declaration has a nondefault visibility, use it. */ if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
if (DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT) DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
{
if (DECL_VISIBILITY (newdecl) != VISIBILITY_DEFAULT /* Copy the assembler name.
&& DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl)) Currently, it can only be defined in the prototype. */
{ COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
warning ("%J'%D': visibility attribute ignored because it",
newdecl, newdecl); /* If either declaration has a nondefault visibility, use it. */
warning ("%Jconflicts with previous declaration here", olddecl); if (DECL_VISIBILITY (olddecl) != VISIBILITY_DEFAULT)
} DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl);
DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl);
}
if (TREE_CODE (newdecl) == FUNCTION_DECL) 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)
{ {
TREE_TYPE (olddecl) = TREE_TYPE (newdecl); DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl);
TREE_READONLY (olddecl) = TREE_READONLY (newdecl); DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl); DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl); 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. */ /* Merge the storage class information. */
...@@ -1448,9 +1448,9 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level, ...@@ -1448,9 +1448,9 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level,
if (DECL_BUILT_IN (olddecl)) if (DECL_BUILT_IN (olddecl))
{ {
/* Get rid of any built-in function if new arg types don't match it /* Get rid of any built-in function if we have a function
or if we have a function definition. */ definition. */
if (! types_match || new_is_definition) if (new_is_definition)
{ {
if (! different_binding_level) if (! different_binding_level)
{ {
...@@ -1502,7 +1502,7 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level, ...@@ -1502,7 +1502,7 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level,
} }
} }
if (different_binding_level) if (different_binding_level)
return 0; return;
/* Copy most of the decl-specific fields of NEWDECL into OLDDECL. /* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
But preserve OLDDECL's DECL_UID. */ But preserve OLDDECL's DECL_UID. */
...@@ -1515,10 +1515,6 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level, ...@@ -1515,10 +1515,6 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level,
DECL_UID (olddecl) = olddecl_uid; 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 /* 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 so that encode_section_info has a chance to look at the new decl
flags and attributes. */ flags and attributes. */
...@@ -1527,10 +1523,34 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level, ...@@ -1527,10 +1523,34 @@ duplicate_decls (tree newdecl, tree olddecl, int different_binding_level,
|| (TREE_CODE (olddecl) == VAR_DECL || (TREE_CODE (olddecl) == VAR_DECL
&& TREE_STATIC (olddecl)))) && TREE_STATIC (olddecl))))
make_decl_rtl (olddecl, NULL); 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 /* Return any external DECL associated with ID, whether or not it is
currently in scope. */ currently in scope. */
...@@ -1890,69 +1910,6 @@ implicit_decl_warning (tree id) ...@@ -1890,69 +1910,6 @@ implicit_decl_warning (tree id)
warning ("implicit declaration of function `%s'", name); 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 /* Issue an error message for a reference to an undeclared variable
ID, including a reference to a builtin outside of function-call ID, including a reference to a builtin outside of function-call
context. Establish a binding of the identifier to error_mark_node context. Establish a binding of the identifier to error_mark_node
......
2004-01-10 Zack Weinberg <zack@codesourcery.com> 2004-01-10 Zack Weinberg <zack@codesourcery.com>
* 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 <zack@codesourcery.com>
* gcc.c-torture/compile/20021123-2.c: Delete; dup of 20021120-1.c. * 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. * gcc.c-torture/compile/20021123-3.c: Delete; dup of 20021120-2.c.
......
...@@ -10,7 +10,7 @@ void foo (double decl1) /* { dg-warning "shadows a global decl" } */ ...@@ -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" } */ double d; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "redeclared as different" "" { target *-*-* } 15 } */ /* { dg-error "redeclared as different" "" { target *-*-* } 15 } */
......
...@@ -13,33 +13,33 @@ static inline void __attribute__((__noinline__)) function_declaration_both_after ...@@ -13,33 +13,33 @@ static inline void __attribute__((__noinline__)) function_declaration_both_after
static void function_declaration_both_after(void) {} 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 void function_declaration_inline_noinline_before(void) {}
static inline void function_declaration_inline_noinline_after(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) {} static void function_declaration_noinline_inline_before(void) {}
......
/* PR c/9928 */ /* PR c/9928 */
/* { dg-do compile } */ /* { dg-do compile } */
enum { CODES }; /* { dg-error "previous declaration" } */ enum { CODES }; /* { dg-error "previous definition" } */
enum { CODES }; /* { dg-error "conflicting types" } */ enum { CODES }; /* { dg-error "conflicting types" } */
...@@ -24,7 +24,6 @@ int main () ...@@ -24,7 +24,6 @@ int main ()
return 0; 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 1 of" "1st incompatible" { target *-*-* } 16 } */
/* { dg-warning "passing arg 2 of" "2nd incompatible" { target *-*-* } 16 } */ /* { dg-warning "passing arg 2 of" "2nd incompatible" { target *-*-* } 16 } */
/* { dg-warning "passing arg 1 of" "1st incompatible" { target *-*-* } 18 } */ /* { dg-warning "passing arg 1 of" "1st incompatible" { target *-*-* } 18 } */
......
...@@ -6,7 +6,7 @@ int foo (const char*, const char*); ...@@ -6,7 +6,7 @@ int foo (const char*, const char*);
void bar (void) void bar (void)
{ {
const char *s = "bar"; const char *s = "bar";
int i; /* { dg-error "previously declared here" } */ int i; /* { dg-error "previous declaration" } */
int size = 2; int size = 2;
int i = foo (s, s + size); /* { dg-error "redeclaration of" } */ int i = foo (s, s + size); /* { dg-error "redeclaration of" } */
} }
...@@ -74,7 +74,7 @@ void test5(void) ...@@ -74,7 +74,7 @@ void test5(void)
/* Extern then static, both at file scope. */ /* 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) static int test6(int x)
{ return x; } /* { dg-warning "follows non-static" } */ { return x; } /* { dg-warning "follows non-static" } */
...@@ -83,7 +83,7 @@ static int test6(int x) ...@@ -83,7 +83,7 @@ static int test6(int x)
void prime7(void) void prime7(void)
{ {
extern int test7(int); /* { dg-warning "previous" "" { xfail *-*-* } } */ extern int test7(int); /* { dg-warning "previous" "" } */
} }
static int test7(int x) static int test7(int x)
...@@ -93,7 +93,7 @@ static int test7(int x) ...@@ -93,7 +93,7 @@ static int test7(int x)
void prime8(void) void prime8(void)
{ {
test8(); /* { dg-warning "previous" "" { xfail *-*-* } } */ test8(); /* { dg-warning "previous" "" } */
/* { dg-warning "implicit" "" { target *-*-* } 96 } */ /* { dg-warning "implicit" "" { target *-*-* } 96 } */
} }
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
extern int extern int
__attribute__((visibility ("hidden"))) __attribute__((visibility ("hidden")))
xyzzy; /* { dg-warning "previous declaration here" "" } */ xyzzy; /* { dg-warning "previous declaration" "" } */
int int
__attribute__((visibility ("protected"))) __attribute__((visibility ("protected")))
xyzzy = 5; /* { dg-warning "visibility attribute ignored" "" } */ xyzzy = 5; /* { dg-warning "different visibility" "" } */
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-Wtraditional" } */ /* { 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" } */ void testfunc1() {} /* { dg-warning "non-static.*follows static" "non-static follows static" } */
# 11 "sys-header.h" 3 # 11 "sys-header.h" 3
......
...@@ -16,9 +16,8 @@ ...@@ -16,9 +16,8 @@
@end @end
@implementation class3 @implementation class3
- (int) meth1 { return 0; } - (int) meth1 { return 0; } /* { dg-error "previous definition" } */
- (int) meth1 { return 0; } /* { dg-error "redefinition of" } */ - (int) meth1 { return 0; } /* { dg-error "redefinition of" } */
/* { dg-error "previously defined here" "" { target *-*-* } 19 } */
@end @end
@interface class4 @interface class4
...@@ -26,7 +25,6 @@ ...@@ -26,7 +25,6 @@
@end @end
@implementation class4 @implementation class4
+ (void) meth1 {} + (void) meth1 {} /* { dg-error "previous definition" } */
+ (void) meth1 {} /* { dg-error "redefinition of" } */ + (void) meth1 {} /* { dg-error "redefinition of" } */
/* { dg-error "previously defined here" "" { target *-*-* } 29 } */
@end @end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment