cgraph.h (const_value_known_p): Replace by ...
authorJan Hubicka <jh@suse.cz>
Wed, 19 Jun 2013 18:06:12 +0000 (20:06 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Wed, 19 Jun 2013 18:06:12 +0000 (18:06 +0000)
* 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.

From-SVN: r200211

14 files changed:
gcc/ChangeLog
gcc/cgraph.h
gcc/cgraphunit.c
gcc/expr.c
gcc/gimple-fold.c
gcc/ipa-inline-analysis.c
gcc/ipa.c
gcc/lto-cgraph.c
gcc/lto/ChangeLog
gcc/lto/lto-partition.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/attr-alias-2.c [new file with mode: 0644]
gcc/tree-ssa-loop-ivcanon.c
gcc/varpool.c

index 8b6bc6f964b1746fa0a4fa55243ef8c4a056b0dc..b2c2ee70afcf1329fd1240507b8220c3f10462b4 100644 (file)
@@ -1,3 +1,23 @@
+2013-06-19  Jan Hubicka  <jh@suse.cz>
+
+       * 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.
+
 2013-06-19  Jakub Jelinek  <jakub@redhat.com>
 
        PR driver/57651
index 62591890182dc82df7fe10a5711fb8ab8d603048..ef2a2a0a348cf2b0a6cce2b5da7b385133fa47e7 100644 (file)
@@ -797,7 +797,7 @@ void varpool_analyze_node (struct varpool_node *);
 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);
+tree ctor_for_folding (tree);
 bool varpool_for_node_and_aliases (struct varpool_node *,
                                   bool (*) (struct varpool_node *, void *),
                                   void *, bool);
index 51365eb167fcd5b4ef7b54b8f793183c2b903ecc..731a0e91294c9d5fd0eadb57049d26b34039ca5c 100644 (file)
@@ -762,8 +762,7 @@ process_function_and_variable_attributes (struct cgraph_node *first,
     {
       tree decl = vnode->symbol.decl;
       if (DECL_EXTERNAL (decl)
-         && DECL_INITIAL (decl)
-         && const_value_known_p (decl))
+         && DECL_INITIAL (decl))
        varpool_finalize_decl (decl);
       if (DECL_PRESERVE_P (decl))
        vnode->symbol.force_output = true;
index 2a7824b62a2f66d39ce3f4206dbb340666d9565d..bce96c9c2272d7ab10eefb2be3585ef28f3648d2 100644 (file)
@@ -9698,6 +9698,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       {
        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 &.
@@ -9744,76 +9745,72 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                 && 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))
+                && 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 (index) == INTEGER_CST)
+           if (TREE_CODE (init) == CONSTRUCTOR)
              {
-               tree init = DECL_INITIAL (array);
+               unsigned HOST_WIDE_INT ix;
+               tree field, value;
 
-               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;
 
-                   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
-                                             field, value)
-                     if (tree_int_cst_equal (field, index))
+                     if (TREE_CODE (value) == CONSTRUCTOR)
                        {
-                         if (TREE_SIDE_EFFECTS (value))
+                         /* 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;
-
-                         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)
+
+                     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 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);
-                     }
+                   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);
                  }
              }
          }
@@ -10676,17 +10673,18 @@ string_constant (tree arg, tree *ptr_offset)
           || TREE_CODE (array) == CONST_DECL)
     {
       int length;
+      tree init = ctor_for_folding (array);
 
       /* 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)
+      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 (DECL_INITIAL (array))) <= 0
+         || (length = TREE_STRING_LENGTH (init)) <= 0
          || compare_tree_int (DECL_SIZE_UNIT (array), length) < 0)
        return 0;
 
@@ -10699,7 +10697,7 @@ string_constant (tree arg, tree *ptr_offset)
        return 0;
 
       *ptr_offset = offset;
-      return DECL_INITIAL (array);
+      return init;
     }
 
   return 0;
index 60fca6bc28541c7833b8b0ea870ec5e748212959..b6d22b3a7c835012edcbf84af4554863525efbaa 100644 (file)
@@ -192,9 +192,9 @@ canonicalize_constructor_val (tree cval, tree from_decl)
 tree
 get_symbol_constant_value (tree sym)
 {
-  if (const_value_known_p (sym))
+  tree val = ctor_for_folding (sym);
+  if (val != error_mark_node)
     {
-      tree val = DECL_INITIAL (sym);
       if (val)
        {
          val = canonicalize_constructor_val (unshare_expr (val), sym);
@@ -2695,19 +2695,18 @@ get_base_constructor (tree base, HOST_WIDE_INT *bit_offset,
   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);
+      {
+       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 a25f51755e3b0b46d3d4f2a955e9c761ce98e1a7..9a3629285fb9f2e12065b9d49231c48c02c70ea2 100644 (file)
@@ -2106,8 +2106,9 @@ param_change_prob (gimple stmt, int i)
       struct record_modified_bb_info info;
       bitmap_iterator bi;
       unsigned index;
+      tree init = ctor_for_folding (base);
 
-      if (const_value_known_p (base))
+      if (init != error_mark_node)
        return 0;
       if (!bb->frequency)
        return REG_BR_PROB_BASE;
index 0f2a5c8b424d0f9594d8b520c33b5b25c6b347de..7c0d495695ba6cbc27b60aa270ef3107fef91d8b 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -145,7 +145,9 @@ process_references (struct ipa_ref_list *list,
                     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)))))
+                     && flag_wpa
+                     && ctor_for_folding (node->symbol.decl)
+                        != error_mark_node))))
        pointer_set_insert (reachable, node);
       enqueue_node ((symtab_node) node, first, reachable);
     }
@@ -400,6 +402,7 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
        }
       else if (!pointer_set_contains (reachable, vnode))
         {
+         tree init;
          if (vnode->symbol.definition)
            {
              if (file)
@@ -411,8 +414,10 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
          vnode->symbol.aux = NULL;
 
          /* Keep body if it may be useful for constant folding.  */
-         if (!const_value_known_p (vnode->symbol.decl))
+         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 e3f8880be7668a5f90369b21ead29e88ba94ada6..2122f705845b4f4f11a77fb48aa511bfe26d8fad 100644 (file)
@@ -766,10 +766,9 @@ compute_ltrans_boundary (lto_symtab_encoder_t in_encoder)
       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))
