This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] fix PR c++/37410


Hello,

When a "using namespace foo;" construct (aka using-directive) happens to be in a lexical block nested in a function, the dwarf info generated by g++ does not take in account the innermost lexical block, but rather attaches the using-directive to the containing function.

This this patch tries to address the problem.

However, I have a problem to come up with a way to write a dejagnu test for this. The test would have to make sure the DW_TAG_imported_module is a child node of its innermost DW_TAG_lexical_block rather than a child of the containing DW_TAG_lexical_block. I have no idea how to write such a test.

Besides that the patch passes regtest on trunk for the x86_64 platform.

Cheers,

Dodji.
    gcc/ChangeLog:
    2008-09-30  Dodji Seketeli  <dodji@redhat.com>
    
    	PR c++/37410
    	* dwarf2out.c (dwarf2out_imported_module_or_decl): Split this
    	  function in two, making it call a new and reusable
    	  dwarf2out_imported_module_or_decl() that takes the containing
    	  BLOCK of the declaration in argument.
    	  (dwarf2out_imported_module_or_decl_real): New function.
    	  (decls_for_scope, gen_decl_die, dwarf2out_decl): Take
    	  IMPORTED_DECL in account.
    	* tree.def: Added IMPORTED_DECL node type.
    	* tree.h: Added accessors for IMPORTED_DECL nodes.
    	* tree.c (init_ttree): Initialise IMPORTED_DECL node type.
    
    gcc/cp/ChangeLog:
    2008-09-30  Dodji Seketeli  <dodji@redhat.com>
    
    	PR c++/37410
    	* cp-gimplify.c (cp_gimplify_expr): For each USING_STMT
    	  make sure an IMPORTED_DECL node is added to the BLOCK_VARS list
    	  of the innermost containing BLOCK.
    
    gcc/testsuite/ChangeLog:
    2008-09-30  Dodji Seketeli  <dodji@redhat.com>
    
    	PR c++/37410
    	* g++.dg/debug/dwarf2/imported-module.C: New test.

diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 243b1c6..a1542b9 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -508,6 +508,8 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
   int saved_stmts_are_full_exprs_p = 0;
   enum tree_code code = TREE_CODE (*expr_p);
   enum gimplify_status ret;
