From: dodji Date: Sun, 6 Jun 2010 18:24:27 +0000 (+0000) Subject: Fix PR c++/44188 X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=commitdiff_plain;h=a8891ab12879a8d2f8421492c85a1b409144cea4;hp=c0c1d342d7e5541730b4dfc57e5fc33568008a06 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@160347 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b3ef9444b85..c82ec230275 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2010-05-25 Dodji Seketeli + + 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. + 2010-06-06 Manuel López-Ibáñez PR c/20000 diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 1053c2bfaec..545f2e28008 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -9364,15 +9364,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-family/c-common.h b/gcc/c-family/c-common.h index 289d70c6be2..5fda1ab7e44 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1071,7 +1071,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/ChangeLog b/gcc/cp/ChangeLog index 6572ac06379..2350ae68ba0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2010-05-25 Dodji Seketeli + + 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. + 2010-06-05 Fabien Chêne PR c++/44086 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 98619460927..5efe2798d32 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5261,7 +5261,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 d534ea3bf9b..c9f864a6eaf 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -9088,10 +9088,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 7d0e4765cd1..29712832391 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1056,14 +1056,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 48f5fa4c208..0cdd2dc274d 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 *, @@ -19426,10 +19429,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)) @@ -19439,13 +19468,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) @@ -19453,8 +19547,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; @@ -19469,6 +19562,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; } @@ -19556,57 +19664,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: @@ -19814,6 +19872,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/ChangeLog b/gcc/testsuite/ChangeLog index bda499ed9ce..345318bce13 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-05-25 Dodji Seketeli + + PR c++/44188 + * g++.dg/debug/dwarf2/typedef3.C: New test. + 2010-06-06 Manuel López-Ibáñez PR c/20000 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 00000000000..ca70d9cacfa --- /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 67e2f417cb9..7b1a489a03f 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -10818,4 +10818,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 13c684af37a..31d80dfa7e2 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);