Re: [PATCH] Fix dwarf2out ICE with self-inlining (PR debug/80321)
On Fri, Apr 7, 2017 at 11:42 PM, Jakub Jelinekwrote: > Hi! > > The following C and Ada testcases show ICE due to endless recursion in > dwarf2out.c. The problem is that when processing BLOCK_NONLOCALIZED_VARS, > we want to treat all the FUNCTION_DECLs in there as mere declarations, > but gen_subprogram_die does: > int declaration = (current_function_decl != decl > || class_or_namespace_scope_p (context_die)); > and thus if there is some self-inlining and we are unlucky enough > not to reach some early-outs that just ignore the FUNCTION_DECL, > like: > /* Detect and ignore this case, where we are trying to output > something we have already output. */ > if (get_AT (old_die, DW_AT_low_pc) > || get_AT (old_die, DW_AT_ranges)) > return; > we will recurse infinitely. The following patch fixes it by > just ignoring current_function_decl seen from BLOCK_NONLOCALIZED_VARS, > that implies it is already inlined into somewhere and in the abstract > origin we emit properly a DW_AT_declaration decl if needed, that is pretty > much what gen_subprogram_die would do anyway in such cases, because there > is already old_die, we really don't want to make some child of it its parent > and otherwise no further action is performed. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? Ok. Thanks, Richard. > Other possibilities include adding some global bool flag that > gen_subprogram_die's int declaration = ... above should ignore > decl == current_function_decl that we'd set in decls_for_scope when > seeing current_function_decl in BLOCK_NONLOCALIZED_VARS (and probably > save/clear + restore in dwarf2out_abstract_function where we change > current_function_decl). Or we could pass through from decls_for_scope > down through process_scope_var, gen_decl_die to gen_subprogram_die > a bool flag force_declaration. > > 2017-04-07 Jakub Jelinek > > PR debug/80321 > * dwarf2out.c (decls_for_scope): Ignore declarations of > current_function_decl in BLOCK_NONLOCALIZED_VARS. > > * gcc.dg/debug/pr80321.c: New test. > > 2017-04-07 Eric Botcazou > > * gnat.dg/debug10.adb: New test. > * gnat.dg/debug10_pkg.ads: New helper. > > --- gcc/dwarf2out.c.jj 2017-04-07 11:46:48.0 +0200 > +++ gcc/dwarf2out.c 2017-04-07 20:00:43.503772542 +0200 > @@ -24889,7 +24889,12 @@ decls_for_scope (tree stmt, dw_die_ref c > for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++) > { > decl = BLOCK_NONLOCALIZED_VAR (stmt, i); > - if (TREE_CODE (decl) == FUNCTION_DECL) > + if (decl == current_function_decl) > + /* Ignore declarations of the current function, while they > +are declarations, gen_subprogram_die would treat them > +as definitions again, because they are equal to > +current_function_decl and endlessly recurse. */; > + else if (TREE_CODE (decl) == FUNCTION_DECL) > process_scope_var (stmt, decl, NULL_TREE, context_die); > else > process_scope_var (stmt, NULL_TREE, decl, context_die); > --- gcc/testsuite/gcc.dg/debug/pr80321.c.jj 2017-04-07 21:39:01.930615179 > +0200 > +++ gcc/testsuite/gcc.dg/debug/pr80321.c2017-04-07 21:39:49.722982635 > +0200 > @@ -0,0 +1,26 @@ > +/* PR debug/80321 */ > +/* { dg-do compile } */ > +/* { dg-options "-fkeep-inline-functions" } */ > + > +void bar (void); > + > +static inline void > +test (int x) > +{ > + inline void > + foo (int x) > + { > +test (0); > +asm volatile ("" : : : "memory"); > + } > + if (x != 0) > +foo (x); > + else > +bar (); > +} > + > +void > +baz (int x) > +{ > + test (x); > +} > --- gcc/testsuite/gnat.dg/debug10.adb.jj2017-04-07 20:24:44.232473780 > +0200 > +++ gcc/testsuite/gnat.dg/debug10.adb 2017-04-07 20:26:40.493980722 +0200 > @@ -0,0 +1,68 @@ > +-- PR debug/80321 > + > +-- { dg-do compile } > +-- { dg-options "-O2 -g" } > + > +with Debug10_Pkg; use Debug10_Pkg; > + > +procedure Debug10 (T : Entity_Id) is > + > + procedure Inner (E : Entity_Id); > + pragma Inline (Inner); > + > + procedure Inner (E : Entity_Id) is > + begin > + if E /= Empty > + and then not Nodes (E + 3).Flag16 > + then > + Debug10 (E); > + end if; > + end Inner; > + > + function Ekind (E : Entity_Id) return Entity_Kind is > + begin > + return N_To_E (Nodes (E + 1).Nkind); > + end Ekind; > + > +begin > + > + if T = Empty then > + return; > + end if; > + > + Nodes (T + 3).Flag16 := True; > + > + if Ekind (T) in Object_Kind then > + Inner (T); > + > + elsif Ekind (T) in Type_Kind then > + Inner (T); > + > + if Ekind (T) in Record_Kind then > + > + if Ekind (T) = E_Class_Wide_Subtype then > +Inner
[PATCH] Fix dwarf2out ICE with self-inlining (PR debug/80321)
Hi! The following C and Ada testcases show ICE due to endless recursion in dwarf2out.c. The problem is that when processing BLOCK_NONLOCALIZED_VARS, we want to treat all the FUNCTION_DECLs in there as mere declarations, but gen_subprogram_die does: int declaration = (current_function_decl != decl || class_or_namespace_scope_p (context_die)); and thus if there is some self-inlining and we are unlucky enough not to reach some early-outs that just ignore the FUNCTION_DECL, like: /* Detect and ignore this case, where we are trying to output something we have already output. */ if (get_AT (old_die, DW_AT_low_pc) || get_AT (old_die, DW_AT_ranges)) return; we will recurse infinitely. The following patch fixes it by just ignoring current_function_decl seen from BLOCK_NONLOCALIZED_VARS, that implies it is already inlined into somewhere and in the abstract origin we emit properly a DW_AT_declaration decl if needed, that is pretty much what gen_subprogram_die would do anyway in such cases, because there is already old_die, we really don't want to make some child of it its parent and otherwise no further action is performed. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? Other possibilities include adding some global bool flag that gen_subprogram_die's int declaration = ... above should ignore decl == current_function_decl that we'd set in decls_for_scope when seeing current_function_decl in BLOCK_NONLOCALIZED_VARS (and probably save/clear + restore in dwarf2out_abstract_function where we change current_function_decl). Or we could pass through from decls_for_scope down through process_scope_var, gen_decl_die to gen_subprogram_die a bool flag force_declaration. 2017-04-07 Jakub JelinekPR debug/80321 * dwarf2out.c (decls_for_scope): Ignore declarations of current_function_decl in BLOCK_NONLOCALIZED_VARS. * gcc.dg/debug/pr80321.c: New test. 2017-04-07 Eric Botcazou * gnat.dg/debug10.adb: New test. * gnat.dg/debug10_pkg.ads: New helper. --- gcc/dwarf2out.c.jj 2017-04-07 11:46:48.0 +0200 +++ gcc/dwarf2out.c 2017-04-07 20:00:43.503772542 +0200 @@ -24889,7 +24889,12 @@ decls_for_scope (tree stmt, dw_die_ref c for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++) { decl = BLOCK_NONLOCALIZED_VAR (stmt, i); - if (TREE_CODE (decl) == FUNCTION_DECL) + if (decl == current_function_decl) + /* Ignore declarations of the current function, while they +are declarations, gen_subprogram_die would treat them +as definitions again, because they are equal to +current_function_decl and endlessly recurse. */; + else if (TREE_CODE (decl) == FUNCTION_DECL) process_scope_var (stmt, decl, NULL_TREE, context_die); else process_scope_var (stmt, NULL_TREE, decl, context_die); --- gcc/testsuite/gcc.dg/debug/pr80321.c.jj 2017-04-07 21:39:01.930615179 +0200 +++ gcc/testsuite/gcc.dg/debug/pr80321.c2017-04-07 21:39:49.722982635 +0200 @@ -0,0 +1,26 @@ +/* PR debug/80321 */ +/* { dg-do compile } */ +/* { dg-options "-fkeep-inline-functions" } */ + +void bar (void); + +static inline void +test (int x) +{ + inline void + foo (int x) + { +test (0); +asm volatile ("" : : : "memory"); + } + if (x != 0) +foo (x); + else +bar (); +} + +void +baz (int x) +{ + test (x); +} --- gcc/testsuite/gnat.dg/debug10.adb.jj2017-04-07 20:24:44.232473780 +0200 +++ gcc/testsuite/gnat.dg/debug10.adb 2017-04-07 20:26:40.493980722 +0200 @@ -0,0 +1,68 @@ +-- PR debug/80321 + +-- { dg-do compile } +-- { dg-options "-O2 -g" } + +with Debug10_Pkg; use Debug10_Pkg; + +procedure Debug10 (T : Entity_Id) is + + procedure Inner (E : Entity_Id); + pragma Inline (Inner); + + procedure Inner (E : Entity_Id) is + begin + if E /= Empty + and then not Nodes (E + 3).Flag16 + then + Debug10 (E); + end if; + end Inner; + + function Ekind (E : Entity_Id) return Entity_Kind is + begin + return N_To_E (Nodes (E + 1).Nkind); + end Ekind; + +begin + + if T = Empty then + return; + end if; + + Nodes (T + 3).Flag16 := True; + + if Ekind (T) in Object_Kind then + Inner (T); + + elsif Ekind (T) in Type_Kind then + Inner (T); + + if Ekind (T) in Record_Kind then + + if Ekind (T) = E_Class_Wide_Subtype then +Inner (T); + end if; + + elsif Ekind (T) in Array_Kind then + Inner (T); + + elsif Ekind (T) in Access_Kind then + Inner (T); + + elsif Ekind (T) in Scalar_Kind then + + if My_Scalar_Range (T) /= Empty + and then My_Test (My_Scalar_Range (T)) + then +if My_Is_Entity_Name (T) then +