Re: [PATCH] Fix dwarf2out ICE with self-inlining (PR debug/80321)

2017-04-13 Thread Richard Biener
On Fri, Apr 7, 2017 at 11:42 PM, Jakub Jelinek  wrote:
> 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)

2017-04-07 Thread Jakub Jelinek
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 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 (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
+