This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Symtab cleanup 6/17: fix handling of constructors of aliases
- From: Jan Hubicka <hubicka at ucw dot cz>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 17 Jun 2013 11:53:57 +0200
- Subject: Symtab cleanup 6/17: fix handling of constructors of aliases
Hi,
this patch makes it possible to fold through aliases. It may seem unimportant, but we
run into those cases in C++ where extra name aliases may get used by devirtualization
machinery. The patch also fixes the following long standing bug:
jh@gcc10:~/trunk/build2/gcc$ cat t.c
static int a=4;
static int b __attribute__ ((alias("a")));
main()
{
return b+a;
}
jh@gcc10:~/trunk/build2/gcc$ gcc -O2 t.c -S
jh@gcc10:~/trunk/build2/gcc$ more t.s
.file "t.c"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
movl $4, %eax
ret
.cfi_endproc
.LFE0:
.size main, .-main
.section .rodata
.align 4
.type a, @object
.size a, 4
a:
.long 4
.set b,a
.ident "GCC: (Debian 4.4.5-8) 4.4.5"
.section .note.GNU-stack,"",@progbits
jh@gcc10:~/trunk/build2/gcc$ gcc --version
gcc (Debian 4.4.5-8) 4.4.5
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
jh@gcc10:~/trunk/build2/gcc$ ./xgcc -B ./ -O2 t.c -S
jh@gcc10:~/trunk/build2/gcc$ more t.s
.file "t.c"
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
movl $8, %eax
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.9.0 20130616 (experimental)"
.section .note.GNU-stack,"",@progbits
The main idea is to replace const_value_known_p predicate by ctor_for_folding
that returns the ctor and is able to look through aliases via the symbol table.
The huge change in expand_expr_real_1 is really just a reformating.
I have bootstrapped/regtested the patch on x86_64-linux and tested with Firefox build.
I am running now PPC64 test and will wait for Richard's renaming patch.
Honza
* cgraph.h (const_value_known_p): Replace by ...
(ctor_for_folding): .. this one.
* cgraphunit.c (process_function_and_variable_attributes): Use it.
* lto-cgraph.c (compute_ltrans_boundary): Use ctor_for_folding.
* expr.c (expand_expr_real_1): Likewise.
(string_constant): Likewise.
* tree-ssa-loop-ivcanon.c (constant_after_peeling): Likewise.
* ipa.c (process_references): Likewise.
(symtab_remove_unreachable_nodes): Likewise.
* ipa-inline-analysis.c (param_change_prob): Likewise.
* gimple-fold.c (canonicalize_constructor_val): Likewise.
(get_base_constructor): Likwise.
* varpool.c (varpool_remove_node): Likewise.
(varpool_remove_initializer): LIkewise.
(dump_varpool_node): LIkwise.
(const_value_known_p): Rewrite to ...
(ctor_for_folding): ... this one.
* lto-partition.c (add_references_to_partition): Use
ctor_for_folding.
* gcc.dg/tree-ssa/attr-alias-2.c: New testcase.
Index: cgraph.h
===================================================================
*** cgraph.h (revision 200147)
--- cgraph.h (working copy)
*************** void varpool_analyze_node (struct varpoo
*** 797,803 ****
struct varpool_node * varpool_extra_name_alias (tree, tree);
struct varpool_node * varpool_create_variable_alias (tree, tree);
void varpool_reset_queue (void);
! bool const_value_known_p (tree);
bool varpool_for_node_and_aliases (struct varpool_node *,
bool (*) (struct varpool_node *, void *),
void *, bool);
--- 797,803 ----
struct varpool_node * varpool_extra_name_alias (tree, tree);
struct varpool_node * varpool_create_variable_alias (tree, tree);
void varpool_reset_queue (void);
! tree ctor_for_folding (tree);
bool varpool_for_node_and_aliases (struct varpool_node *,
bool (*) (struct varpool_node *, void *),
void *, bool);
Index: cgraphunit.c
===================================================================
*** cgraphunit.c (revision 200147)
--- cgraphunit.c (working copy)
*************** process_function_and_variable_attributes
*** 761,768 ****
{
tree decl = vnode->symbol.decl;
if (DECL_EXTERNAL (decl)
! && DECL_INITIAL (decl)
! && const_value_known_p (decl))
varpool_finalize_decl (decl);
if (DECL_PRESERVE_P (decl))
vnode->symbol.force_output = true;
--- 761,767 ----
{
tree decl = vnode->symbol.decl;
if (DECL_EXTERNAL (decl)
! && DECL_INITIAL (decl))
varpool_finalize_decl (decl);
if (DECL_PRESERVE_P (decl))
vnode->symbol.force_output = true;
Index: testsuite/gcc.dg/tree-ssa/attr-alias-2.c
===================================================================
*** testsuite/gcc.dg/tree-ssa/attr-alias-2.c (revision 0)
--- testsuite/gcc.dg/tree-ssa/attr-alias-2.c (revision 0)
***************
*** 0 ****
--- 1,10 ----
+ /* { dg-do compile } */
+ /* { dg-require-alias "" } */
+ /* { dg-options "-O2 -fdump-tree-optimized" } */
+ static int a=4;
+ static int b __attribute__ ((alias("a")));
+ main()
+ {
+ return b+a;
+ }
+ /* { dg-final { scan-tree-dump "return 8" "optimized" } } */
Index: lto-cgraph.c
===================================================================
*** lto-cgraph.c (revision 200147)
--- lto-cgraph.c (working copy)
*************** compute_ltrans_boundary (lto_symtab_enco
*** 766,775 ****
symtab_node node = lto_symtab_encoder_deref (encoder, i);
if (varpool_node *vnode = dyn_cast <varpool_node> (node))
{
! if (DECL_INITIAL (vnode->symbol.decl)
! && !lto_symtab_encoder_encode_initializer_p (encoder,
! vnode)
! && const_value_known_p (vnode->symbol.decl))
{
lto_set_symtab_encoder_encode_initializer (encoder, vnode);
add_references (encoder, &vnode->symbol.ref_list);
--- 766,774 ----
symtab_node node = lto_symtab_encoder_deref (encoder, i);
if (varpool_node *vnode = dyn_cast <varpool_node> (node))
{
! if (!lto_symtab_encoder_encode_initializer_p (encoder,
! vnode)
! && ctor_for_folding (vnode->symbol.decl) != error_mark_node)
{
lto_set_symtab_encoder_encode_initializer (encoder, vnode);
add_references (encoder, &vnode->symbol.ref_list);
Index: expr.c
===================================================================
*** expr.c (revision 200147)
--- expr.c (working copy)
*************** expand_expr_real_1 (tree exp, rtx target
*** 9698,9703 ****
--- 9698,9704 ----
{
tree array = treeop0;
tree index = treeop1;
+ tree init;
/* Fold an expression like: "foo"[2].
This is not done in fold so it won't happen inside &.
*************** expand_expr_real_1 (tree exp, rtx target
*** 9744,9819 ****
&& modifier != EXPAND_INITIALIZER
&& modifier != EXPAND_MEMORY
&& TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
! && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
! && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK
! && const_value_known_p (array))
{
! if (TREE_CODE (index) == INTEGER_CST)
{
! tree init = DECL_INITIAL (array);
! if (TREE_CODE (init) == CONSTRUCTOR)
! {
! unsigned HOST_WIDE_INT ix;
! tree field, value;
! FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
! field, value)
! if (tree_int_cst_equal (field, index))
{
! if (TREE_SIDE_EFFECTS (value))
break;
! if (TREE_CODE (value) == CONSTRUCTOR)
! {
! /* If VALUE is a CONSTRUCTOR, this
! optimization is only useful if
! this doesn't store the CONSTRUCTOR
! into memory. If it does, it is more
! efficient to just load the data from
! the array directly. */
! rtx ret = expand_constructor (value, target,
! modifier, true);
! if (ret == NULL_RTX)
! break;
! }
! return expand_expr (fold (value), target, tmode,
! modifier);
! }
! }
! else if(TREE_CODE (init) == STRING_CST)
{
! tree index1 = index;
! tree low_bound = array_ref_low_bound (exp);
! index1 = fold_convert_loc (loc, sizetype,
! treeop1);
!
! /* Optimize the special-case of a zero lower bound.
!
! We convert the low_bound to sizetype to avoid some problems
! with constant folding. (E.g. suppose the lower bound is 1,
! and its mode is QI. Without the conversion,l (ARRAY
! +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
! +INDEX), which becomes (ARRAY+255+INDEX). Opps!) */
!
! if (! integer_zerop (low_bound))
! index1 = size_diffop_loc (loc, index1,
! fold_convert_loc (loc, sizetype,
! low_bound));
!
! if (0 > compare_tree_int (index1,
! TREE_STRING_LENGTH (init)))
! {
! tree type = TREE_TYPE (TREE_TYPE (init));
! enum machine_mode mode = TYPE_MODE (type);
! if (GET_MODE_CLASS (mode) == MODE_INT
! && GET_MODE_SIZE (mode) == 1)
! return gen_int_mode (TREE_STRING_POINTER (init)
! [TREE_INT_CST_LOW (index1)],
! mode);
! }
}
}
}
--- 9745,9816 ----
&& modifier != EXPAND_INITIALIZER
&& modifier != EXPAND_MEMORY
&& TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
! && TREE_CODE (index) == INTEGER_CST
! && (TREE_CODE (array) == VAR_DECL
! || TREE_CODE (array) == CONST_DECL)
! && (init = ctor_for_folding (array)) != error_mark_node)
{
! if (TREE_CODE (init) == CONSTRUCTOR)
{
! unsigned HOST_WIDE_INT ix;
! tree field, value;
! FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
! field, value)
! if (tree_int_cst_equal (field, index))
! {
! if (TREE_SIDE_EFFECTS (value))
! break;
! if (TREE_CODE (value) == CONSTRUCTOR)
{
! /* If VALUE is a CONSTRUCTOR, this
! optimization is only useful if
! this doesn't store the CONSTRUCTOR
! into memory. If it does, it is more
! efficient to just load the data from
! the array directly. */
! rtx ret = expand_constructor (value, target,
! modifier, true);
! if (ret == NULL_RTX)
break;
+ }
! return expand_expr (fold (value), target, tmode,
! modifier);
! }
! }
! else if(TREE_CODE (init) == STRING_CST)
! {
! tree index1 = index;
! tree low_bound = array_ref_low_bound (exp);
! index1 = fold_convert_loc (loc, sizetype,
! treeop1);
!
! /* Optimize the special-case of a zero lower bound.
!
! We convert the low_bound to sizetype to avoid some problems
! with constant folding. (E.g. suppose the lower bound is 1,
! and its mode is QI. Without the conversion,l (ARRAY
! +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
! +INDEX), which becomes (ARRAY+255+INDEX). Opps!) */
!
! if (! integer_zerop (low_bound))
! index1 = size_diffop_loc (loc, index1,
! fold_convert_loc (loc, sizetype,
! low_bound));
! if (0 > compare_tree_int (index1,
! TREE_STRING_LENGTH (init)))
{
! tree type = TREE_TYPE (TREE_TYPE (init));
! enum machine_mode mode = TYPE_MODE (type);
! if (GET_MODE_CLASS (mode) == MODE_INT
! && GET_MODE_SIZE (mode) == 1)
! return gen_int_mode (TREE_STRING_POINTER (init)
! [TREE_INT_CST_LOW (index1)],
! mode);
}
}
}
*************** string_constant (tree arg, tree *ptr_off
*** 10676,10692 ****
|| TREE_CODE (array) == CONST_DECL)
{
int length;
/* Variables initialized to string literals can be handled too. */
! if (!const_value_known_p (array)
! || !DECL_INITIAL (array)
! || TREE_CODE (DECL_INITIAL (array)) != STRING_CST)
return 0;
/* Avoid const char foo[4] = "abcde"; */
if (DECL_SIZE_UNIT (array) == NULL_TREE
|| TREE_CODE (DECL_SIZE_UNIT (array)) != INTEGER_CST
! || (length = TREE_STRING_LENGTH (DECL_INITIAL (array))) <= 0
|| compare_tree_int (DECL_SIZE_UNIT (array), length) < 0)
return 0;
--- 10673,10690 ----
|| TREE_CODE (array) == CONST_DECL)
{
int length;
+ tree init = ctor_for_folding (array);
/* Variables initialized to string literals can be handled too. */
! if (init == error_mark_node
! || !init
! || TREE_CODE (init) != STRING_CST)
return 0;
/* Avoid const char foo[4] = "abcde"; */
if (DECL_SIZE_UNIT (array) == NULL_TREE
|| TREE_CODE (DECL_SIZE_UNIT (array)) != INTEGER_CST
! || (length = TREE_STRING_LENGTH (init)) <= 0
|| compare_tree_int (DECL_SIZE_UNIT (array), length) < 0)
return 0;
*************** string_constant (tree arg, tree *ptr_off
*** 10699,10705 ****
return 0;
*ptr_offset = offset;
! return DECL_INITIAL (array);
}
return 0;
--- 10697,10703 ----
return 0;
*ptr_offset = offset;
! return init;
}
return 0;
Index: tree-ssa-loop-ivcanon.c
===================================================================
*** tree-ssa-loop-ivcanon.c (revision 200147)
--- tree-ssa-loop-ivcanon.c (working copy)
*************** constant_after_peeling (tree op, gimple
*** 174,180 ****
while (handled_component_p (base))
base = TREE_OPERAND (base, 0);
if ((DECL_P (base)
! && const_value_known_p (base))
|| CONSTANT_CLASS_P (base))
{
/* If so, see if we understand all the indices. */
--- 174,180 ----
while (handled_component_p (base))
base = TREE_OPERAND (base, 0);
if ((DECL_P (base)
! && ctor_for_folding (base) != error_mark_node)
|| CONSTANT_CLASS_P (base))
{
/* If so, see if we understand all the indices. */
Index: ipa.c
===================================================================
*** ipa.c (revision 200147)
--- ipa.c (working copy)
*************** process_references (struct ipa_ref_list
*** 145,151 ****
constant folding. Keep references alive so partitioning
knows about potential references. */
|| (TREE_CODE (node->symbol.decl) == VAR_DECL
! && flag_wpa && const_value_known_p (node->symbol.decl)))))
pointer_set_insert (reachable, node);
enqueue_node ((symtab_node) node, first, reachable);
}
--- 145,153 ----
constant folding. Keep references alive so partitioning
knows about potential references. */
|| (TREE_CODE (node->symbol.decl) == VAR_DECL
! && flag_wpa
! && ctor_for_folding (node->symbol.decl)
! != error_mark_node))))
pointer_set_insert (reachable, node);
enqueue_node ((symtab_node) node, first, reachable);
}
*************** symtab_remove_unreachable_nodes (bool be
*** 400,405 ****
--- 402,408 ----
}
else if (!pointer_set_contains (reachable, vnode))
{
+ tree init;
if (vnode->symbol.definition)
{
if (file)
*************** symtab_remove_unreachable_nodes (bool be
*** 411,418 ****
vnode->symbol.aux = NULL;
/* Keep body if it may be useful for constant folding. */
! if (!const_value_known_p (vnode->symbol.decl))
varpool_remove_initializer (vnode);
ipa_remove_all_references (&vnode->symbol.ref_list);
}
else
--- 414,423 ----
vnode->symbol.aux = NULL;
/* Keep body if it may be useful for constant folding. */
! if ((init = ctor_for_folding (vnode->symbol.decl)) == error_mark_node)
varpool_remove_initializer (vnode);
+ else
+ DECL_INITIAL (vnode->symbol.decl) = init;
ipa_remove_all_references (&vnode->symbol.ref_list);
}
else
Index: ipa-inline-analysis.c
===================================================================
*** ipa-inline-analysis.c (revision 200147)
--- ipa-inline-analysis.c (working copy)
*************** param_change_prob (gimple stmt, int i)
*** 2106,2113 ****
struct record_modified_bb_info info;
bitmap_iterator bi;
unsigned index;
! if (const_value_known_p (base))
return 0;
if (!bb->frequency)
return REG_BR_PROB_BASE;
--- 2106,2114 ----
struct record_modified_bb_info info;
bitmap_iterator bi;
unsigned index;
+ tree init = ctor_for_folding (base);
! if (init != error_mark_node)
return 0;
if (!bb->frequency)
return REG_BR_PROB_BASE;
Index: gimple-fold.c
===================================================================
*** gimple-fold.c (revision 200147)
--- gimple-fold.c (working copy)
*************** canonicalize_constructor_val (tree cval,
*** 192,200 ****
tree
get_symbol_constant_value (tree sym)
{
! if (const_value_known_p (sym))
{
- tree val = DECL_INITIAL (sym);
if (val)
{
val = canonicalize_constructor_val (unshare_expr (val), sym);
--- 192,200 ----
tree
get_symbol_constant_value (tree sym)
{
! tree val = ctor_for_folding (sym);
! if (val != error_mark_node)
{
if (val)
{
val = canonicalize_constructor_val (unshare_expr (val), sym);
*************** get_base_constructor (tree base, HOST_WI
*** 2695,2713 ****
switch (TREE_CODE (base))
{
case VAR_DECL:
- if (!const_value_known_p (base))
- return NULL_TREE;
-
- /* Fallthru. */
case CONST_DECL:
! if (!DECL_INITIAL (base)
! && (TREE_STATIC (base) || DECL_EXTERNAL (base)))
! return error_mark_node;
! /* Do not return an error_mark_node DECL_INITIAL. LTO uses this
! as special marker (_not_ zero ...) for its own purposes. */
! if (DECL_INITIAL (base) == error_mark_node)
! return NULL_TREE;
! return DECL_INITIAL (base);
case ARRAY_REF:
case COMPONENT_REF:
--- 2695,2712 ----
switch (TREE_CODE (base))
{
case VAR_DECL:
case CONST_DECL:
! {
! tree init = ctor_for_folding (base);
!
! /* Our semantic is exact oposite of ctor_for_folding;
! NULL means unknown, while error_mark_node is 0. */
! if (init == error_mark_node)
! return NULL_TREE;
! if (!init)
! return error_mark_node;
! return init;
! }
case ARRAY_REF:
case COMPONENT_REF:
Index: lto/lto-partition.c
===================================================================
*** lto/lto-partition.c (revision 200147)
--- lto/lto-partition.c (working copy)
*************** add_references_to_partition (ltrans_part
*** 146,152 ****
Recursively look into the initializers of the constant variable and add
references, too. */
else if (is_a <varpool_node> (ref->referred)
! && const_value_known_p (ref->referred->symbol.decl)
&& !lto_symtab_encoder_in_partition_p (part->encoder, ref->referred))
{
if (!part->initializers_visited)
--- 146,152 ----
Recursively look into the initializers of the constant variable and add
references, too. */
else if (is_a <varpool_node> (ref->referred)
! && ctor_for_folding (ref->referred->symbol.decl) != error_mark_node
&& !lto_symtab_encoder_in_partition_p (part->encoder, ref->referred))
{
if (!part->initializers_visited)
Index: varpool.c
===================================================================
*** varpool.c (revision 200147)
--- varpool.c (working copy)
*************** void
*** 66,77 ****
varpool_remove_node (struct varpool_node *node)
{
symtab_unregister_node ((symtab_node)node);
/* Because we remove references from external functions before final compilation,
we may end up removing useful constructors.
FIXME: We probably want to trace boundaries better. */
! if (!const_value_known_p (node->symbol.decl))
varpool_remove_initializer (node);
ggc_free (node);
}
--- 66,80 ----
varpool_remove_node (struct varpool_node *node)
{
symtab_unregister_node ((symtab_node)node);
+ tree init;
/* Because we remove references from external functions before final compilation,
we may end up removing useful constructors.
FIXME: We probably want to trace boundaries better. */
! if ((init = ctor_for_folding (node->symbol.decl)) == error_mark_node)
varpool_remove_initializer (node);
+ else
+ DECL_INITIAL (node->symbol.decl) = init;
ggc_free (node);
}
*************** varpool_remove_initializer (struct varpo
*** 84,90 ****
/* Keep vtables for BINFO folding. */
&& !DECL_VIRTUAL_P (node->symbol.decl)
/* FIXME: http://gcc.gnu.org/PR55395 */
! && debug_info_level == DINFO_LEVEL_NONE)
DECL_INITIAL (node->symbol.decl) = error_mark_node;
}
--- 87,96 ----
/* Keep vtables for BINFO folding. */
&& !DECL_VIRTUAL_P (node->symbol.decl)
/* FIXME: http://gcc.gnu.org/PR55395 */
! && debug_info_level == DINFO_LEVEL_NONE
! /* During LTO streaming we may have multiple nodes
! associated to a given decl. */
! && cgraph_state != CGRAPH_LTO_STREAMING)
DECL_INITIAL (node->symbol.decl) = error_mark_node;
}
*************** dump_varpool_node (FILE *f, struct varpo
*** 104,110 ****
fprintf (f, " output");
if (TREE_READONLY (node->symbol.decl))
fprintf (f, " read-only");
! if (const_value_known_p (node->symbol.decl))
fprintf (f, " const-value-known");
fprintf (f, "\n");
}
--- 110,116 ----
fprintf (f, " output");
if (TREE_READONLY (node->symbol.decl))
fprintf (f, " read-only");
! if (ctor_for_folding (node->symbol.decl) != error_mark_node)
fprintf (f, " const-value-known");
fprintf (f, "\n");
}
*************** varpool_node_for_asm (tree asmname)
*** 139,182 ****
}
/* Return if DECL is constant and its initial value is known (so we can do
! constant folding using DECL_INITIAL (decl)). */
! bool
! const_value_known_p (tree decl)
{
if (TREE_CODE (decl) != VAR_DECL
! &&TREE_CODE (decl) != CONST_DECL)
! return false;
if (TREE_CODE (decl) == CONST_DECL
|| DECL_IN_CONSTANT_POOL (decl))
! return true;
!
! gcc_assert (TREE_CODE (decl) == VAR_DECL);
! if (!TREE_READONLY (decl) || TREE_THIS_VOLATILE (decl))
! return false;
! /* Gimplifier takes away constructors of local vars */
if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
! return DECL_INITIAL (decl) != NULL;
! gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
/* Variables declared 'const' without an initializer
have zero as the initializer if they may not be
overridden at link or run time. */
! if (!DECL_INITIAL (decl)
! && (DECL_EXTERNAL (decl)
! || decl_replaceable_p (decl)))
! return false;
/* Variables declared `const' with an initializer are considered
to not be overwritable with different initializer by default.
??? Previously we behaved so for scalar variables but not for array
accesses. */
! return true;
}
/* Add the variable DECL to the varpool.
--- 145,237 ----
}
/* Return if DECL is constant and its initial value is known (so we can do
! constant folding using DECL_INITIAL (decl)).
! Return ERROR_MARK_NODE when value is unknown. */
! tree
! ctor_for_folding (tree decl)
{
+ struct varpool_node *node, *real_node;
+ tree real_decl;
+
if (TREE_CODE (decl) != VAR_DECL
! && TREE_CODE (decl) != CONST_DECL)
! return error_mark_node;
if (TREE_CODE (decl) == CONST_DECL
|| DECL_IN_CONSTANT_POOL (decl))
! return DECL_INITIAL (decl);
! if (TREE_THIS_VOLATILE (decl))
! return error_mark_node;
! /* Do not care about automatic variables. Those are never initialized
! anyway, because gimplifier exapnds the code*/
if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
! {
! gcc_assert (!TREE_PUBLIC (decl));
! return error_mark_node;
! }
!
! gcc_assert (TREE_CODE (decl) == VAR_DECL);
!
! node = varpool_get_node (decl);
! if (node)
! {
! real_node = varpool_variable_node (node);
! real_decl = real_node->symbol.decl;
! }
! else
! real_decl = decl;
! /* See if we are dealing with alias.
! In most cases alias is just alternative symbol pointing to a given
! constructor. This allows us to use interposition rules of DECL
! constructor of REAL_NODE. However weakrefs are special by being just
! alternative name of their target (if defined). */
! if (decl != real_decl)
! {
! gcc_assert (!DECL_INITIAL (decl)
! || DECL_INITIAL (decl) == error_mark_node);
! if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
! {
! node = varpool_alias_target (node);
! decl = node->symbol.decl;
! }
! }
!
! /* Vtables are defined by their types and must match no matter of interposition
! rules. */
! if (DECL_VIRTUAL_P (real_decl))
! {
! gcc_checking_assert (TREE_READONLY (real_decl));
! return DECL_INITIAL (real_decl);
! }
!
! /* If thre is no constructor, we have nothing to do. */
! if (DECL_INITIAL (real_decl) == error_mark_node)
! return error_mark_node;
!
! /* Non-readonly alias of readonly variable is also de-facto readonly,
! because the variable itself is in readonly section.
! We also honnor READONLY flag on alias assuming that user knows
! what he is doing. */
! if (!TREE_READONLY (decl) && !TREE_READONLY (real_decl))
! return error_mark_node;
/* Variables declared 'const' without an initializer
have zero as the initializer if they may not be
overridden at link or run time. */
! if (!DECL_INITIAL (real_decl)
! && (DECL_EXTERNAL (decl) || decl_replaceable_p (decl)))
! return error_mark_node;
/* Variables declared `const' with an initializer are considered
to not be overwritable with different initializer by default.
??? Previously we behaved so for scalar variables but not for array
accesses. */
! return DECL_INITIAL (real_decl);
}
/* Add the variable DECL to the varpool.