[RFC] PR c++/44188

Dodji Seketeli dodji@redhat.com
Sat Jun 5 19:59:00 GMT 2010


Hello,

My previous patch for PR c++/44188 at
http://gcc.gnu.org/ml/gcc-patches/2010-05/msg01998.html turned out to
not bootstrap on ObjC and Ada. For ObjC, it was due to the hunk in
gen_typedef_die trying to generate tagged type DIEs for constructs
that were not naming typedefs. I just added a test there to make sure
we generate the DIE there for naming types only.

Looking at the Ada part, I think maybe the concept of "typedef naming
an anonymous type" is specific to c++ (or maybe to all FEs but
Ada?). I made is_naming_typedef_decl be c++ specific for now. I have
put the somewhat long rationale in attachment to this email.

The patch below is an updated patch of the one that was OKed. I have
also put in attachment the difference between this version of the
patch and the previous one.

It bootstraps on C,C++,Obj-C(++),Java,Ada and passes regtests on
trunk.

commit d2c243d43b4809c72f4c9ed06caf4f382cf7fddf
Author: dodji <dodji@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Thu May 27 19:29:53 2010 +0000

    Fix PR c++/44188
    
    gcc/ChangeLog:
    	PR c++/44188
    	* c-common.c (is_typedef_decl): Move this definition ...
    	* tree.c (is_typedef_decl): ... here.
    	(typdef_variant_p): Move definition here from gcc/cp/tree.c.
    	* c-common.h (is_typedef_decl): Move this declaration ...
    	* tree.h (is_typedef_decl): ... here.
    	(typedef_variant_p): Move declaration here from gcc/cp/cp-tree.h
    	* dwarf2out.c (is_naming_typedef_decl): New function.
    	(gen_tagged_type_die): Split out of ...
    	(gen_type_die_with_usage): ... this function. When an anonymous
    	tagged type is named by a typedef, make sure a DW_TAG_typedef DIE
    	is emitted for the typedef.
    	(gen_typedef_die): Emit DW_TAG_typedef also for typedefs naming
    	anonymous tagged types.
    
    gcc/cp/ChangeLog:
    	PR c++/44188
    	* cp-tree.h (typedef_variant_p): Move this declaration to
    	gcc/tree.h.
    	* tree.c (typedef_variant_p): Move this definition to gcc/tree.c.
    	* decl.c (grokdeclarator): Do not rename debug info of an
    	anonymous tagged type named by a typedef.
    
    gcc/testsuite/ChangeLog:
    	PR c++/44188
    	* g++.dg/debug/dwarf2/typedef3.C: New test.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@159943 138bc75d-0d04-0410-961f-82ee72b054a4

diff --git a/gcc/c-common.c b/gcc/c-common.c
index 1fd11c5..e72aaf9 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -9387,15 +9387,6 @@ set_underlying_type (tree x)
     }
 }
 
-/* Returns true if X is a typedef decl.  */
-
-bool
-is_typedef_decl (tree x)
-{
-  return (x && TREE_CODE (x) == TYPE_DECL
-          && DECL_ORIGINAL_TYPE (x) != NULL_TREE);
-}
-
 /* Record the types used by the current global variable declaration
    being parsed, so that we can decide later to emit their debug info.
    Those types are in types_used_by_cur_var_decl, and we are going to
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 039edbe..ec63e0c 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -1055,7 +1055,6 @@ extern void warn_for_sign_compare (location_t,
 				   tree result_type,
 				   enum tree_code resultcode);
 extern void set_underlying_type (tree x);
-extern bool is_typedef_decl (tree x);
 extern VEC(tree,gc) *make_tree_vector (void);
 extern void release_tree_vector (VEC(tree,gc) *);
 extern VEC(tree,gc) *make_tree_vector_single (tree);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 37a0f1e..4d3cf7d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5256,7 +5256,6 @@ extern bool type_has_nontrivial_copy_init	(const_tree);
 extern bool class_tmpl_impl_spec_p		(const_tree);
 extern int zero_init_p				(const_tree);
 extern tree strip_typedefs			(tree);
-extern bool typedef_variant_p			(tree);
 extern void cp_set_underlying_type		(tree);
 extern tree copy_binfo				(tree, tree, tree,
 						 tree *, int);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 0d30340..533b56f 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -9081,10 +9081,12 @@ grokdeclarator (const cp_declarator *declarator,
 	  for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
 	    {
 	      if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
-		{
-		  debug_hooks->set_name (t, decl);
-		  TYPE_NAME (t) = decl;
-		}
+		/* We do not rename the debug info representing the
+		   anonymous tagged type because the standard says in
+		   [dcl.typedef] that the naming applies only for
+		   linkage purposes.  */
+		/*debug_hooks->set_name (t, decl);*/
+		TYPE_NAME (t) = decl;
   	    }
 
 	  if (TYPE_LANG_SPECIFIC (type))
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index d5ccd65..5421980 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1055,14 +1055,6 @@ strip_typedefs (tree t)
   return cp_build_qualified_type (result, cp_type_quals (t));
 }
 