+  tree block = NULL;
+  VEC(gimple, heap) *bind_expr_stack = NULL;
 
   if (STATEMENT_CODE_P (code))
     {
@@ -574,8 +576,37 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
       break;
 
     case USING_STMT:
-      /* Just ignore for now.  Eventually we will want to pass this on to
-	 the debugger.  */
+      /* Get the innermost inclosing GIMPLE_BIND that has a non NULL
+         BLOCK, and append an IMPORTED_DECL to its
+	 BLOCK_VARS chained list.  */
+
+      bind_expr_stack = gimple_bind_expr_stack ();
+      if (bind_expr_stack)
+	{
+	  int i;
+	  for (i = VEC_length (gimple, bind_expr_stack) - 1; i >= 0; i--)
+	    if ((block = gimple_bind_block (VEC_index (gimple,
+						       bind_expr_stack,
+						       i))))
+	      break;
+	}
+      if (block)
+	{
+	  tree using_directive;
+	  gcc_assert (TREE_OPERAND (*expr_p,0)
+		      && NAMESPACE_DECL_CHECK (TREE_OPERAND (*expr_p, 0)));
+
+	  using_directive = make_node (IMPORTED_DECL);
+	  TREE_TYPE (using_directive) = void_type_node;
+
+	  IMPORTED_DECL_ASSOCIATED_DECL (using_directive)
+	    = TREE_OPERAND (*expr_p, 0);
+	  DECL_NAME (using_directive)
+	    = DECL_NAME (TREE_OPERAND (*expr_p, 0));
+	  TREE_CHAIN (using_directive) = BLOCK_VARS (block);
+	  BLOCK_VARS (block) = using_directive;
+	}
+      /* The USING_STMT won't appear in GIMPLE.  */
       *expr_p = NULL;
       ret = GS_ALL_DONE;
       break;
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index a04d731..0da373c 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -3484,7 +3484,6 @@ do_using_directive (tree name_space)
   if (!toplevel_bindings_p ())
     {
       push_using_directive (name_space);
-      context = current_scope ();
     }
   else
     {
@@ -3492,12 +3491,12 @@ do_using_directive (tree name_space)
       add_using_namespace (current_namespace, name_space, 0);
       if (current_namespace != global_namespace)
 	context = current_namespace;
-    }
 
-  /* Emit debugging info.  */
-  if (!processing_template_decl)
-    (*debug_hooks->imported_module_or_decl) (name_space, NULL_TREE,
-					     context, false);
+      /* Emit debugging info.  */
+      if (!processing_template_decl)
+	(*debug_hooks->imported_module_or_decl) (name_space, NULL_TREE,
+						 context, false);
+    }
 }
 
 /* Deal with a using-directive seen by the parser.  Currently we only
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index e39e687..5556339 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -4489,6 +4489,8 @@ static bool dwarf2out_ignore_block (const_tree);
 static void dwarf2out_global_decl (tree);
 static void dwarf2out_type_decl (tree, int);
 static void dwarf2out_imported_module_or_decl (tree, tree, tree, bool);
+static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree,
+						 dw_die_ref);
 static void dwarf2out_abstract_function (tree);
 static void dwarf2out_var_location (rtx);
 static void dwarf2out_begin_function (tree);
@@ -14918,6 +14920,9 @@ decls_for_scope (tree stmt, dw_die_ref context_die, int depth)
 	  if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)
 	      && !(is_fortran () && TREE_PUBLIC (decl)))
 	    ;
+	  else if (TREE_CODE (decl) == IMPORTED_DECL)
+	    dwarf2out_imported_module_or_decl_1 (decl, DECL_NAME (decl),
+						 stmt, context_die);
 	  else
 	    gen_decl_die (decl, context_die);
 	}
@@ -15309,6 +15314,7 @@ gen_decl_die (tree decl, dw_die_ref context_die)
       break;
 
     case NAMESPACE_DECL:
+    case IMPORTED_DECL:
       gen_namespace_die (decl);
       break;
 
@@ -15343,44 +15349,21 @@ dwarf2out_type_decl (tree decl, int local)
 }
 
 /* Output debug information for imported module or decl DECL.
-   NAME is non-NULL name in context if the decl has been renamed.
-   CHILD is true if decl is one of the renamed decls as part of
-   importing whole module.  */
-
+   IMPORTED_MODULE_NAME is non-NULL name in the lexical block
+   if the decl has been renamed.
+   LEXICAL_BLOCK is the lexical block (which TREE_CODE is a BLOCK)
+   that DECL belongs to.
+   LEXICAL_BLOCK_DIE is the DIE of LEXICAL_BLOCK.  */
 static void
-dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
-				   bool child)
+dwarf2out_imported_module_or_decl_1 (tree decl,
+				     tree imported_module_name,
+				     tree lexical_block,
+				     dw_die_ref lexical_block_die)
 {
-  dw_die_ref imported_die, at_import_die;
-  dw_die_ref scope_die;
   expanded_location xloc;
+  dw_die_ref imported_die = NULL;
+  dw_die_ref at_import_die;
 
-  if (debug_info_level <= DINFO_LEVEL_TERSE)
-    return;
-
-  gcc_assert (decl);
-
-  /* To emit DW_TAG_imported_module or DW_TAG_imported_decl, we need two DIEs.
-     We need decl DIE for reference and scope die. First, get DIE for the decl
-     itself.  */
-
-  /* Get the scope die for decl context. Use comp_unit_die for global module
-     or decl. If die is not found for non globals, force new die.  */
-  if (context
-      && TYPE_P (context)
-      && !should_emit_struct_debug (context, DINFO_USAGE_DIR_USE))
-    return;
-  scope_die = get_context_die (context);
-
-  if (child)
-    {
-      gcc_assert (scope_die->die_child);
-      gcc_assert (scope_die->die_child->die_tag == DW_TAG_imported_module);
-      gcc_assert (TREE_CODE (decl) != NAMESPACE_DECL);
-      scope_die = scope_die->die_child;
-    }
-
-  /* For TYPE_DECL or CONST_DECL, lookup TREE_TYPE.  */
   if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
     {
       if (is_base_type (TREE_TYPE (decl)))
@@ -15398,6 +15381,17 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
 	  gcc_assert (at_import_die);
 	}
     }
