Hi all,

attached is an updated version of the patch.

Change:

Tobias Burnus wrote:
But for "USE mod_name, only: nml", one is supposed to generate a DW_TAG_imported_declaration. And there I am stuck. For normal variables, the DW_TAG_imported_declaration refers to a DW_TAG_variable die. Analogously, for a namelist one would have to refer to a DW_TAG_namelist die. But such DW_TAG_namelist comes with a DW_TAG_namelist_item list. And for the latter, one needs to have the die of all variables in the namelist. But with use-only the symbols aren't use associate and no decl or die exists. (Failing call tree with the patch: gfc_trans_use_stmts -> dwarf2out_imported_module_or_decl_1 -> force_decl_die.)

With the attached patch, one now generates DW_TAG_namelist with no DW_TAG_namelist_item and sets DW_AT_declaration.

Thus, for (first file)

  module mm
    integer :: ii
    real :: rr
    namelist /nml/ ii, rr
  end module mm


and (second file):

  subroutine test
    use mm, only: nml
    write(*,nml)
  end subroutine test


One now generates (first file):

 <1><1e>: Abbrev Number: 2 (DW_TAG_module)
    <1f>   DW_AT_name        : mm
    <22>   DW_AT_decl_file   : 1
    <23>   DW_AT_decl_line   : 1
    <24>   DW_AT_sibling     : <0x59>
 <2><28>: Abbrev Number: 3 (DW_TAG_variable)
    <29>   DW_AT_name        : ii
    <2c>   DW_AT_decl_file   : 1
    <2d>   DW_AT_decl_line   : 2
    <2e>   DW_AT_linkage_name: (indirect string, offset: 0x15): __mm_MOD_ii
    <32>   DW_AT_type        : <0x59>
    <36>   DW_AT_external    : 1
    <36>   DW_AT_location    : 9 byte block: 3 0 0 0 0 0 0 0 0  (DW_OP_addr: 0)
 <2><40>: Abbrev Number: 3 (DW_TAG_variable)
    <41>   DW_AT_name        : rr
    <44>   DW_AT_decl_file   : 1
    <45>   DW_AT_decl_line   : 2
    <46>   DW_AT_linkage_name: (indirect string, offset: 0x9): __mm_MOD_rr
    <4a>   DW_AT_type        : <0x60>
    <4e>   DW_AT_external    : 1
    <4e>   DW_AT_location    : 9 byte block: 3 4 0 0 0 0 0 0 0  (DW_OP_addr: 4)
 <2><58>: Abbrev Number: 0
 <1><59>: Abbrev Number: 4 (DW_TAG_base_type)
    <5a>   DW_AT_byte_size   : 4
    <5b>   DW_AT_encoding    : 5        (signed)
    <5c>   DW_AT_name        : (indirect string, offset: 0x29): integer(kind=4)
 <1><60>: Abbrev Number: 4 (DW_TAG_base_type)
    <61>   DW_AT_byte_size   : 4
    <62>   DW_AT_encoding    : 4        (float)
    <63>   DW_AT_name        : (indirect string, offset: 0x12c): real(kind=4)
 <1><67>: Abbrev Number: 5 (DW_TAG_namelist)
    <68>   DW_AT_name        : nml
 <2><6c>: Abbrev Number: 6 (DW_TAG_namelist_item)
    <6d>   DW_AT_namelist_items: <0x28>
 <2><71>: Abbrev Number: 6 (DW_TAG_namelist_item)
    <72>   DW_AT_namelist_items: <0x40>

Second file:

  <2><4f>: Abbrev Number: 3 (DW_TAG_imported_declaration)
    <50>   DW_AT_decl_file   : 1
    <51>   DW_AT_decl_line   : 2
    <52>   DW_AT_import      : <0x70>   [Abbrev Number: 6 (DW_TAG_namelist)]
 <2><56>: Abbrev Number: 4 (DW_TAG_lexical_block)
    <57>   DW_AT_low_pc      : 0xb
    <5f>   DW_AT_high_pc     : 0xb0
 <2><67>: Abbrev Number: 0
 <1><68>: Abbrev Number: 5 (DW_TAG_module)
    <69>   DW_AT_name        : mm
    <6c>   DW_AT_declaration : 1
    <6c>   DW_AT_sibling     : <0x76>
 <2><70>: Abbrev Number: 6 (DW_TAG_namelist)
    <71>   DW_AT_name        : nml
    <75>   DW_AT_declaration : 1
 <2><75>: Abbrev Number: 0

