This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
RFHelp: c-decl.c rewrite 2/3
- From: "Zack Weinberg" <zack at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Andrew Pinski <apinski at apple dot com>, Per Bothner <per at bothner dot com>
- Date: Mon, 12 Jan 2004 10:28:44 -0800
- Subject: RFHelp: c-decl.c rewrite 2/3
So here's the present state of the second stage of my c-decl.c
rewrite. This is roughly Per's "never modify olddecl in
duplicate_decls" concept from last month, only it uses a different
mechanism to identify the canonical decl (to avoid conflict with
DECL_ABSTRACT_ORIGIN) and it copies over more information.
It is unfortunately necessary to have merge_weak behave differently
when called from the C front end than when called from the C++ front
end.
I get a small handful of C testsuite failures on i686-linux, which I
am not having any luck resolving:
FAIL: gcc.c-torture/compile/20011119-2.c, -O1 (test for excess errors)
Abort in make_decl_rtl because expand_expr was passed a RESULT_DECL
whose DECL_RTL was not set by assign_parms - I cannot figure out why
this is happening.
FAIL: gcc.c-torture/compile/20031113-1.c, -O2
FAIL: gcc.c-torture/compile/900313-1.c, -O2
FAIL: gcc.c-torture/compile/950618-1.c, -O2
Abort in dwarf2out.c:gen_subprogram_die upon being handed a function
definition a second time. The problem construct is
foo() { baz(); } /* implicit declaration of baz */
bar() { baz(); } /* this line might not be necessary */
baz() { }
This is some kind of funky interaction with cgraph and, again, I
can't figure out what's going on.
I'd appreciate any help resolving these bugs. I would also appreciate
testing on non-i686-linux platforms, especially those that use
different object or debug formats.
The varray.[ch] changes are just extra checking, I will split them out
and send them separately. The testsuite change is a case of 'why
weren't we issuing this warning in the first place?'
zw
* tree.h (DECL_HAS_DUPLICATE, DECL_CANONICAL): New macros.
(decl_get_canonical, decl_set_canonical): New prototypes.
(struct tree_decl): Add has_duplicate bit.
* tree.c: Include varray.h.
(copy_node): Does not create duplicated decls.
(canonical_decls, decl_get_canonical, decl_set_canonical): New.
(get_callee_fndecl): Use the canonical decl.
* print-tree.c (print_node): Print has_duplicate flag.
* Makefile.in (tree.o): Depend on varray.h.
* output.h: Update prototypes.
* c-decl.c (merge_decls): Remove different_tu argument. Never
modify olddecl. Copy all necessary information from olddecl
to newdecl. Call common_type for builtins too. Move
PARM_DECL special case to duplicate_decls. Mark newdecl and
olddecl as duplicates of each other.
(duplicate_decls): Update to match.
(pushdecl): Update calls to duplicate_decls. Do not call
copy_node. Do not call duplicate_decls with newdecl and
olddecl equal.
(any_external_decl, lookup_name, lookup_name_current_level):
Return DECL_CANONICAL of the decl found.
(merge_translation_unit_decls): Update call to duplicate_decls.
(c_write_global_declarations): Only put canonical decls in the
vector.
* expr.c (expand_expr_real <VAR_DECL, FUNCTION_DECL, RESULT_DECL>):
Use the canonical decl.
* tree-inline.c (expand_call_inline): Likewise.
* varasm.c (assemble_variable, weak_finish): Likewise.
(merge_weak): Do not modify olddecl or remove it from the
lists if modify_olddecl is false.
* varray.h: When ENABLE_CHECKING, do bounds checking in
VARRAY_TOP and VARRAY_POP also.
* varray.c: Don't prototype error.
(varray_check_failed): Split long string.
(varray_underflow): New function.
cp:
* decl.c (duplicate_decls): Update call to merge_weak.
testsuite:
* gcc.dg/noncompile/20020213-1.c: Update error regexps.
===================================================================
Index: Makefile.in
--- Makefile.in 11 Jan 2004 15:56:25 -0000 1.1218
+++ Makefile.in 12 Jan 2004 18:15:31 -0000
@@ -1494,7 +1494,7 @@ langhooks.o : langhooks.c $(CONFIG_H) $(
$(LANGHOOKS_DEF_H) flags.h $(GGC_H) gt-langhooks.h diagnostic.h
tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) flags.h function.h \
toplev.h $(GGC_H) $(HASHTAB_H) $(TARGET_H) output.h $(TM_P_H) langhooks.h \
- real.h gt-tree.h
+ real.h gt-tree.h varray.h
tree-dump.o: tree-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(C_TREE_H) flags.h langhooks.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \
$(EXPR_H) $(SPLAY_TREE_H) tree-dump.h
===================================================================
Index: c-decl.c
--- c-decl.c 11 Jan 2004 22:40:47 -0000 1.468
+++ c-decl.c 12 Jan 2004 18:15:32 -0000
@@ -1234,56 +1234,35 @@ diagnose_mismatched_decls (tree newdecl,
}
/* 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. */
+ consistent with OLDDECL, but carries new information. Merge
+ all information that OLDDECL has and NEWDECL does not, into
+ NEWDECL. This function issues no diagnostics.
+
+ new information into OLDDECL. If DIFFERENT_BINDING_LEVEL is true,
+ avoid completely merging the decls, as this will break assumptions
+ elsewhere. This function issues no diagnostics. */
static void
merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype,
- bool different_binding_level, bool different_tu)
+ bool different_binding_level)
{
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))
- {
- 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))
- {
- 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)));
- }
- else
- TREE_TYPE (newdecl)
- = TREE_TYPE (olddecl)
- = common_type (newtype, oldtype);
- }
+ if (different_binding_level
+ && (TYPE_ARG_TYPES (oldtype) == 0
+ || TYPE_ARG_TYPES (newtype) != 0))
+ TREE_TYPE (newdecl)
+ = build_type_attribute_variant
+ (newtype,
+ merge_attributes (TYPE_ATTRIBUTES (newtype),
+ TYPE_ATTRIBUTES (oldtype)));
+ else
+ TREE_TYPE (newdecl) = common_type (newtype, oldtype);
/* Lay the type out, unless already done. */
if (oldtype != TREE_TYPE (newdecl))
@@ -1301,27 +1280,20 @@ merge_decls (tree newdecl, tree olddecl,
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);
- }
+ if (TREE_CODE (olddecl) != FUNCTION_DECL
+ && 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. */
- COPY_DECL_RTL (olddecl, newdecl);
-
/* Merge the type qualifiers. */
- if (TREE_READONLY (newdecl))
- TREE_READONLY (write_olddecl) = 1;
+ TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
+ TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
- if (TREE_THIS_VOLATILE (newdecl))
- {
- TREE_THIS_VOLATILE (write_olddecl) = 1;
- if (TREE_CODE (newdecl) == VAR_DECL)
- make_var_volatile (newdecl);
- }
+ if (TREE_THIS_VOLATILE (newdecl) && 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
@@ -1331,24 +1303,33 @@ merge_decls (tree newdecl, tree olddecl,
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;
+ DECL_IN_SYSTEM_HEADER (newdecl) |= DECL_IN_SYSTEM_HEADER (olddecl);
/* 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)
+ if (!different_binding_level && DECL_INITIAL (newdecl) == 0)
DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+ if (!different_binding_level
+ && DECL_INITIAL (newdecl) == error_mark_node
+ && DECL_INITIAL (olddecl)
+ && TREE_CODE (DECL_INITIAL (olddecl)) == BLOCK)
+ {
+ /* This happens when olddecl is an extern-inline definition and
+ newdecl is a weak alias. See c-torture/compile/20011119-2.c.
+ new_is_definition is incorrectly set in this case. */
+ DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+ new_is_definition = false;
+ }
+
/* 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);
+ if (!DECL_SECTION_NAME (newdecl))
+ DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
/* Copy the assembler name.
Currently, it can only be defined in the prototype. */
@@ -1365,31 +1346,30 @@ merge_decls (tree newdecl, tree 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 (TREE_CODE (newdecl) == VAR_DECL)
+ {
+ DECL_IN_TEXT_SECTION (newdecl) |= DECL_IN_TEXT_SECTION (olddecl);
+ }
+
/* Merge the storage class information. */
- merge_weak (newdecl, olddecl);
+ merge_weak (newdecl, olddecl, /*modify_olddecl=*/false);
/* For functions, static overrides non-static. */
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl);
- /* This is since we don't automatically
- copy the attributes of NEWDECL into OLDDECL. */
- /* No need to worry about different_binding_level here because
- then TREE_PUBLIC (newdecl) was true. */
- TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
/* If this clears `static', clear it in the identifier too. */
if (! TREE_PUBLIC (olddecl))
TREE_PUBLIC (DECL_NAME (olddecl)) = 0;
}
+
if (DECL_EXTERNAL (newdecl))
{
- if (! different_binding_level || different_tu)
+ if (! different_binding_level)
{
/* Don't mess with these flags on local externs; they remain
external even if there's a declaration at file scope which
@@ -1397,23 +1377,15 @@ merge_decls (tree newdecl, tree olddecl,
TREE_STATIC (newdecl) = TREE_STATIC (olddecl);
DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl);
}
+
/* An extern decl does not override previous storage class. */
TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
if (! DECL_EXTERNAL (newdecl))
{
DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl);
DECL_COMMON (newdecl) = DECL_COMMON (olddecl);
- /* If we have two non-EXTERNAL file-scope decls that are
- the same, only one of them should be written out. */
- if (different_tu)
- TREE_ASM_WRITTEN (newdecl) = 1;
}
}
- else
- {
- TREE_STATIC (olddecl) = TREE_STATIC (newdecl);
- TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
- }
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
@@ -1438,116 +1410,101 @@ merge_decls (tree newdecl, tree olddecl,
{
/* If either decl says `inline', this fn is inline,
unless its definition was passed already. */
- if (DECL_DECLARED_INLINE_P (newdecl)
- || DECL_DECLARED_INLINE_P (olddecl))
- DECL_DECLARED_INLINE_P (newdecl) = 1;
-
- DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl)
- = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl));
- }
-
- if (DECL_BUILT_IN (olddecl))
- {
- /* Get rid of any built-in function if we have a function
- definition. */
- if (new_is_definition)
- {
- if (! different_binding_level)
- {
- TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
- DECL_BUILT_IN_CLASS (olddecl) = NOT_BUILT_IN;
- }
- }
- else
- {
- /* If redeclaring a builtin function, and not a definition,
- it stays built in. */
- DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
- DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
- }
- }
+ DECL_DECLARED_INLINE_P (newdecl) |= DECL_DECLARED_INLINE_P (olddecl);
+ DECL_UNINLINABLE (newdecl) |= DECL_UNINLINABLE (olddecl);
- /* Also preserve various other info from the definition. */
- if (! new_is_definition)
- {
- DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
- /* 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 (! different_binding_level)
- DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
- DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl);
- DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl);
- DECL_ESTIMATED_INSNS (newdecl) = DECL_ESTIMATED_INSNS (olddecl);
- DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
-
- /* Set DECL_INLINE on the declaration if we've got a body
- from which to instantiate. */
- if (DECL_INLINE (olddecl) && ! DECL_UNINLINABLE (newdecl))
- {
- DECL_INLINE (newdecl) = 1;
- DECL_ABSTRACT_ORIGIN (newdecl)
- = (different_binding_level
- ? DECL_ORIGIN (olddecl)
- : DECL_ABSTRACT_ORIGIN (olddecl));
- }
- }
- else
- {
- /* If a previous declaration said inline, mark the
- definition as inlinable. */
if (DECL_DECLARED_INLINE_P (newdecl)
- && ! DECL_UNINLINABLE (newdecl))
+ && !DECL_UNINLINABLE (newdecl))
DECL_INLINE (newdecl) = 1;
- }
- }
+
+ if (DECL_INLINE (newdecl))
+ DECL_ABSTRACT_ORIGIN (newdecl)
+ = (different_binding_level
+ ? DECL_ORIGIN (olddecl)
+ : DECL_ABSTRACT_ORIGIN (olddecl));
+ }
+
+ if (!new_is_definition && DECL_BUILT_IN (olddecl))
+ {
+ /* If redeclaring a builtin function, and not a definition,
+ it stays built in. */
+ DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
+ DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+ }
+
+ /* Preserve various other information. */
+ DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
+ DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl);
+ DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl);
+ DECL_ESTIMATED_INSNS (newdecl) = DECL_ESTIMATED_INSNS (olddecl);
+ DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
+ DECL_NO_STATIC_CHAIN (newdecl) |= DECL_NO_STATIC_CHAIN (olddecl);
+ DECL_INLINED_FNS (newdecl) = DECL_INLINED_FNS (olddecl);
+ }
+
+ /* Other common information to be copied over. */
+ TREE_ADDRESSABLE (newdecl) |= TREE_ADDRESSABLE (olddecl);
+ TREE_ASM_WRITTEN (newdecl) |= TREE_ASM_WRITTEN (olddecl);
+ TREE_USED (newdecl) |= TREE_USED (olddecl);
+ TREE_DEPRECATED (newdecl) |= TREE_DEPRECATED (olddecl);
+
+ DECL_IGNORED_P (newdecl) |= DECL_IGNORED_P (olddecl);
+ DECL_ABSTRACT (newdecl) |= DECL_ABSTRACT (olddecl);
+ DECL_COMMON (newdecl) |= DECL_COMMON (olddecl);
+ DECL_REGISTER (newdecl) |= DECL_REGISTER (olddecl);
+ DECL_NONLOCAL (newdecl) |= DECL_NONLOCAL (olddecl);
+ DECL_DEFER_OUTPUT (newdecl) |= DECL_DEFER_OUTPUT (olddecl);
+ DECL_ARTIFICIAL (newdecl) |= DECL_ARTIFICIAL (olddecl);
+
if (different_binding_level)
return;
- /* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
- But preserve OLDDECL's DECL_UID. */
- {
- unsigned olddecl_uid = DECL_UID (olddecl);
-
- memcpy ((char *) olddecl + sizeof (struct tree_common),
- (char *) newdecl + sizeof (struct tree_common),
- sizeof (struct tree_decl) - sizeof (struct tree_common));
- DECL_UID (olddecl) = olddecl_uid;
- }
-
- /* 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. */
- if (DECL_RTL_SET_P (olddecl)
- && (TREE_CODE (olddecl) == FUNCTION_DECL
- || (TREE_CODE (olddecl) == VAR_DECL
- && TREE_STATIC (olddecl))))
- make_decl_rtl (olddecl, NULL);
+ /* Make NEWDECL a duplicate of OLDDECL. */
+ DECL_HAS_DUPLICATE (newdecl) = 1;
+ DECL_HAS_DUPLICATE (olddecl) = 1;
+ DECL_UID (newdecl) = DECL_UID (olddecl);
+ decl_set_canonical (newdecl);
+
+ /* Update cgraph if appropriate. It indexes by DECL_ASSEMBLER_NAME,
+ so will find the appropriate node from NEWDECL. */
+ if (DECL_INITIAL (newdecl) && TREE_CODE (newdecl) == FUNCTION_DECL)
+ cgraph_node (newdecl)->decl = newdecl;
}
/* 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 appropriate. Combines information from OLDDECL and NEWDECL.
- If safely possible, alter OLDDECL to look like NEWDECL, and return
- true. Otherwise, return false.
+ The return value is true if OLDDECL is the decl to continue using
+ (this is rare, but could be made more common); false if NEWDECL
+ should be used instead.
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)
+duplicate_decls (tree newdecl, tree olddecl, bool different_binding_level)
{
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;
+ /* For real parm decl following a forward decl, old decl should
+ be reused. Only allow this to happen once. */
+ if (TREE_CODE (newdecl) == PARM_DECL
+ && TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl))
+ {
+ TREE_ASM_WRITTEN (olddecl) = 0;
+ return true;
+ }
+ else
+ {
+ merge_decls (newdecl, olddecl, newtype, oldtype,
+ different_binding_level);
+ return false;
+ }
}
@@ -1563,11 +1520,11 @@ any_external_decl (tree id)
if (decl == 0 || TREE_CODE (decl) == ERROR_MARK)
return 0;
else if (TREE_CODE (decl) != TYPE_DECL && DECL_EXTERNAL (decl))
- return decl;
+ return DECL_CANONICAL (decl);
t = purpose_member (id, truly_local_externals);
if (t)
- return TREE_VALUE (t);
+ return DECL_CANONICAL (TREE_VALUE (t));
return 0;
}
@@ -1728,7 +1685,7 @@ pushdecl (tree x)
IDENTIFIER_POINTER (name));
old = lookup_name_current_level (name);
- if (old && duplicate_decls (x, old, 0, false))
+ if (old && duplicate_decls (x, old, false))
{
/* For PARM_DECLs, old may be a forward declaration.
If so, we want to remove it from its old location
@@ -1747,18 +1704,18 @@ pushdecl (tree x)
}
return old;
}
- if (DECL_EXTERNAL (x) || scope == global_scope)
+ else if (DECL_EXTERNAL (x) || scope == global_scope)
{
/* Find and check against a previous, not-in-scope, external
decl for this identifier. (C99 6.2.7p2: All declarations
that refer to the same object or function shall have
compatible type; otherwise, the behavior is undefined.) */
tree ext = any_external_decl (name);
- if (ext)
+ if (ext && ext != x)
{
- if (duplicate_decls (x, ext, scope != global_scope,
- false))
- x = copy_node (ext);
+ if (duplicate_decls (x, ext, scope != global_scope))
+ /* Cannot have a PARM_DECL here. */
+ return ext;
}
else
record_external_decl (x);
@@ -2186,7 +2143,7 @@ lookup_name (tree name)
return decl;
if (C_DECL_INVISIBLE (decl))
return 0;
- return decl;
+ return DECL_CANONICAL (decl);
}
/* Similar to `lookup_name' but look only at the current scope. */
@@ -2200,16 +2157,16 @@ lookup_name_current_level (tree name)
return 0;
if (current_scope == global_scope)
- return decl;
+ return DECL_CANONICAL (decl);
/* Scan the current scope for a decl with name NAME.
For PARM_DECLs, we have to look at both ->parms and ->names, since
forward parameter declarations wind up on the ->names list. */
if (TREE_CODE (decl) == PARM_DECL
&& chain_member (decl, current_scope->parms))
- return decl;
+ return DECL_CANONICAL (decl);
if (chain_member (decl, current_scope->names))
- return decl;
+ return DECL_CANONICAL (decl);
return 0;
}
@@ -6589,7 +6546,7 @@ merge_translation_unit_decls (void)
/* Print any appropriate error messages, and partially merge
the decls. */
- (void) duplicate_decls (decl, global_decl, true, true);
+ (void) duplicate_decls (decl, global_decl, true);
}
htab_delete (link_hash_table);
@@ -6598,7 +6555,7 @@ merge_translation_unit_decls (void)
/* Perform final processing on file-scope data. */
void
-c_write_global_declarations(void)
+c_write_global_declarations (void)
{
tree link;
@@ -6612,14 +6569,13 @@ c_write_global_declarations(void)
/* Process the decls in the order they were written. */
- for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl))
- vec[i] = decl;
-
- wrapup_global_declarations (vec, len);
+ for (i = 0, decl = globals; decl; decl = TREE_CHAIN (decl))
+ if (decl == DECL_CANONICAL (decl))
+ vec[i++] = decl;
- check_global_declarations (vec, len);
+ wrapup_global_declarations (vec, i);
+ check_global_declarations (vec, i);
- /* Clean up. */
free (vec);
}
}
===================================================================
Index: expr.c
--- expr.c 10 Jan 2004 20:50:53 -0000 1.614
+++ expr.c 12 Jan 2004 18:15:33 -0000
@@ -6350,6 +6350,7 @@ expand_expr_real (tree exp, rtx target,
case FUNCTION_DECL:
case RESULT_DECL:
+ exp = DECL_CANONICAL (exp);
if (DECL_RTL (exp) == 0)
abort ();
===================================================================
Index: output.h
--- output.h 1 Oct 2003 22:57:57 -0000 1.133
+++ output.h 12 Jan 2004 18:15:33 -0000
@@ -224,7 +224,7 @@ extern void mergeable_constant_section (
/* Declare DECL to be a weak symbol. */
extern void declare_weak (tree);
/* Merge weak status. */
-extern void merge_weak (tree, tree);
+extern void merge_weak (tree, tree, bool);
/* Emit any pending weak declarations. */
extern void weak_finish (void);
===================================================================
Index: print-tree.c
--- print-tree.c 5 Jan 2004 15:16:35 -0000 1.80
+++ print-tree.c 12 Jan 2004 18:15:33 -0000
@@ -307,6 +307,8 @@ print_node (FILE *file, const char *pref
fputs (" external", file);
if (DECL_WEAK (node))
fputs (" weak", file);
+ if (DECL_HAS_DUPLICATE (node))
+ fputs (" has_duplicate", file);
if (DECL_REGISTER (node) && TREE_CODE (node) != FIELD_DECL
&& TREE_CODE (node) != FUNCTION_DECL
&& TREE_CODE (node) != LABEL_DECL)
===================================================================
Index: tree-inline.c
--- tree-inline.c 4 Jan 2004 14:39:12 -0000 1.89
+++ tree-inline.c 12 Jan 2004 18:15:33 -0000
@@ -1312,7 +1312,7 @@ expand_call_inline (tree *tp, int *walk_
return NULL_TREE;
/* Turn forward declarations into real ones. */
- fn = cgraph_node (fn)->decl;
+ fn = DECL_CANONICAL (cgraph_node (fn)->decl);
/* If fn is a declaration of a function in a nested scope that was
globally declared inline, we don't set its DECL_INITIAL.
===================================================================
Index: tree.c
--- tree.c 10 Jan 2004 12:02:34 -0000 1.341
+++ tree.c 12 Jan 2004 18:15:33 -0000
@@ -45,6 +45,7 @@ Software Foundation, 59 Temple Place - S
#include "output.h"
#include "target.h"
#include "langhooks.h"
+#include "varray.h"
/* obstack.[ch] explicitly declined to prototype this. */
extern int _obstack_allocated_p (struct obstack *h, void *obj);
@@ -355,7 +356,13 @@ copy_node (tree node)
TREE_ASM_WRITTEN (t) = 0;
if (TREE_CODE_CLASS (code) == 'd')
- DECL_UID (t) = next_decl_uid++;
+ {
+ /* This process creates a new decl which is distinct from the
+ old one. If caller meant to create a duplicate, caller can
+ undo this. */
+ DECL_UID (t) = next_decl_uid++;
+ DECL_HAS_DUPLICATE (t) = 0;
+ }
else if (TREE_CODE_CLASS (code) == 't')
{
TYPE_UID (t) = next_type_uid++;
@@ -4450,7 +4457,88 @@ decl_type_context (tree decl)
return NULL_TREE;
}
+
+/* There may be more than one decl for the same object. If so, this
+ data structure holds the canonical decl for that object (the one
+ with the most information). See merge_decls, etc. in c-decl.c.
+
+ Use of this data structure should be rare, and we know that
+ DECL_UIDs are assigned in strictly ascending order. Thus,
+ we use a sorted varray and binary search: O(log n) all
+ operations. */
+static GTY(()) varray_type canonical_decls;
+
+tree
+decl_get_canonical (tree decl)
+{
+ unsigned int uid = DECL_UID (decl);
+ int high, low, probe;
+
+ if (!canonical_decls)
+ abort ();
+ if (VARRAY_ACTIVE_SIZE (canonical_decls) > INT_MAX)
+ abort ();
+
+ /* Binary search on DECL_UID */
+ low = -1;
+ high = VARRAY_ACTIVE_SIZE (canonical_decls);
+ while (high - low > 1)
+ {
+ probe = (high + low) / 2;
+ if (DECL_UID (VARRAY_TREE (canonical_decls, probe)) > uid)
+ high = probe;
+ else
+ low = probe;
+ }
+
+ if (low == -1 || DECL_UID (VARRAY_TREE (canonical_decls, low)) != uid)
+ abort ();
+
+ return VARRAY_TREE (canonical_decls, low);
+}
+
+void
+decl_set_canonical (tree decl)
+{
+ unsigned int uid = DECL_UID (decl);
+ int high, low, probe;
+
+ if (!canonical_decls)
+ VARRAY_TREE_INIT (canonical_decls, 16, "canonical_decls");
+ if (VARRAY_ACTIVE_SIZE (canonical_decls) > INT_MAX)
+ abort ();
+
+ /* Binary search on DECL_UID */
+ low = -1;
+ high = VARRAY_ACTIVE_SIZE (canonical_decls);
+ while (high - low > 1)
+ {
+ probe = (high + low) / 2;
+ if (DECL_UID (VARRAY_TREE (canonical_decls, probe)) > uid)
+ high = probe;
+ else
+ low = probe;
+ }
+
+ if (low != -1 && DECL_UID (VARRAY_TREE (canonical_decls, low)) == uid)
+ VARRAY_TREE (canonical_decls, low) = decl;
+ else if (low == (int)VARRAY_ACTIVE_SIZE (canonical_decls) - 1)
+ VARRAY_PUSH_TREE (canonical_decls, decl);
+ else
+ {
+ /* Need to insert in the middle of the array. low points
+ one before the target address. */
+ VARRAY_PUSH_TREE (canonical_decls, 0); /* make room */
+ memmove (&VARRAY_TREE (canonical_decls, low + 2),
+ &VARRAY_TREE (canonical_decls, low + 1),
+ /* do _not_ include the new slot we just allocated
+ in the move */
+ (VARRAY_ACTIVE_SIZE (canonical_decls)-low-2) * sizeof (tree));
+ VARRAY_TREE (canonical_decls, low + 1) = decl;
+ }
+}
+
/* CALL is a CALL_EXPR. Return the declaration for the function
called, or NULL_TREE if the called function cannot be
determined. */
@@ -4481,7 +4569,8 @@ get_callee_fndecl (tree call)
that `f' is being called. */
if (TREE_CODE (addr) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (addr, 0)) == FUNCTION_DECL)
- return TREE_OPERAND (addr, 0);
+ /* There might be more than one decl for this function. */
+ return DECL_CANONICAL (TREE_OPERAND (addr, 0));
/* We couldn't figure out what was being called. Maybe the front
end has some idea. */
===================================================================
Index: tree.h
--- tree.h 9 Jan 2004 19:55:01 -0000 1.456
+++ tree.h 12 Jan 2004 18:15:34 -0000
@@ -1497,6 +1497,14 @@ struct tree_type GTY(())
/* Value of the decls's visibility attribute */
#define DECL_VISIBILITY(NODE) (DECL_CHECK (NODE)->decl.visibility)
+/* Nonzero for a decl which has at least one duplicate. */
+#define DECL_HAS_DUPLICATE(DECL) (DECL_CHECK (DECL)->decl.has_duplicate)
+
+/* Find the version of this DECL which carries the most information.
+ Note evaluates DECL twice. */
+#define DECL_CANONICAL(DECL) \
+ (DECL_HAS_DUPLICATE (DECL) ? decl_get_canonical (DECL) : (DECL))
+
/* In a FUNCTION_DECL, nonzero if the function cannot be inlined. */
#define DECL_UNINLINABLE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.uninlinable)
@@ -1689,8 +1697,7 @@ struct tree_decl GTY(())
unsigned thread_local_flag : 1;
unsigned declared_inline_flag : 1;
ENUM_BITFIELD(symbol_visibility) visibility : 2;
- unsigned unused : 1;
- /* one unused bit. */
+ unsigned has_duplicate : 1;
unsigned lang_flag_0 : 1;
unsigned lang_flag_1 : 1;
@@ -2665,6 +2672,13 @@ extern tree decl_function_context (tree)
/* Return the RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE which provides
this _DECL with its context, or zero if none. */
extern tree decl_type_context (tree);
+
+/* Return the version of this decl which carries the most information. */
+extern tree decl_get_canonical (tree);
+
+/* Assert that DECL is the version of all decls of the same object
+ which carries the most information. */
+extern void decl_set_canonical (tree);
/* Given the FUNCTION_DECL for the current function,
return zero if it is ok for this function to be inline.
===================================================================
Index: varasm.c
--- varasm.c 6 Jan 2004 16:51:21 -0000 1.402
+++ varasm.c 12 Jan 2004 18:15:34 -0000
@@ -1351,6 +1351,8 @@ assemble_variable (tree decl, int top_le
int reloc = 0;
rtx decl_rtl;
+ decl = DECL_CANONICAL (decl);
+
if (lang_hooks.decls.prepare_assemble_variable)
(*lang_hooks.decls.prepare_assemble_variable) (decl);
@@ -4240,10 +4242,12 @@ mark_weak (tree decl)
SYMBOL_REF_WEAK (XEXP (DECL_RTL (decl), 0)) = 1;
}
-/* Merge weak status between NEWDECL and OLDDECL. */
+/* Merge weak status between NEWDECL and OLDDECL.
+ MODIFY_OLDDECL is false if we are not to modify OLDDECL
+ (the C and C++ front ends' expectations are different). */
void
-merge_weak (tree newdecl, tree olddecl)
+merge_weak (tree newdecl, tree olddecl, bool modify_olddecl)
{
if (DECL_WEAK (newdecl) == DECL_WEAK (olddecl))
return;
@@ -4255,9 +4259,9 @@ merge_weak (tree newdecl, tree olddecl)
/* NEWDECL is weak, but OLDDECL is not. */
/* If we already output the OLDDECL, we're in trouble; we can't
- go back and make it weak. This error cannot caught in
- declare_weak because the NEWDECL and OLDDECL was not yet
- been merged; therefore, TREE_ASM_WRITTEN was not set. */
+ go back and make it weak. This error cannot be caught in
+ declare_weak because NEWDECL and OLDDECL had not yet been
+ merged; therefore, TREE_ASM_WRITTEN was not set. */
if (TREE_ASM_WRITTEN (olddecl))
error ("%Jweak declaration of '%D' must precede definition",
newdecl, newdecl);
@@ -4270,7 +4274,7 @@ merge_weak (tree newdecl, tree olddecl)
warning ("%Jweak declaration of '%D' after first use results "
"in unspecified behavior", newdecl, newdecl);
- if (SUPPORTS_WEAK)
+ if (SUPPORTS_WEAK && modify_olddecl)
{
/* We put the NEWDECL on the weak_decls list at some point.
Replace it with the OLDDECL. */
@@ -4286,8 +4290,9 @@ merge_weak (tree newdecl, tree olddecl)
not need to do anything. */
}
- /* Make the OLDDECL weak; it's OLDDECL that we'll be keeping. */
- mark_weak (olddecl);
+ if (modify_olddecl)
+ /* Make the OLDDECL weak; it's OLDDECL that we'll be keeping. */
+ mark_weak (olddecl);
}
else
/* OLDDECL was weak, but NEWDECL was not explicitly marked as
@@ -4324,7 +4329,7 @@ weak_finish (void)
for (t = weak_decls; t; t = TREE_CHAIN (t))
{
- tree decl = TREE_VALUE (t);
+ tree decl = DECL_CANONICAL (TREE_VALUE (t));
#if defined (ASM_WEAKEN_DECL) || defined (ASM_WEAKEN_LABEL)
const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
#endif
===================================================================
Index: varray.c
--- varray.c 19 Jul 2003 14:47:14 -0000 1.21
+++ varray.c 12 Jan 2004 18:15:34 -0000
@@ -118,15 +118,22 @@ varray_clear (varray_type va)
#if defined ENABLE_CHECKING && (GCC_VERSION >= 2007)
-extern void error (const char *, ...) ATTRIBUTE_PRINTF_1;
-
void
varray_check_failed (varray_type va, size_t n, const char *file, int line,
const char *function)
{
- internal_error ("virtual array %s[%lu]: element %lu out of bounds in %s, at %s:%d",
+ internal_error ("virtual array %s[%lu]: element %lu out of bounds "
+ "in %s, at %s:%d",
va->name, (unsigned long) va->num_elements, (unsigned long) n,
function, trim_filename (file), line);
+}
+
+void
+varray_underflow (varray_type va, const char *file, int line,
+ const char *function)
+{
+ internal_error ("underflowed virtual array %s in %s, at %s:%d",
+ va->name, function, trim_filename (file), line);
}
#endif
===================================================================
Index: varray.h
--- varray.h 10 Jul 2003 11:38:18 -0000 1.32
+++ varray.h 12 Jan 2004 18:15:34 -0000
@@ -227,14 +227,27 @@ extern void varray_clear (varray_type);
#if defined ENABLE_CHECKING && (GCC_VERSION >= 2007)
extern void varray_check_failed (varray_type, size_t, const char *, int,
const char *) ATTRIBUTE_NORETURN;
+extern void varray_underflow (varray_type, const char *, int, const char *)
+ ATTRIBUTE_NORETURN;
#define VARRAY_CHECK(VA, N, T) __extension__ \
(*({ varray_type const _va = (VA); \
const size_t _n = (N); \
if (_n >= _va->num_elements) \
varray_check_failed (_va, _n, __FILE__, __LINE__, __FUNCTION__); \
&_va->data.T[_n]; }))
+
+#define VARRAY_POP(VA) do { \
+ varray_type const _va = (VA); \
+ if (_va->elements_used == 0) \
+ varray_underflow (_va, __FILE__, __LINE__, __FUNCTION__); \
+ else \
+ _va->elements_used--; \
+} while (0)
+
#else
#define VARRAY_CHECK(VA, N, T) ((VA)->data.T[N])
+/* Pop the top element of VA. */
+#define VARRAY_POP(VA) do { ((VA)->elements_used--); } while (0)
#endif
/* Push X onto VA. T is the name of the field in varray_data
@@ -248,14 +261,6 @@ extern void varray_check_failed (varray_
} \
while (0)
-/* Pop the top element of VA. */
-#define VARRAY_POP(VA) \
- ((VA)->elements_used--)
-
-/* Return the top element of VA. */
-#define VARRAY_TOP(VA, T) \
- ((VA)->data.T[(VA)->elements_used - 1])
-
#define VARRAY_CHAR(VA, N) VARRAY_CHECK (VA, N, c)
#define VARRAY_UCHAR(VA, N) VARRAY_CHECK (VA, N, uc)
#define VARRAY_SHORT(VA, N) VARRAY_CHECK (VA, N, s)
@@ -299,6 +304,8 @@ extern void varray_check_failed (varray_
#define VARRAY_PUSH_BB(VA, X) VARRAY_PUSH (VA, bb, X)
/* Return the last element of VA. */
+#define VARRAY_TOP(VA, T) VARRAY_CHECK(VA, (VA)->elements_used - 1, T)
+
#define VARRAY_TOP_CHAR(VA) VARRAY_TOP (VA, c)
#define VARRAY_TOP_UCHAR(VA) VARRAY_TOP (VA, uc)
#define VARRAY_TOP_SHORT(VA) VARRAY_TOP (VA, s)
===================================================================
Index: cp/decl.c
--- cp/decl.c 10 Jan 2004 01:18:08 -0000 1.1171
+++ cp/decl.c 12 Jan 2004 18:15:39 -0000
@@ -1734,7 +1734,7 @@ duplicate_decls (tree newdecl, tree oldd
}
/* Merge the storage class information. */
- merge_weak (newdecl, olddecl);
+ merge_weak (newdecl, olddecl, /*modify_olddecl=*/true);
DECL_ONE_ONLY (newdecl) |= DECL_ONE_ONLY (olddecl);
DECL_DEFER_OUTPUT (newdecl) |= DECL_DEFER_OUTPUT (olddecl);
===================================================================
Index: testsuite/gcc.dg/noncompile/20020213-1.c
--- testsuite/gcc.dg/noncompile/20020213-1.c 11 Jan 2004 01:18:58 -0000 1.2
+++ testsuite/gcc.dg/noncompile/20020213-1.c 12 Jan 2004 18:15:44 -0000
@@ -24,6 +24,7 @@ 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 } */