From 7a7b545f8ea2e00afbf953b75cb7787759f0c266 Mon Sep 17 00:00:00 2001 From: Pierre-Marie de Rodat Date: Sat, 12 Aug 2017 09:07:12 +0000 Subject: [PATCH] [PR79542][Ada] Fix ICE in dwarf2out.c with nested func. inlining https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79542 reports an ICE in dwarf2out.c for an Ada testcase built with optimization. This crash happens during the late generation pass because add_gnat_descriptive_type cannot find the type DIE corresponding to some descriptive type after having tried to generate it. This is because the DIE was generated during the early generation pass, but then pruned by the type pruning machinery. So why was it pruned? We are in a situation where we have cloned types (because of inlining, IIUC) whose TYPE_NAME have non-null DECL_ABSTRACT_ORIGIN attributes. As a consequence: * In modified_type_die, the "handle C typedef types" part calls gen_type_die on the cloned type. * gen_type_die matches a typedef variant, and then calls gen_decl_die on its TYPE_NAME, which will end up calling gen_typedef_die. * gen_typedef_die checks decl_ultimate_origin for this TYPE_DECL, and finds one, so it only adds a DW_AT_abstract_origin attribute to the DW_TAG_typedef DIE, but the cloned type itself does not get its own DIE. * Back in modified_type_die, the call to lookup_type_die on the type passed to gen_type_die returns NULL. In the end, whole type trees, i.e. the ones referenced by DECL_ABSTRACT_ORIGIN attributes, are never referenced from type pruning "roots" and are thus pruned. The descriptive type at stake here is one of them, hence the assertion failure. This patch attemps to fix that with what seems to be the most sensible thing to do in my opinion: updating the "handle C typedef types" part in modified_type_die to check decl_ultimate_origin before calling gen_type_die: if that function returns something not null, then we know that gen_type_die/gen_typedef_die will not generate a DIE for the input type, so we try to process the ultimate origin instead. It also updates in a similar way gen_type_die_with_usage, assert that when gen_typedef_die is called on nodes that have an ultimate origin, this origin is themselves. gcc/ PR ada/79542 * dwarf2out.c (modified_type_die): For C typedef types that have an ultimate origin, process the ultimate origin instead of the input type. (gen_typedef_die): Assert that input DECLs have no ultimate origin. (gen_type_die_with_usage): For typedef variants that have an ultimate origin, just call gen_decl_die on the original DECL. (process_scope_var): Avoid creating DIEs for local typedefs and concrete static variables. gcc/testsuite/ PR ada/79542 * gnat.dg/debug13.ads, gnat.dg/debug13.adb: New testcase. From-SVN: r251066 --- gcc/ChangeLog | 13 +++ gcc/dwarf2out.c | 143 ++++++++++++++++++------------ gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gnat.dg/debug13.adb | 38 ++++++++ gcc/testsuite/gnat.dg/debug13.ads | 5 ++ 5 files changed, 147 insertions(+), 57 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/debug13.adb create mode 100644 gcc/testsuite/gnat.dg/debug13.ads diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 55645ca3b85..bbe66587669 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2017-08-12 Pierre-Marie de Rodat + + PR ada/79542 + * dwarf2out.c (modified_type_die): For C typedef types that have + an ultimate origin, process the ultimate origin instead of the + input type. + (gen_typedef_die): Assert that input DECLs have no ultimate + origin. + (gen_type_die_with_usage): For typedef variants that have an + ultimate origin, just call gen_decl_die on the original DECL. + (process_scope_var): Avoid creating DIEs for local typedefs and + concrete static variables. + 2017-08-12 Alan Modra PR target/81170 diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 8e422279a61..917ab9fa58a 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -12506,6 +12506,15 @@ modified_type_die (tree type, int cv_quals, bool reverse, if (qualified_type == dtype) { + tree origin = decl_ultimate_origin (name); + + /* Typedef variants that have an abstract origin don't get their own + type DIE (see gen_typedef_die), so fall back on the ultimate + abstract origin instead. */ + if (origin != NULL) + return modified_type_die (TREE_TYPE (origin), cv_quals, reverse, + context_die); + /* For a named type, use the typedef. */ gen_type_die (qualified_type, context_die); return lookup_type_die (qualified_type); @@ -24296,7 +24305,7 @@ static void gen_typedef_die (tree decl, dw_die_ref context_die) { dw_die_ref type_die; - tree origin; + tree type; if (TREE_ASM_WRITTEN (decl)) { @@ -24305,75 +24314,71 @@ gen_typedef_die (tree decl, dw_die_ref context_die) return; } + /* As we avoid creating DIEs for local typedefs (see decl_ultimate_origin + checks in process_scope_var and modified_type_die), this should be called + only for original types. */ + gcc_assert (decl_ultimate_origin (decl) == NULL); + TREE_ASM_WRITTEN (decl) = 1; type_die = new_die (DW_TAG_typedef, context_die, decl); - origin = decl_ultimate_origin (decl); - if (origin != NULL) - add_abstract_origin_attribute (type_die, origin); - else + + add_name_and_src_coords_attributes (type_die, decl); + if (DECL_ORIGINAL_TYPE (decl)) { - tree type = TREE_TYPE (decl); + type = DECL_ORIGINAL_TYPE (decl); + if (type == error_mark_node) + return; + gcc_assert (type != TREE_TYPE (decl)); + equate_type_number_to_die (TREE_TYPE (decl), type_die); + } + else + { + type = TREE_TYPE (decl); if (type == error_mark_node) return; - add_name_and_src_coords_attributes (type_die, decl); - if (DECL_ORIGINAL_TYPE (decl)) + if (is_naming_typedef_decl (TYPE_NAME (type))) { - type = DECL_ORIGINAL_TYPE (decl); + /* 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. - if (type == error_mark_node) - return; + 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. */ + if (!TREE_ASM_WRITTEN (type)) + gen_tagged_type_die (type, context_die, DINFO_USAGE_DIR_USE); - gcc_assert (type != TREE_TYPE (decl)); - equate_type_number_to_die (TREE_TYPE (decl), type_die); - } - else - { - 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. */ - if (!TREE_ASM_WRITTEN (type)) - gen_tagged_type_die (type, context_die, DINFO_USAGE_DIR_USE); - - /* This is a GNU Extension. We are adding a - DW_AT_linkage_name attribute to the DIE of the - anonymous struct TYPE. The value of that attribute - is the name of the typedef decl naming the anonymous - struct. This greatly eases the work of consumers of - this debug info. */ - add_linkage_name_raw (lookup_type_die (type), decl); - } + /* This is a GNU Extension. We are adding a + DW_AT_linkage_name attribute to the DIE of the + anonymous struct TYPE. The value of that attribute + is the name of the typedef decl naming the anonymous + struct. This greatly eases the work of consumers of + this debug info. */ + add_linkage_name_raw (lookup_type_die (type), decl); } + } - add_type_attribute (type_die, type, decl_quals (decl), false, - 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); + add_type_attribute (type_die, type, decl_quals (decl), false, + context_die); - type = TREE_TYPE (decl); + 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); - add_alignment_attribute (type_die, type); + add_alignment_attribute (type_die, TREE_TYPE (decl)); - add_accessibility_attribute (type_die, decl); - } + add_accessibility_attribute (type_die, decl); if (DECL_ABSTRACT_P (decl)) equate_decl_number_to_die (decl, type_die); @@ -24485,15 +24490,23 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die, if (TREE_ASM_WRITTEN (type)) return; + tree name = TYPE_NAME (type); + tree origin = decl_ultimate_origin (name); + if (origin != NULL) + { + gen_decl_die (origin, NULL, NULL, context_die); + return; + } + /* Prevent broken recursion; we can't hand off to the same type. */ - gcc_assert (DECL_ORIGINAL_TYPE (TYPE_NAME (type)) != type); + gcc_assert (DECL_ORIGINAL_TYPE (name) != type); /* Give typedefs the right scope. */ context_die = scope_die_for (type, context_die); TREE_ASM_WRITTEN (type) = 1; - gen_decl_die (TYPE_NAME (type), NULL, NULL, context_die); + gen_decl_die (name, NULL, NULL, context_die); return; } @@ -24812,6 +24825,22 @@ process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die) else die = NULL; + /* Avoid creating DIEs for local typedefs and concrete static variables that + will only be pruned later. */ + if ((origin || decl_ultimate_origin (decl)) + && (TREE_CODE (decl_or_origin) == TYPE_DECL + || (VAR_P (decl_or_origin) && TREE_STATIC (decl_or_origin)))) + { + origin = decl_ultimate_origin (decl_or_origin); + if (decl && VAR_P (decl) && die != NULL) + { + die = lookup_decl_die (origin); + if (die != NULL) + equate_decl_number_to_die (decl, die); + } + return; + } + if (die != NULL && die->die_parent == NULL) add_child_die (context_die, die); else if (TREE_CODE (decl_or_origin) == IMPORTED_DECL) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 056953e7793..e13b30ba250 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-08-12 Pierre-Marie de Rodat + + PR ada/79542 + * gnat.dg/debug13.ads, gnat.dg/debug13.adb: New testcase. + 2017-08-11 Marek Polacek PR c/81795 diff --git a/gcc/testsuite/gnat.dg/debug13.adb b/gcc/testsuite/gnat.dg/debug13.adb new file mode 100644 index 00000000000..4b94b3e6bf1 --- /dev/null +++ b/gcc/testsuite/gnat.dg/debug13.adb @@ -0,0 +1,38 @@ +-- { dg-options "-cargs -O2 -g -margs" } + +package body Debug13 is + + procedure Compile (P : Natural) + is + Max_Pos : constant Natural := P; + type Position_Set is array (1 .. Max_Pos) of Boolean; + + Empty : constant Position_Set := (others => False); + + type Position_Set_Array is array (1 .. Max_Pos) of Position_Set; + + Follow : Position_Set_Array := (others => Empty); + + function Get_Follows return Position_Set; + + procedure Make_DFA; + + function Get_Follows return Position_Set is + Result : Position_Set := Empty; + begin + Result := Result or Follow (1); + + return Result; + end Get_Follows; + + procedure Make_DFA is + Next : constant Position_Set := Get_Follows; + begin + null; + end Make_DFA; + + begin + Make_DFA; + end Compile; + +end Debug13; diff --git a/gcc/testsuite/gnat.dg/debug13.ads b/gcc/testsuite/gnat.dg/debug13.ads new file mode 100644 index 00000000000..512a9ef75bb --- /dev/null +++ b/gcc/testsuite/gnat.dg/debug13.ads @@ -0,0 +1,5 @@ +package Debug13 is + + procedure Compile (P : Natural); + +end Debug13; -- 2.30.2