OSDN Git Service

PR driver/15303
[pf3gnuchains/gcc-fork.git] / gcc / fortran / trans-common.c
index afcbb1c..1162636 100644 (file)
@@ -1,5 +1,5 @@
 /* Common block and equivalence list handling
-   Copyright (C) 2000, 2003, 2004, 2005, 2006, 2007
+   Copyright (C) 2000, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
    Contributed by Canqun Yang <canqun@nudt.edu.cn>
 
@@ -7,7 +7,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */     
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */     
 
 /* The core algorithm is based on Andy Vaught's g95 tree.  Also the
    way to build UNION_TYPE is borrowed from Richard Henderson.
@@ -97,11 +96,10 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "target.h"
-#include "tree.h"
-#include "toplev.h"
 #include "tm.h"
-#include "rtl.h"
+#include "tree.h"
+#include "toplev.h"    /* For exact_log2.  */
+#include "output.h"    /* For decl_default_tls_model.  */
 #include "gfortran.h"
 #include "trans.h"
 #include "trans-types.h"
@@ -133,7 +131,7 @@ get_segment_info (gfc_symbol * sym, HOST_WIDE_INT offset)
 
   /* Make sure we've got the character length.  */
   if (sym->ts.type == BT_CHARACTER)
-    gfc_conv_const_charlen (sym->ts.cl);
+    gfc_conv_const_charlen (sym->ts.u.cl);
 
   /* Create the segment_info and fill it in.  */
   s = (segment_info *) gfc_getmem (sizeof (segment_info));
@@ -217,13 +215,37 @@ add_segments (segment_info *list, segment_info *v)
   return list;
 }
 
+
 /* Construct mangled common block name from symbol name.  */
 
+/* We need the bind(c) flag to tell us how/if we should mangle the symbol
+   name.  There are few calls to this function, so few places that this
+   would need to be added.  At the moment, there is only one call, in
+   build_common_decl().  We can't attempt to look up the common block
+   because we may be building it for the first time and therefore, it won't
+   be in the common_root.  We also need the binding label, if it's bind(c).
+   Therefore, send in the pointer to the common block, so whatever info we
+   have so far can be used.  All of the necessary info should be available
+   in the gfc_common_head by now, so it should be accurate to test the
+   isBindC flag and use the binding label given if it is bind(c).
+
+   We may NOT know yet if it's bind(c) or not, but we can try at least.
+   Will have to figure out what to do later if it's labeled bind(c)
+   after this is called.  */
+
 static tree
-gfc_sym_mangled_common_id (const char *name)
+gfc_sym_mangled_common_id (gfc_common_head *com)
 {
   int has_underscore;
   char mangled_name[GFC_MAX_MANGLED_SYMBOL_LEN + 1];
+  char name[GFC_MAX_SYMBOL_LEN + 1];
+
+  /* Get the name out of the common block pointer.  */
+  strcpy (name, com->name);
+
+  /* If we're suppose to do a bind(c).  */
+  if (com->is_bind_c == 1 && com->binding_label[0] != '\0')
+    return get_identifier (com->binding_label);
 
   if (strcmp (name, BLANK_COMMON_NAME) == 0)
     return get_identifier (name);
@@ -255,8 +277,8 @@ build_field (segment_info *h, tree union_type, record_layout_info rli)
   unsigned HOST_WIDE_INT desired_align, known_align;
 
   name = get_identifier (h->sym->name);
-  field = build_decl (FIELD_DECL, name, h->field);
-  gfc_set_decl_location (field, &h->sym->declared_at);
+  field = build_decl (h->sym->declared_at.lb->location,
+                     FIELD_DECL, name, h->field);
   known_align = (offset & -offset) * BITS_PER_UNIT;
   if (known_align == 0 || known_align > BIGGEST_ALIGNMENT)
     known_align = BIGGEST_ALIGNMENT;
@@ -295,6 +317,15 @@ build_field (segment_info *h, tree union_type, record_layout_info rli)
       GFC_DECL_ASSIGN_ADDR (field) = pushdecl_top_level (addr);
     }
 