Does the dumps look okay? For the first file, DW_TAG_namelist doesn't come directly after DW_TAG_module but after its sibling 0x59; does one still see that "nml" belongs to that module? (On dwarf2out level, context die should point to the module tag, but I don't understand the readelf/eu-readelf output well enough to see whether that's also the case for the generated dwarf.)

I assume that the compiler can see from the DWARF of the second file that "nml" comes from module "mm" and doesn't search the value elsewhere. (It is possible to have multiple namelist with the same name in different modules.)


For previous version, I did an all-language bootstrap + regtesting; for this one, I only build and tested Fortran. I will do a now a full all language bootstrap regtesting. Assuming that it is successful:
OK for the trunk?

Tobias
gcc/
2013-11-24  Tobias Burnus  <bur...@net-b.de>

	PR debug/37132
	* lto-streamer.h (LTO_tags): Add LTO_namelist_decl_ref.
	* tree.def (NAMELIST_DECL): Add.
	* tree.h (NAMELIST_DECL_ASSOCIATED_DECL): New macro.
	* tree.c (initialize_tree_contains_struct): Add asserts for it.
	* dwarf2out.c (gen_namelist_decl): New function.
	(gen_decl_die, dwarf2out_decl): Call it.
	(dwarf2out_imported_module_or_decl_1): Handle NAMELIST_DECL.
	* lto-streamer-in.c (lto_input_tree_ref): Handle NAMELIST_DECL.
	(lto_input_tree_ref, lto_input_tree_1): Update lto_tag_check_range
	call.
	* lto-streamer-out.c (lto_output_tree_ref): Handle NAMELIST_DECL.

gcc/fortran
2013-11-24  Tobias Burnus  <bur...@net-b.de>

	PR debug/37132
	* trans-decl.c (generate_namelist_decl, create_module_nml_decl):
	New static functions.
	(gfc_generate_module_vars, generate_local_vars): Call them.
	(gfc_trans_use_stmts): Handle namelists for debug genertion.

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 3448ec4..0f35591 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3185,6 +3185,7 @@ static inline int is_redundant_typedef (const_tree);
 static bool is_naming_typedef_decl (const_tree);
 static inline dw_die_ref get_context_die (tree);
 static void gen_namespace_die (tree, dw_die_ref);
+static dw_die_ref gen_namelist_decl (tree, dw_die_ref, tree);
 static dw_die_ref gen_decl_die (tree, tree, dw_die_ref);
 static dw_die_ref force_decl_die (tree);
 static dw_die_ref force_type_die (tree);
@@ -20432,6 +20433,11 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
 	gen_namespace_die (decl, context_die);
       break;
 
+    case NAMELIST_DECL:
+      gen_namelist_decl (DECL_NAME (decl), context_die,
+			 NAMELIST_DECL_ASSOCIATED_DECL (decl));
+      break;
+
     default:
       /* Probably some frontend-internal decl.  Assume we don't care.  */
       gcc_assert ((int)TREE_CODE (decl) > NUM_TREE_CODES);
@@ -20522,7 +20528,12 @@ dwarf2out_imported_module_or_decl_1 (tree decl,
 	      gen_type_die_for_member (type, decl,
 				       get_context_die (TYPE_CONTEXT (type)));
 	    }
-	  at_import_die = force_decl_die (decl);
+	  if (TREE_CODE (decl) == NAMELIST_DECL)
+	    at_import_die = gen_namelist_decl (DECL_NAME (decl),
+					 get_context_die (DECL_CONTEXT (decl)),
+					 NULL_TREE);
+	  else
+	    at_import_die = force_decl_die (decl);
 	}
     }
 
@@ -20594,6 +20605,43 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
 
 }
 