+         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 aeda657fdba34f7e27cf470408d0cd59728a99c4..2723678f27585ad649de9ae673f3fb00b188a3fb 100644 (file)
@@ -1,3 +1,8 @@
+2013-06-19  Jan Hubicka  <jh@suse.cz>
+
+       * lto-partition.c (add_references_to_partition): Use
+       ctor_for_folding.
+
 2013-06-18  Richard Biener  <rguenther@suse.de>
 
        * lto.c (lto_register_var_decl_in_symtab): Pass in cache index
index 6f4538061558766dd331af71da5464f83f0fce2c..ffc8da3e94e35ef9a5d755b71be8a1d5e7dc3cd9 100644 (file)
@@ -146,7 +146,7 @@ add_references_to_partition (ltrans_partition part, symtab_node node)
        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)
+            && 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 f731837cb7380220cf84dbd3e6634897702a9ec6..baae9b9447e1f787e8589e43f7cc7aac8c5d22b4 100644 (file)
@@ -1,3 +1,7 @@
+2013-06-19  Jan Hubicka  <jh@suse.cz>
+
+       * gcc.dg/tree-ssa/attr-alias-2.c: New testcase.
+
 2013-06-19  Balaji V. Iyer  <balaji.v.iyer@intel.com>
 
        * c-c++-common/cilk-plus/AN/builtin_fn_custom.c: Replaced all the
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/attr-alias-2.c b/gcc/testsuite/gcc.dg/tree-ssa/attr-alias-2.c
new file mode 100644 (file)
index 0000000..50623a4
--- /dev/null
@@ -0,0 +1,30 @@
+/* { 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" } } */
+/* { 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" } } */
+/* { 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 45774e60dd8e82654d57191874d2e31761bd4e6f..91cf8c16a3234caee78fd8d4a0e2b18d0facce14 100644 (file)
@@ -174,7 +174,7 @@ constant_after_peeling (tree op, gimple stmt, struct loop *loop)
       while (handled_component_p (base))
        base = TREE_OPERAND (base, 0);
       if ((DECL_P (base)
-          && const_value_known_p (base))
+          && ctor_for_folding (base) != error_mark_node)
          || CONSTANT_CLASS_P (base))
        {
          /* If so, see if we understand all the indices.  */
index 80e98b3dd5dde6d4441bcc1b0e4ebebfd9c9169e..b426757ec8463feef14a304fd45313931790067d 100644 (file)
@@ -66,12 +66,15 @@ void
 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 (!const_value_known_p (node->symbol.decl))
+  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);
 }
 
@@ -109,7 +112,7 @@ dump_varpool_node (FILE *f, struct varpool_node *node)
     fprintf (f, " output");
   if (TREE_READONLY (node->symbol.decl))
     fprintf (f, " read-only");
-  if (const_value_known_p (node->symbol.decl))
+  if (ctor_for_folding (node->symbol.decl) != error_mark_node)
     fprintf (f, " const-value-known");
   fprintf (f, "\n");
 }
@@ -144,44 +147,93 @@ varpool_node_for_asm (tree asmname)
 }
 
 /* Return if DECL is constant and its initial value is known (so we can do
-   constant folding using DECL_INITIAL (decl)).  */
+   constant folding using DECL_INITIAL (decl)).
+   Return ERROR_MARK_NODE when value is unknown.  */
 
-bool
-const_value_known_p (tree decl)
+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 false;
+      && TREE_CODE (decl) != CONST_DECL)
+    return error_mark_node;
 
   if (TREE_CODE (decl) == CONST_DECL
       || DECL_IN_CONSTANT_POOL (decl))
-    return true;
+    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);
 
-  if (!TREE_READONLY (decl) || TREE_THIS_VOLATILE (decl))
-    return false;
+  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;
+       }
+    }
 
-  /* Gimplifier takes away constructors of local vars  */
-  if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
-    return DECL_INITIAL (decl) != NULL;
+  /* 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;
 
-  gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
+  /* 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 (decl)
-      && (DECL_EXTERNAL (decl)
-         || decl_replaceable_p (decl)))
-    return false;
+  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 true;
+  return DECL_INITIAL (real_decl);
 }
 
 /* Add the variable DECL to the varpool.