-/* Returns true iff TYPE is a type variant created for a typedef. */
-
-bool
-typedef_variant_p (tree type)
-{
-  return is_typedef_decl (TYPE_NAME (type));
-}
-
 /* Setup a TYPE_DECL node as a typedef representation.
    See comments of set_underlying_type in c-common.c.  */
 
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index ca2194f..9a6f414 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -6202,6 +6202,7 @@ static void gen_type_die (tree, dw_die_ref);
 static void gen_block_die (tree, dw_die_ref, int);
 static void decls_for_scope (tree, dw_die_ref, int);
 static 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 void gen_decl_die (tree, tree, dw_die_ref);
@@ -6213,6 +6214,8 @@ static struct dwarf_file_data * lookup_filename (const char *);
 static void retry_incomplete_types (void);
 static void gen_type_die_for_member (tree, tree, dw_die_ref);
 static void gen_generic_params_dies (tree);
+static void gen_tagged_type_die (tree, dw_die_ref, enum debug_info_usage);
+static void gen_type_die_with_usage (tree, dw_die_ref, enum debug_info_usage);
 static void splice_child_die (dw_die_ref, dw_die_ref);
 static int file_info_cmp (const void *, const void *);
 static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
@@ -19408,10 +19411,36 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
 	  equate_type_number_to_die (TREE_TYPE (decl), type_die);
 	}
       else
-	type = TREE_TYPE (decl);
+	{
+	  type = TREE_TYPE (decl);
+
+	  if (is_naming_typedef_decl (TYPE_NAME (type)))
+	    /* 
+	       Here, we are in the case of decl being a typedef naming
+	       an anonymous type, e.g:
+	             typedef struct {...} foo;
+	       In that case TREE_TYPE (decl) is not a typedef variant
+	       type and TYPE_NAME of the anonymous type is set to the
+	       TYPE_DECL of the typedef. This construct is emitted by
+	       the C++ FE.
+
+	       TYPE is the anonymous struct named by the typedef
+	       DECL. As we need the DW_AT_type attribute of the
+	       DW_TAG_typedef to point to the DIE of TYPE, let's
+	       generate that DIE right away. add_type_attribute
+	       called below will then pick (via lookup_type_die) that
+	       anonymous struct DIE.  */
+	    gen_tagged_type_die (type, context_die, DINFO_USAGE_DIR_USE);
+	}
 
       add_type_attribute (type_die, type, TREE_READONLY (decl),
 			  TREE_THIS_VOLATILE (decl), context_die);
+
+      if (is_naming_typedef_decl (decl))
+	/* We want that all subsequent calls to lookup_type_die with
+	   TYPE in argument yield the DW_TAG_typedef we have just
+	   created.  */
+	equate_type_number_to_die (type, type_die);
     }
 
   if (DECL_ABSTRACT (decl))
@@ -19421,13 +19450,78 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
     add_pubtype (decl, type_die);
 }
 
