OSDN Git Service

* trans-expr.c: Do not include convert.h, ggc.h, real.h, and gimple.h.
[pf3gnuchains/gcc-fork.git] / gcc / fortran / trans-common.c
index 353afe7..5881113 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>
 
@@ -99,8 +99,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "tree.h"
 #include "toplev.h"
-#include "tm.h"
-#include "rtl.h"
+#include "tm.h"                /* For rtl.h.  */
+#include "rtl.h"       /* For decl_default_tls_model.  */
 #include "gfortran.h"
 #include "trans.h"
 #include "trans-types.h"
@@ -108,12 +108,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "target-memory.h"
 
 
-/* TODO: This is defined in match.h, and probably shouldn't be here also,
-   but we need it for now at least and don't want to include the whole
-   match.h.  */
-gfc_common_head *gfc_get_common (const char *, int);
-
-
 /* Holds a single variable in an equivalence set.  */
 typedef struct segment_info
 {
@@ -138,7 +132,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));
@@ -284,8 +278,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;
@@ -324,6 +318,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;
 }
 
@@ -346,7 +349,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;
 
@@ -395,8 +399,11 @@ build_common_decl (gfc_common_head *com, tree union_type, bool is_init)
          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 (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);
        }
      }
 
@@ -409,11 +416,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));
+      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;
 
@@ -510,8 +532,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;
 
@@ -531,7 +553,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;
 
@@ -618,7 +639,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)
@@ -634,14 +654,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;
 
@@ -660,25 +678,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;
 
@@ -807,7 +832,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;
@@ -937,7 +962,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
@@ -1038,7 +1063,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;
 
@@ -1079,21 +1106,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.  */
@@ -1117,10 +1150,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);
@@ -1204,14 +1243,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);
     }