+  /* If this field is volatile, mark it.  */
+  if (h->sym->attr.volatile_)
+    {
+      tree new_type;
+      TREE_THIS_VOLATILE (field) = 1;
+      new_type = build_qualified_type (TREE_TYPE (field), TYPE_QUAL_VOLATILE);
+      TREE_TYPE (field) = new_type;
+    }
+
   h->field = field;
 }
 
@@ -317,7 +348,8 @@ build_equiv_decl (tree union_type, bool is_init, bool is_saved)
     }
 
   snprintf (name, sizeof (name), "equiv.%d", serial++);
-  decl = build_decl (VAR_DECL, get_identifier (name), union_type);
+  decl = build_decl (input_location,
+                    VAR_DECL, get_identifier (name), union_type);
   DECL_ARTIFICIAL (decl) = 1;
   DECL_IGNORED_P (decl) = 1;
 
@@ -360,14 +392,18 @@ build_common_decl (gfc_common_head *com, tree union_type, bool is_init)
       tree size = TYPE_SIZE_UNIT (union_type);
       if (tree_int_cst_lt (DECL_SIZE_UNIT (decl), size))
         {
-          /* Named common blocks of the same name shall be of the same size
-             in all scoping units of a program in which they appear, but
-             blank common blocks may be of different sizes.  */
-          if (strcmp (com->name, BLANK_COMMON_NAME))
+         /* Named common blocks of the same name shall be of the same size
+            in all scoping units of a program in which they appear, but
+            blank common blocks may be of different sizes.  */
+         if (strcmp (com->name, BLANK_COMMON_NAME))
            gfc_warning ("Named COMMON block '%s' at %L shall be of the "
                         "same size", com->name, &com->where);
-          DECL_SIZE_UNIT (decl) = size;
-        }
+         DECL_SIZE (decl) = TYPE_SIZE (union_type);
+         DECL_SIZE_UNIT (decl) = size;
+         DECL_MODE (decl) = TYPE_MODE (union_type);
+         TREE_TYPE (decl) = union_type;
+         layout_decl (decl, 0);
+       }
      }
 
   /* If this common block has been declared in a previous program unit,
@@ -379,11 +415,26 @@ build_common_decl (gfc_common_head *com, tree union_type, bool is_init)
   /* If there is no backend_decl for the common block, build it.  */
   if (decl == NULL_TREE)
     {
-      decl = build_decl (VAR_DECL, get_identifier (com->name), union_type);
-      SET_DECL_ASSEMBLER_NAME (decl, gfc_sym_mangled_common_id (com->name));
+      decl = build_decl (input_location,
+                        VAR_DECL, get_identifier (com->name), union_type);
+      gfc_set_decl_assembler_name (decl, gfc_sym_mangled_common_id (com));
       TREE_PUBLIC (decl) = 1;
       TREE_STATIC (decl) = 1;
-      DECL_ALIGN (decl) = BIGGEST_ALIGNMENT;
+      DECL_IGNORED_P (decl) = 1;
+      if (!com->is_bind_c)
+       DECL_ALIGN (decl) = BIGGEST_ALIGNMENT;
+      else
+        {
+         /* Do not set the alignment for bind(c) common blocks to
+            BIGGEST_ALIGNMENT because that won't match what C does.  Also,
+            for common blocks with one element, the alignment must be
+            that of the field within the common block in order to match
+            what C will do.  */
+         tree field = NULL_TREE;
+         field = TYPE_FIELDS (TREE_TYPE (decl));
+         if (TREE_CHAIN (field) == NULL_TREE)
+           DECL_ALIGN (decl) = TYPE_ALIGN (TREE_TYPE (field));
+       }
       DECL_USER_ALIGN (decl) = 0;
       GFC_DECL_COMMON_OR_EQUIV (decl) = 1;
 
@@ -480,8 +531,8 @@ get_init_field (segment_info *head, tree union_type, tree *field_init,
   tmp = build_range_type (gfc_array_index_type,
                          gfc_index_zero_node, tmp);
   tmp = build_array_type (type, tmp);
-  field = build_decl (FIELD_DECL, NULL_TREE, tmp);
-  gfc_set_decl_location (field, &gfc_current_locus);
+  field = build_decl (gfc_current_locus.lb->location,
+                     FIELD_DECL, NULL_TREE, tmp);
 
   known_align = BIGGEST_ALIGNMENT;
 
@@ -501,7 +552,6 @@ get_init_field (segment_info *head, tree union_type, tree *field_init,
 
   init = build_constructor (TREE_TYPE (field), v);
   TREE_CONSTANT (init) = 1;
-  TREE_INVARIANT (init) = 1;
 
   *field_init = init;
 
@@ -588,7 +638,6 @@ create_common (gfc_common_head *com, segment_info *head, bool saw_equiv)
   if (is_init)
     {
       tree ctor, tmp;
-      HOST_WIDE_INT offset = 0;
       VEC(constructor_elt,gc) *v = NULL;
 
       if (field != NULL_TREE && field_init != NULL_TREE)
@@ -604,14 +653,12 @@ create_common (gfc_common_head *com, segment_info *head, bool saw_equiv)
                    s->sym->attr.pointer || s->sym->attr.allocatable);
 
                CONSTRUCTOR_APPEND_ELT (v, s->field, tmp);
-               offset = s->offset + s->length;
              }
          }
 
       gcc_assert (!VEC_empty (constructor_elt, v));
       ctor = build_constructor (union_type, v);
       TREE_CONSTANT (ctor) = 1;
-      TREE_INVARIANT (ctor) = 1;
       TREE_STATIC (ctor) = 1;
       DECL_INITIAL (decl) = ctor;
 
@@ -630,25 +677,32 @@ create_common (gfc_common_head *com, segment_info *head, bool saw_equiv)
     {
       tree var_decl;
 
-      var_decl = build_decl (VAR_DECL, DECL_NAME (s->field),
+      var_decl = build_decl (s->sym->declared_at.lb->location,
+                            VAR_DECL, DECL_NAME (s->field),
                             TREE_TYPE (s->field));
-      gfc_set_decl_location (var_decl, &s->sym->declared_at);
-      TREE_PUBLIC (var_decl) = TREE_PUBLIC (decl);
       TREE_STATIC (var_decl) = TREE_STATIC (decl);
       TREE_USED (var_decl) = TREE_USED (decl);
+      if (s->sym->attr.use_assoc)
+       DECL_IGNORED_P (var_decl) = 1;
       if (s->sym->attr.target)
        TREE_ADDRESSABLE (var_decl) = 1;
       /* This is a fake variable just for debugging purposes.  */
       TREE_ASM_WRITTEN (var_decl) = 1;
-
-      if (com)
+      /* Fake variables are not visible from other translation units. */
+      TREE_PUBLIC (var_decl) = 0;
+
+      /* To preserve identifier names in COMMON, chain to procedure
+         scope unless at top level in a module definition.  */
+      if (com
+          && s->sym->ns->proc_name
+          && s->sym->ns->proc_name->attr.flavor == FL_MODULE)
        var_decl = pushdecl_top_level (var_decl);
       else
        gfc_add_decl_to_function (var_decl);
 
       SET_DECL_VALUE_EXPR (var_decl,
-                          build3 (COMPONENT_REF, TREE_TYPE (s->field),
-                                  decl, s->field, NULL_TREE));
+                          fold_build3 (COMPONENT_REF, TREE_TYPE (s->field),
+                                       decl, s->field, NULL_TREE));
       DECL_HAS_VALUE_EXPR_P (var_decl) = 1;
       GFC_DECL_COMMON_OR_EQUIV (var_decl) = 1;
 
@@ -777,7 +831,7 @@ calculate_offset (gfc_expr *e)
           case AR_ELEMENT:
            n = element_number (&reference->u.ar);
            if (element_type->type == BT_CHARACTER)
-             gfc_conv_const_charlen (element_type->cl);
+             gfc_conv_const_charlen (element_type->u.cl);
            element_size =
               int_size_in_bytes (gfc_typenode_for_spec (element_type));
            offset += n * element_size;
@@ -907,7 +961,7 @@ find_equivalence (segment_info *n)
    segment list multiple times to include indirect equivalences.  Since
    a new segment_info can inserted at the beginning of the segment list,
    depending on its offset, we have to force a final pass through the
-   loop by demanding that completion sees a pass with no matches; ie.
+   loop by demanding that completion sees a pass with no matches; i.e.,
    all symbols with equiv_built set and no new equivalences found.  */
 
 static void
@@ -1008,7 +1062,9 @@ translate_common (gfc_common_head *common, gfc_symbol *var_list)
   bool saw_equiv;
 
   common_segment = NULL;
+  offset = 0;
   current_offset = 0;
+  align = 1;
   max_align = 1;
   saw_equiv = false;
 
@@ -1049,21 +1105,27 @@ translate_common (gfc_common_head *common, gfc_symbol *var_list)
                       "extension to COMMON '%s' at %L", sym->name,
                       common->name, &common->where);
 
-         offset = align_segment (&align);
+         if (gfc_option.flag_align_commons)
+           offset = align_segment (&align);
 
          if (offset & (max_align - 1))
            {
              /* The required offset conflicts with previous alignment
                 requirements.  Insert padding immediately before this
                 segment.  */
-             gfc_warning ("Padding of %d bytes required before '%s' in "
-                          "COMMON '%s' at %L", (int)offset, s->sym->name,
-                          common->name, &common->where);
-           }
-         else
-           {
-             /* Offset the whole common block.  */
-             apply_segment_offset (common_segment, offset);
+             if (gfc_option.warn_align_commons)
+               {
+                 if (strcmp (common->name, BLANK_COMMON_NAME))
+                   gfc_warning ("Padding of %d bytes required before '%s' in "
+                                "COMMON '%s' at %L; reorder elements or use "
+                                "-fno-align-commons", (int)offset,
+                                s->sym->name, common->name, &common->where);
+                 else
+                   gfc_warning ("Padding of %d bytes required before '%s' in "
+                                "COMMON at %L; reorder elements or use "
+                                "-fno-align-commons", (int)offset,
+                                s->sym->name, &common->where);
+               }
            }
 
          /* Apply the offset to the new segments.  */
@@ -1087,10 +1149,16 @@ translate_common (gfc_common_head *common, gfc_symbol *var_list)
       return;
     }
 