+/* Output debug information for namelists.   */
+
+static dw_die_ref
+gen_namelist_decl (tree name, dw_die_ref scope_die, tree item_decls)
+{
+  dw_die_ref nml_die, nml_item_die, nml_item_ref_die;
+  tree value;
+  unsigned i;
+
+  if (debug_info_level <= DINFO_LEVEL_TERSE)
+    return NULL;
+
+  gcc_assert (scope_die != NULL);
+  nml_die = new_die (DW_TAG_namelist, scope_die, NULL);
+  add_AT_string (nml_die, DW_AT_name, IDENTIFIER_POINTER (name));
+
+  /* If there are no item_decls, we have a nondefining namelist, e.g.
+     with USE association; hence, set DW_AT_declaration.  */
+  if (item_decls == NULL_TREE)
+    {
+      add_AT_flag (nml_die, DW_AT_declaration, 1);
+      return nml_die;
+    }
+
+  FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (item_decls), i, value)
+    {
+      nml_item_ref_die = lookup_decl_die (value);
+      if (!nml_item_ref_die)
+	nml_item_ref_die = force_decl_die (value);
+
+      nml_item_die = new_die (DW_TAG_namelist_item, nml_die, NULL);
+      add_AT_die_ref (nml_item_die, DW_AT_namelist_items, nml_item_ref_die);
+    }
+  return nml_die;
+}
+
+
 /* Write the debugging output for DECL.  */
 
 void
@@ -20714,6 +20762,9 @@ dwarf2out_decl (tree decl)
 
       break;
 
+    case NAMELIST_DECL:
+      break;
+
     default:
       return;
     }
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index f974c6e..c1775b3 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -4144,6 +4144,37 @@ gfc_module_add_decl (struct module_htab_entry *entry, tree decl)
 
 static struct module_htab_entry *cur_module;
 
+
+/* Generate debugging symbols for namelists. This function must come after
+   generate_local_decl to ensure that the variables in the namelist are
+   already declared.  */
+
+static tree
+generate_namelist_decl (gfc_symbol * sym)
+{
+  gfc_namelist *nml;
+  tree decl;
+  vec<constructor_elt, va_gc> *nml_decls = NULL;
+
+  gcc_assert (sym->attr.flavor == FL_NAMELIST);
+  for (nml = sym->namelist; nml; nml = nml->next)
+    {
+      if (nml->sym->backend_decl == NULL_TREE)
+	{
+	  nml->sym->attr.referenced = 1;
+	  nml->sym->backend_decl = gfc_get_symbol_decl (nml->sym);
+	}
+      CONSTRUCTOR_APPEND_ELT (nml_decls, NULL_TREE, nml->sym->backend_decl);
+    }
+
+  decl = make_node (NAMELIST_DECL);
+  TREE_TYPE (decl) = void_type_node;
+  NAMELIST_DECL_ASSOCIATED_DECL (decl) = build_constructor (NULL_TREE, nml_decls);
+  DECL_NAME (decl) = get_identifier (sym->name);
+  return decl;
+}
+
+
 /* Output an initialized decl for a module variable.  */
 
 static void
@@ -4333,6 +4364,18 @@ gfc_trans_use_stmts (gfc_namespace * ns)
 		  DECL_IGNORED_P (decl) = 0;
 		  DECL_INITIAL (decl) = NULL_TREE;
 		}
+	      else if (st->n.sym->attr.flavor == FL_NAMELIST
+		       && st->n.sym->attr.use_only
+		       && st->n.sym->module
+		       && strcmp (st->n.sym->module, use_stmt->module_name)
+			  == 0)
+		{
+		  decl = generate_namelist_decl (st->n.sym);
+		  DECL_CONTEXT (decl) = entry->namespace_decl;
+		  DECL_EXTERNAL (decl) = 1;
+		  DECL_IGNORED_P (decl) = 0;
+		  DECL_INITIAL (decl) = NULL_TREE;
+		}
 	      else
 		{
 		  *slot = error_mark_node;
@@ -4610,6 +4653,21 @@ generate_coarray_init (gfc_namespace * ns __attribute((unused)))
 }
 
 