+  else if (TREE_CODE (decl) == IMPORTED_DECL)
+    {
+      tree imported_ns_decl;
+      gcc_assert (DECL_INITIAL (decl)
+		  && TREE_CODE (DECL_INITIAL (decl)) == NAMESPACE_DECL);
+      imported_ns_decl = DECL_INITIAL (decl);
+      at_import_die = lookup_decl_die (imported_ns_decl);
+      if (!at_import_die)
+	at_import_die = force_decl_die (imported_ns_decl);
+      gcc_assert (at_import_die);
+    }
   else
     {
       at_import_die = lookup_decl_die (decl);
@@ -15421,20 +15415,66 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
 	}
     }
 
-  /* OK, now we have DIEs for decl as well as scope. Emit imported die.  */
   if (TREE_CODE (decl) == NAMESPACE_DECL)
-    imported_die = new_die (DW_TAG_imported_module, scope_die, context);
+    imported_die = new_die (DW_TAG_imported_module,
+			    lexical_block_die,
+			    lexical_block);
   else
-    imported_die = new_die (DW_TAG_imported_declaration, scope_die, context);
+    imported_die = new_die (DW_TAG_imported_declaration,
+			    lexical_block_die,
+			    lexical_block);
 
   xloc = expand_location (input_location);
   add_AT_file (imported_die, DW_AT_decl_file, lookup_filename (xloc.file));
   add_AT_unsigned (imported_die, DW_AT_decl_line, xloc.line);
-  if (name)
-    add_AT_string (imported_die, DW_AT_name, IDENTIFIER_POINTER (name));
+  if (imported_module_name)
+    add_AT_string (imported_die, DW_AT_name,
+		   IDENTIFIER_POINTER (imported_module_name));
   add_AT_die_ref (imported_die, DW_AT_import, at_import_die);
 }
 
+/* Output debug information for imported module or decl DECL.
+   NAME is non-NULL name in context if the decl has been renamed.
+   CHILD is true if decl is one of the renamed decls as part of
+   importing whole module.  */
+
+static void
+dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
+				   bool child)
+{
+  /* dw_die_ref at_import_die;  */
+  dw_die_ref scope_die;
+
+  if (debug_info_level <= DINFO_LEVEL_TERSE)
+    return;
+
+  gcc_assert (decl);
+
+  /* To emit DW_TAG_imported_module or DW_TAG_imported_decl, we need two DIEs.
+     We need decl DIE for reference and scope die. First, get DIE for the decl
+     itself.  */
+
+  /* Get the scope die for decl context. Use comp_unit_die for global module
+     or decl. If die is not found for non globals, force new die.  */
+  if (context
+      && TYPE_P (context)
+      && !should_emit_struct_debug (context, DINFO_USAGE_DIR_USE))
+    return;
+  scope_die = get_context_die (context);
+
+  if (child)
+    {
+      gcc_assert (scope_die->die_child);
+      gcc_assert (scope_die->die_child->die_tag == DW_TAG_imported_module);
+      gcc_assert (TREE_CODE (decl) != NAMESPACE_DECL);
+      scope_die = scope_die->die_child;
+    }
+
+  /* OK, now we have DIEs for decl as well as scope. Emit imported die.  */
+  dwarf2out_imported_module_or_decl_1 (decl, name, context, scope_die);
+
+}
+
 /* Write the debugging output for DECL.  */
 
 void