-  if (common_segment->offset != 0)
+  if (common_segment->offset != 0 && gfc_option.warn_align_commons)
     {
-      gfc_warning ("COMMON '%s' at %L requires %d bytes of padding at start",
-                  common->name, &common->where, (int)common_segment->offset);
+      if (strcmp (common->name, BLANK_COMMON_NAME))
+       gfc_warning ("COMMON '%s' at %L requires %d bytes of padding at start; "
+                    "reorder elements or use -fno-align-commons",
+                    common->name, &common->where, (int)common_segment->offset);
+      else
+       gfc_warning ("COMMON at %L requires %d bytes of padding at start; "
+                    "reorder elements or use -fno-align-commons",
+                    &common->where, (int)common_segment->offset);
     }
 
   create_common (common, common_segment, saw_equiv);
@@ -1174,14 +1242,7 @@ gfc_trans_common (gfc_namespace *ns)
   if (ns->blank_common.head != NULL)
     {
       c = gfc_get_common_head ();
-
-      /* We've lost the real location, so use the location of the
-        enclosing procedure.  */
-      if (ns->proc_name != NULL)
-       c->where = ns->proc_name->declared_at;
-      else
-       c->where = ns->blank_common.head->common_head->where;
-
+      c->where = ns->blank_common.head->common_head->where;
       strcpy (c->name, BLANK_COMMON_NAME);
       translate_common (c, ns->blank_common.head);
     }