+static void
+create_module_nml_decl (gfc_symbol *sym)
+{
+  if (sym->attr.flavor == FL_NAMELIST)
+    {
+      tree decl = generate_namelist_decl (sym);
+      pushdecl (decl);
+      gcc_assert (sym->ns->proc_name->attr.flavor == FL_MODULE);
+      DECL_CONTEXT (decl) = sym->ns->proc_name->backend_decl;
+      rest_of_decl_compilation (decl, 1, 0);
+      gfc_module_add_decl (cur_module, decl);
+    }
+}
+
+
 /* Generate all the required code for module variables.  */
 
 void
@@ -4628,6 +4686,7 @@ gfc_generate_module_vars (gfc_namespace * ns)
 
   /* Create decls for all the module variables.  */
   gfc_traverse_ns (ns, gfc_create_module_variable);
+  gfc_traverse_ns (ns, create_module_nml_decl);
 
   if (gfc_option.coarray == GFC_FCOARRAY_LIB && has_coarray_vars)
     generate_coarray_init (ns);
@@ -4893,10 +4952,23 @@ generate_local_decl (gfc_symbol * sym)
     sym->backend_decl = gfc_typenode_for_spec (&(sym->ts));
 }
 
+
+static void
+generate_local_nml_decl (gfc_symbol * sym)
+{
+  if (sym->attr.flavor == FL_NAMELIST && !sym->attr.use_assoc)
+    {
+      tree decl = generate_namelist_decl (sym);
+      pushdecl (decl);
+    }
+}
+
+
 static void
 generate_local_vars (gfc_namespace * ns)
 {
   gfc_traverse_ns (ns, generate_local_decl);
+  gfc_traverse_ns (ns, generate_local_nml_decl);
 }
 
 
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 333e815..a4e362b 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -204,7 +204,7 @@ lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
   unsigned HOST_WIDE_INT ix_u;
   tree result = NULL_TREE;
 
-  lto_tag_check_range (tag, LTO_field_decl_ref, LTO_global_decl_ref);
+  lto_tag_check_range (tag, LTO_field_decl_ref, LTO_namelist_decl_ref);
 
   switch (tag)
     {
@@ -248,6 +248,28 @@ lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
       result = lto_file_decl_data_get_var_decl (data_in->file_data, ix_u);
       break;
 
+    case LTO_namelist_decl_ref:
+      {
+	tree tmp;
+	vec<constructor_elt, va_gc> *nml_decls = NULL;
+	unsigned i, n;
+
+	result = make_node (NAMELIST_DECL);
+	TREE_TYPE (result) = void_type_node;
+	DECL_NAME (result) = stream_read_tree (ib, data_in);
+	n = streamer_read_uhwi (ib);
+	for (i = 0; i < n; i++)
+	  {
+	    ix_u = streamer_read_uhwi (ib);
+	    tmp = lto_file_decl_data_get_var_decl (data_in->file_data, ix_u);
+	    gcc_assert (tmp != NULL_TREE);
+	    CONSTRUCTOR_APPEND_ELT (nml_decls, NULL_TREE, tmp);
+	  }
+	NAMELIST_DECL_ASSOCIATED_DECL (result) = build_constructor (NULL_TREE,
+								    nml_decls);
+	break;
+      }
+
     default:
       gcc_unreachable ();
     }