@@ -15519,6 +15559,7 @@ dwarf2out_decl (tree decl)
       break;
 
     case NAMESPACE_DECL:
+    case IMPORTED_DECL:
       if (debug_info_level <= DINFO_LEVEL_TERSE)
 	return;
       if (lookup_decl_die (decl) != NULL)
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index 16ba392..fb9f126 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -926,6 +926,12 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
 	case TARGET_OPTION_NODE:
 	  cl_target_option_print (file, indent + 4, TREE_TARGET_OPTION (node));
 	  break;
+	case IMPORTED_DECL:
+	  fprintf (file, " imported declaration");
+	  print_node_brief (file, "associated declaration",
+			    IMPORTED_DECL_ASSOCIATED_DECL (node),
+			    indent + 4);
+	  break;
 
 	default:
 	  if (EXCEPTIONAL_CLASS_P (node))
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/imported-module.C b/gcc/testsuite/g++.dg/debug/dwarf2/imported-module.C
new file mode 100644
index 0000000..7b25233
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/imported-module.C
@@ -0,0 +1,35 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin: PR debug/37410
+// { dg-do compile }
+
+namespace A1
+  {
+    int aaa = 1;
+  };
+namespace A2
+  {
+    int aaa = 2;
+  };
+
+int
+foo (void)
+{
+  int x;
+
+  {
+    int block_create;
+    using namespace A1;
+
+    block_create = aaa; /* break1 */
+  }
+
+  {
+    int block_create;
+    using namespace A2;
+
+    block_create = aaa; /* break2 */
+  }
+
+  return x = 0;
+}
+
diff --git a/gcc/tree.c b/gcc/tree.c
index 3d2f3e1..f480cbd 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -343,6 +343,8 @@ init_ttree (void)
   tree_contains_struct[CONST_DECL][TS_CONST_DECL] = 1;
   tree_contains_struct[TYPE_DECL][TS_TYPE_DECL] = 1;
   tree_contains_struct[FUNCTION_DECL][TS_FUNCTION_DECL] = 1;
+  tree_contains_struct[IMPORTED_DECL][TS_DECL_MINIMAL] = 1;
+  tree_contains_struct[IMPORTED_DECL][TS_DECL_COMMON] = 1;
 
   lang_hooks.init_ts ();
 }
diff --git a/gcc/tree.def b/gcc/tree.def
index ef103cd..bde59b7 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -371,6 +371,17 @@ DEFTREECODE (MEMORY_PARTITION_TAG, "memory_partition_tag", tcc_declaration, 0)
    _DECLs, providing a hierarchy of names.  */
 DEFTREECODE (NAMESPACE_DECL, "namespace_decl", tcc_declaration, 0)
 
+/* A declaration import.
+   The C++ FE uses this to represent a using-directive; eg:
+   "using namespace foo".
+   But it could be used to represent any declaration import construct.
+   Whenever a declaration import appears in a lexical block, the BLOCK node
+   representing that lexical block in GIMPLE will contain an IMPORTED_DECL
+   node, linked via BLOCK_VARS accessor of the said BLOCK.
+   For a given NODE which code is IMPORTED_DECL,
+   IMPORTED_DECL_ASSOCIATED_DECL (NODE) accesses the imported declaration.  */
+DEFTREECODE (IMPORTED_DECL, "imported_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 4c046c2..85704e6 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3334,6 +3334,11 @@ struct tree_function_decl GTY(())
 #define TYPE_DECL_SUPPRESS_DEBUG(NODE) \
   (TYPE_DECL_CHECK (NODE)->decl_common.decl_flag_2)
 
+/* Getter of the imported declaration associated to the
+   IMPORTED_DECL node.  */
+#define IMPORTED_DECL_ASSOCIATED_DECL(NODE) \
+(DECL_INITIAL (IMPORTED_DECL_CHECK (NODE)))
+
 struct tree_type_decl GTY(())
 {
   struct tree_decl_non_common common;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]