+/* Generate a DIE for a struct, class, enum or union type.  */
+
+static void
+gen_tagged_type_die (tree type,
+		     dw_die_ref context_die,
+		     enum debug_info_usage usage)
+{
+  int need_pop;
+
+  if (type == NULL_TREE
+      || !is_tagged_type (type))
+    return;
+
+  /* If this is a nested type whose containing class hasn't been written
+     out yet, writing it out will cover this one, too.  This does not apply
+     to instantiations of member class templates; they need to be added to
+     the containing class as they are generated.  FIXME: This hurts the
+     idea of combining type decls from multiple TUs, since we can't predict
+     what set of template instantiations we'll get.  */
+  if (TYPE_CONTEXT (type)
+      && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
+      && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
+    {
+      gen_type_die_with_usage (TYPE_CONTEXT (type), context_die, usage);
+
+      if (TREE_ASM_WRITTEN (type))
+	return;
+
+      /* If that failed, attach ourselves to the stub.  */
+      push_decl_scope (TYPE_CONTEXT (type));
+      context_die = lookup_type_die (TYPE_CONTEXT (type));
+      need_pop = 1;
+    }
+  else if (TYPE_CONTEXT (type) != NULL_TREE
+	   && (TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL))
+    {
+      /* If this type is local to a function that hasn't been written
+	 out yet, use a NULL context for now; it will be fixed up in
+	 decls_for_scope.  */
+      context_die = lookup_decl_die (TYPE_CONTEXT (type));
+      need_pop = 0;
+    }
+  else
+    {
+      context_die = declare_in_namespace (type, context_die);
+      need_pop = 0;
+    }
+
+  if (TREE_CODE (type) == ENUMERAL_TYPE)
+    {
+      /* This might have been written out by the call to
+	 declare_in_namespace.  */
+      if (!TREE_ASM_WRITTEN (type))
+	gen_enumeration_type_die (type, context_die);
+    }
+  else
+    gen_struct_or_union_type_die (type, context_die, usage);
+
+  if (need_pop)
+    pop_decl_scope ();
+
+  /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix
+     it up if it is ever completed.  gen_*_type_die will set it for us
+     when appropriate.  */
+}
+
 /* Generate a type description DIE.  */
 
 static void
 gen_type_die_with_usage (tree type, dw_die_ref context_die,
 				enum debug_info_usage usage)
 {
-  int need_pop;
   struct array_descr_info info;
 
   if (type == NULL_TREE || type == error_mark_node)
@@ -19435,8 +19529,7 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
 
   /* If TYPE is a typedef type variant, let's generate debug info
      for the parent typedef which TYPE is a type of.  */
-  if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
-      && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+  if (typedef_variant_p (type))
     {
       if (TREE_ASM_WRITTEN (type))
 	return;
@@ -19451,6 +19544,21 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
 	context_die = get_context_die (DECL_CONTEXT (TYPE_NAME (type)));
 
       TREE_ASM_WRITTEN (type) = 1;
+
+      gen_decl_die (TYPE_NAME (type), NULL, context_die);
+      return;
+    }
+
+  /* If type is an anonymous tagged type named by a typedef, let's
+     generate debug info for the typedef.  */
+  if (is_naming_typedef_decl (TYPE_NAME (type)))
+    {
+      /* Use the DIE of the containing namespace as the parent DIE of
+         the type description DIE we want to generate.  */
+      if (DECL_CONTEXT (TYPE_NAME (type))
+	  && TREE_CODE (DECL_CONTEXT (TYPE_NAME (type))) == NAMESPACE_DECL)
+	context_die = get_context_die (DECL_CONTEXT (TYPE_NAME (type)));
+      
       gen_decl_die (TYPE_NAME (type), NULL, context_die);
       return;
     }
@@ -19538,57 +19646,7 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
     case RECORD_TYPE:
     case UNION_TYPE:
     case QUAL_UNION_TYPE:
-      /* If this is a nested type whose containing class hasn't been written
-	 out yet, writing it out will cover this one, too.  This does not apply
-	 to instantiations of member class templates; they need to be added to
-	 the containing class as they are generated.  FIXME: This hurts the
-	 idea of combining type decls from multiple TUs, since we can't predict
-	 what set of template instantiations we'll get.  */
-      if (TYPE_CONTEXT (type)
-	  && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
-	  && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
-	{
-	  gen_type_die_with_usage (TYPE_CONTEXT (type), context_die, usage);
-
-	  if (TREE_ASM_WRITTEN (type))
-	    return;
-
-	  /* If that failed, attach ourselves to the stub.  */
-	  push_decl_scope (TYPE_CONTEXT (type));
-	  context_die = lookup_type_die (TYPE_CONTEXT (type));
-	  need_pop = 1;
-	}
-      else if (TYPE_CONTEXT (type) != NULL_TREE
-	       && (TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL))
-	{
-	  /* If this type is local to a function that hasn't been written
-	     out yet, use a NULL context for now; it will be fixed up in
-	     decls_for_scope.  */
-	  context_die = lookup_decl_die (TYPE_CONTEXT (type));
-	  need_pop = 0;
-	}
-      else
-	{
-	  context_die = declare_in_namespace (type, context_die);
-	  need_pop = 0;
-	}
-
-      if (TREE_CODE (type) == ENUMERAL_TYPE)
-	{
-	  /* This might have been written out by the call to
-	     declare_in_namespace.  */
-	  if (!TREE_ASM_WRITTEN (type))
-	    gen_enumeration_type_die (type, context_die);
-	}
-      else
-	gen_struct_or_union_type_die (type, context_die, usage);
-
-      if (need_pop)
-	pop_decl_scope ();
-
-      /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix
-	 it up if it is ever completed.  gen_*_type_die will set it for us
-	 when appropriate.  */
+      gen_tagged_type_die (type, context_die, usage);
       return;
 
     case VOID_TYPE:
@@ -19796,6 +19854,35 @@ is_redundant_typedef (const_tree decl)
   return 0;
 }
 
+/* Return TRUE if TYPE is a typedef that names a type for linkage
+   purposes. This kind of typedefs is produced by the C++ FE for
+   constructs like:
+
+   typedef struct {...} foo;
+
+   In that case, there is no typedef variant type produced for foo.
+   Rather, the TREE_TYPE of the TYPE_DECL of foo is the anonymous
+   struct type.  */
+
+static bool
+is_naming_typedef_decl (const_tree decl)
+{
+  if (decl == NULL_TREE
+      || TREE_CODE (decl) != TYPE_DECL
+      || !is_tagged_type (TREE_TYPE (decl))
+      || is_redundant_typedef (decl)
+      /* It looks like Ada produces TYPE_DECLs that are very similar
+         to C++ naming typedefs but that have different
+         semantics. Let's be specific to c++ for now.  */
+      || !is_cxx ())
+    return FALSE;
+
+  return (DECL_ORIGINAL_TYPE (decl) == NULL_TREE
+	  && TYPE_NAME (TREE_TYPE (decl)) == decl
+	  && (TYPE_STUB_DECL (TREE_TYPE (decl))
+	      != TYPE_NAME (TREE_TYPE (decl))));
+}
+
 /* Returns the DIE for a context.  */
 
 static inline dw_die_ref
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/typedef3.C b/gcc/testsuite/g++.dg/debug/dwarf2/typedef3.C
new file mode 100644
index 0000000..ca70d9c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/typedef3.C
@@ -0,0 +1,19 @@
+// Origin: PR debug/44188
+// { dg-options "-g -dA" }
+// { dg-do compile }
+
+// { dg-final { scan-assembler-times "\[^\n\r\]*\\(DIE\[^\n\r\]*DW_TAG_typedef\\)" 1 } }
+
+// { dg-final { scan-assembler-times "\[^\n\r\]*\\(DIE\[^\n\r\]*DW_TAG_structure_type\\)" 1 } }
+
+typedef struct
+{
+  int i;
+} AAA;
+
+int
+main(void)
+{
+  AAA aa;
+  return 0;
+}
diff --git a/gcc/tree.c b/gcc/tree.c
index 743293e..8b04c37 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -10825,4 +10825,21 @@ get_binfo_at_offset (tree binfo, HOST_WIDE_INT offset, tree expected_type)
   return binfo;
 }
 
+/* Returns true if X is a typedef decl.  */
+
+bool
+is_typedef_decl (tree x)
+{
+  return (x && TREE_CODE (x) == TYPE_DECL
+          && DECL_ORIGINAL_TYPE (x) != NULL_TREE);
+}
+
+/* Returns true iff TYPE is a type variant created for a typedef. */
+
+bool
+typedef_variant_p (tree type)
+{
+  return is_typedef_decl (TYPE_NAME (type));
+}
+
 #include "gt-tree.h"
diff --git a/gcc/tree.h b/gcc/tree.h
index 5acadb4..94379fe 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4820,6 +4820,8 @@ extern tree create_artificial_label (location_t);
 extern const char *get_name (tree);
 extern bool stdarg_p (tree);
 extern bool prototype_p (tree);
+extern bool is_typedef_decl (tree x);
+extern bool typedef_variant_p (tree);
 extern bool auto_var_in_fn_p (const_tree, const_tree);
 extern tree build_low_bits_mask (tree, unsigned);
 extern tree tree_strip_nop_conversions (tree);

-- 
Dodji Seketeli
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: not available
URL: <http://gcc.gnu.org/pipermail/gcc-patches/attachments/20100605/691dc6be/attachment.ksh>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: not available
URL: <http://gcc.gnu.org/pipermail/gcc-patches/attachments/20100605/691dc6be/attachment-0001.ksh>


More information about the Gcc-patches mailing list