@@ -1240,7 +1262,7 @@ lto_input_tree_1 (struct lto_input_block *ib, struct data_in *data_in,
 
   if (tag == LTO_null)
     result = NULL_TREE;
-  else if (tag >= LTO_field_decl_ref && tag <= LTO_global_decl_ref)
+  else if (tag >= LTO_field_decl_ref && tag <= LTO_namelist_decl_ref)
     {
       /* If TAG is a reference to an indexable tree, the next value
 	 in IB is the index into the table where we expect to find
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 6163d12..e61430f 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -54,6 +54,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 
 
+static void lto_write_tree (struct output_block*, tree, bool);
+
 /* Clear the line info stored in DATA_IN.  */
 
 static void
@@ -250,6 +252,21 @@ lto_output_tree_ref (struct output_block *ob, tree expr)
       lto_output_type_decl_index (ob->decl_state, ob->main_stream, expr);
       break;
 
+    case NAMELIST_DECL:
+      {
+	unsigned i;
+	tree value, tmp;
+
+	streamer_write_record_start (ob, LTO_namelist_decl_ref);
+	stream_write_tree (ob, DECL_NAME (expr), true);
+	tmp = NAMELIST_DECL_ASSOCIATED_DECL (expr);
+	gcc_assert (tmp != NULL_TREE);
+	streamer_write_uhwi (ob, CONSTRUCTOR_ELTS (tmp)->length());
+	FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (tmp), i, value)
+	  lto_output_var_decl_index (ob->decl_state, ob->main_stream, value);
+	break;
+      }
+
     case NAMESPACE_DECL:
       streamer_write_record_start (ob, LTO_namespace_decl_ref);
       lto_output_namespace_decl_index (ob->decl_state, ob->main_stream, expr);
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index 9dac7c9..91bbb93 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -222,7 +222,8 @@ enum LTO_tags
   LTO_const_decl_ref,
   LTO_imported_decl_ref,
   LTO_translation_unit_decl_ref,
-  LTO_global_decl_ref,			/* Do not change.  */
+  LTO_global_decl_ref,
+  LTO_namelist_decl_ref,		/* Do not change.  */
 
   /* This tag must always be last.  */
   LTO_NUM_TAGS
diff --git a/gcc/tree.c b/gcc/tree.c
index d363cfc..da33944 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -551,6 +551,8 @@ initialize_tree_contains_struct (void)
   gcc_assert (tree_contains_struct[FUNCTION_DECL][TS_FUNCTION_DECL]);
   gcc_assert (tree_contains_struct[IMPORTED_DECL][TS_DECL_MINIMAL]);
   gcc_assert (tree_contains_struct[IMPORTED_DECL][TS_DECL_COMMON]);
+  gcc_assert (tree_contains_struct[NAMELIST_DECL][TS_DECL_MINIMAL]);
+  gcc_assert (tree_contains_struct[NAMELIST_DECL][TS_DECL_COMMON]);
 }
 
 
diff --git a/gcc/tree.def b/gcc/tree.def
index 8eecba7..a325c7a 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -377,6 +377,16 @@ DEFTREECODE (NAMESPACE_DECL, "namespace_decl", tcc_declaration, 0)
    IMPORTED_DECL_ASSOCIATED_DECL (NODE) accesses the imported declaration.  */
 DEFTREECODE (IMPORTED_DECL, "imported_decl", tcc_declaration, 0)
 
+/* A namelist declaration.
+   The Fortran FE uses this to represent a namelist statement, e.g.:
+   NAMELIST /namelist-group-name/ namelist-group-object-list.
+   Whenever a declaration import appears in a lexical block, the BLOCK node
+   representing that lexical block in GIMPLE will contain an NAMELIST_DECL
+   node, linked via BLOCK_VARS accessor of the said BLOCK.
+   For a given NODE which code is NAMELIST_DECL,
+   NAMELIST_DECL_ASSOCIATED_DECL (NODE) accesses the imported declaration.  */
+DEFTREECODE (NAMELIST_DECL, "namelist_decl", tcc_declaration, 0)
+
 /* A translation unit.  This is not technically a declaration, since it
    can't be looked up, but it's close enough.  */
 DEFTREECODE (TRANSLATION_UNIT_DECL, "translation_unit_decl",\
diff --git a/gcc/tree.h b/gcc/tree.h
index 68f9826..0c70810 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2670,6 +2670,11 @@ extern vec<tree, va_gc> **decl_debug_args_insert (tree);
 #define IMPORTED_DECL_ASSOCIATED_DECL(NODE) \
 (DECL_INITIAL (IMPORTED_DECL_CHECK (NODE)))
 
+/* Getter of the symbol declaration associated with the
+   NAMELIST_DECL node.  */
+#define NAMELIST_DECL_ASSOCIATED_DECL(NODE) \
+  (DECL_INITIAL (NODE))
+
 /* A STATEMENT_LIST chains statements together in GENERIC and GIMPLE.
    To reduce overhead, the nodes containing the statements are not trees.
    This avoids the overhead of tree_common on all linked list elements.

Reply via email to