diff mbox

Fix dwarf2out ICE with self-inlining (PR debug/80321)

Message ID 20170407214228.GH1914@tucnak
State New
Headers show

Commit Message

Jakub Jelinek April 7, 2017, 9:42 p.m. UTC
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  <jakub@redhat.com>

	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  <ebotcazou@adacore.com>

	* gnat.dg/debug10.adb: New test.
	* gnat.dg/debug10_pkg.ads: New helper.


	Jakub

Comments

Richard Biener April 13, 2017, 10:40 a.m. UTC | #1
On Fri, Apr 7, 2017 at 11:42 PM, Jakub Jelinek <jakub@redhat.com> 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  <jakub@redhat.com>
>
>         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  <ebotcazou@adacore.com>
>
>         * gnat.dg/debug10.adb: New test.
>         * gnat.dg/debug10_pkg.ads: New helper.
>
> --- gcc/dwarf2out.c.jj  2017-04-07 11:46:48.000000000 +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.c        2017-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.jj        2017-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
> +               Inner (T);
> +            end if;
> +
> +            if My_Is_Entity_Name (T) then
> +               Inner (T);
> +            end if;
> +         end if;
> +      end if;
> +   end if;
> +end;
> --- gcc/testsuite/gnat.dg/debug10_pkg.ads.jj    2017-04-07 20:24:47.384433302 +0200
> +++ gcc/testsuite/gnat.dg/debug10_pkg.ads       2017-04-07 20:24:22.000000000 +0200
> @@ -0,0 +1,138 @@
> +with Unchecked_Conversion;
> +
> +package Debug10_Pkg is
> +
> +   type Node_Id is range 0 .. 99_999_999;
> +
> +   Empty : constant Node_Id := 0;
> +
> +   subtype Entity_Id is Node_Id;
> +
> +   type Union_Id is new Integer;
> +
> +   function My_Is_Entity_Name (N : Node_Id) return Boolean;
> +
> +   function My_Scalar_Range (Id : Entity_Id) return Node_Id;
> +
> +   function My_Test (N : Node_Id) return Boolean;
> +
> +   type Node_Kind is (N_Unused_At_Start, N_Unused_At_End);
> +
> +   type Entity_Kind is (
> +
> +      E_Void,
> +      E_Component,
> +      E_Constant,
> +      E_Discriminant,
> +      E_Loop_Parameter,
> +      E_Variable,
> +      E_Out_Parameter,
> +      E_In_Out_Parameter,
> +      E_In_Parameter,
> +      E_Generic_In_Out_Parameter,
> +      E_Generic_In_Parameter,
> +      E_Named_Integer,
> +      E_Named_Real,
> +      E_Enumeration_Type,
> +      E_Enumeration_Subtype,
> +      E_Signed_Integer_Type,
> +      E_Signed_Integer_Subtype,
> +      E_Modular_Integer_Type,
> +      E_Modular_Integer_Subtype,
> +      E_Ordinary_Fixed_Point_Type,
> +      E_Ordinary_Fixed_Point_Subtype,
> +      E_Decimal_Fixed_Point_Type,
> +      E_Decimal_Fixed_Point_Subtype,
> +      E_Floating_Point_Type,
> +      E_Floating_Point_Subtype,
> +      E_Access_Type,
> +      E_Access_Subtype,
> +      E_Access_Attribute_Type,
> +      E_Allocator_Type,
> +      E_General_Access_Type,
> +      E_Access_Subprogram_Type,
> +      E_Anonymous_Access_Subprogram_Type,
> +      E_Access_Protected_Subprogram_Type,
> +      E_Anonymous_Access_Protected_Subprogram_Type,
> +      E_Anonymous_Access_Type,
> +      E_Array_Type,
> +      E_Array_Subtype,
> +      E_String_Literal_Subtype,
> +      E_Class_Wide_Type,
> +      E_Class_Wide_Subtype,
> +      E_Record_Type,
> +      E_Record_Subtype,
> +      E_Record_Type_With_Private,
> +      E_Record_Subtype_With_Private,
> +      E_Private_Type,
> +      E_Private_Subtype,
> +      E_Limited_Private_Type,
> +      E_Limited_Private_Subtype,
> +      E_Incomplete_Type,
> +      E_Incomplete_Subtype,
> +      E_Task_Type,
> +      E_Task_Subtype,
> +      E_Protected_Type,
> +      E_Protected_Subtype,
> +      E_Exception_Type,
> +      E_Subprogram_Type,
> +      E_Enumeration_Literal,
> +      E_Function,
> +      E_Operator,
> +      E_Procedure,
> +      E_Abstract_State,
> +      E_Entry,
> +      E_Entry_Family,
> +      E_Block,
> +      E_Entry_Index_Parameter,
> +      E_Exception,
> +      E_Generic_Function,
> +      E_Generic_Procedure,
> +      E_Generic_Package,
> +      E_Label,
> +      E_Loop,
> +      E_Return_Statement,
> +      E_Package,
> +      E_Package_Body,
> +      E_Protected_Object,
> +      E_Protected_Body,
> +      E_Task_Body,
> +      E_Subprogram_Body
> +   );
> +
> +   subtype Access_Kind                 is Entity_Kind range
> +       E_Access_Type ..
> +       E_Anonymous_Access_Type;
> +
> +   subtype Array_Kind                  is Entity_Kind range
> +       E_Array_Type ..
> +       E_String_Literal_Subtype;
> +
> +   subtype Object_Kind                 is Entity_Kind range
> +       E_Component ..
> +       E_Generic_In_Parameter;
> +
> +   subtype Record_Kind                 is Entity_Kind range
> +       E_Class_Wide_Type ..
> +       E_Record_Subtype_With_Private;
> +
> +   subtype Scalar_Kind                 is Entity_Kind range
> +       E_Enumeration_Type ..
> +       E_Floating_Point_Subtype;
> +
> +   subtype Type_Kind                   is Entity_Kind range
> +       E_Enumeration_Type ..
> +       E_Subprogram_Type;
> +
> +   type Node_Record (Is_Extension : Boolean := False) is record
> +      Flag16 : Boolean;
> +      Nkind : Node_Kind;
> +   end record;
> +
> +   function N_To_E is new Unchecked_Conversion (Node_Kind, Entity_Kind);
> +
> +   type Arr is array (Node_Id) of Node_Record;
> +
> +   Nodes : Arr;
> +
> +end Debug10_Pkg;
>
>         Jakub
diff mbox

Patch

--- gcc/dwarf2out.c.jj	2017-04-07 11:46:48.000000000 +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.c	2017-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.jj	2017-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
+               Inner (T);
+            end if;
+
+            if My_Is_Entity_Name (T) then
+               Inner (T);
+            end if;
+         end if;
+      end if;
+   end if;
+end;
--- gcc/testsuite/gnat.dg/debug10_pkg.ads.jj	2017-04-07 20:24:47.384433302 +0200
+++ gcc/testsuite/gnat.dg/debug10_pkg.ads	2017-04-07 20:24:22.000000000 +0200
@@ -0,0 +1,138 @@ 
+with Unchecked_Conversion;
+
+package Debug10_Pkg is
+
+   type Node_Id is range 0 .. 99_999_999;
+
+   Empty : constant Node_Id := 0;
+
+   subtype Entity_Id is Node_Id;
+
+   type Union_Id is new Integer;
+
+   function My_Is_Entity_Name (N : Node_Id) return Boolean;
+
+   function My_Scalar_Range (Id : Entity_Id) return Node_Id;
+
+   function My_Test (N : Node_Id) return Boolean;
+
+   type Node_Kind is (N_Unused_At_Start, N_Unused_At_End);
+
+   type Entity_Kind is (
+
+      E_Void,
+      E_Component,
+      E_Constant,
+      E_Discriminant,
+      E_Loop_Parameter,
+      E_Variable,
+      E_Out_Parameter,
+      E_In_Out_Parameter,
+      E_In_Parameter,
+      E_Generic_In_Out_Parameter,
+      E_Generic_In_Parameter,
+      E_Named_Integer,
+      E_Named_Real,
+      E_Enumeration_Type,
+      E_Enumeration_Subtype,
+      E_Signed_Integer_Type,
+      E_Signed_Integer_Subtype,
+      E_Modular_Integer_Type,
+      E_Modular_Integer_Subtype,
+      E_Ordinary_Fixed_Point_Type,
+      E_Ordinary_Fixed_Point_Subtype,
+      E_Decimal_Fixed_Point_Type,
+      E_Decimal_Fixed_Point_Subtype,
+      E_Floating_Point_Type,
+      E_Floating_Point_Subtype,
+      E_Access_Type,
+      E_Access_Subtype,
+      E_Access_Attribute_Type,
+      E_Allocator_Type,
+      E_General_Access_Type,
+      E_Access_Subprogram_Type,
+      E_Anonymous_Access_Subprogram_Type,
+      E_Access_Protected_Subprogram_Type,
+      E_Anonymous_Access_Protected_Subprogram_Type,
+      E_Anonymous_Access_Type,
+      E_Array_Type,
+      E_Array_Subtype,
+      E_String_Literal_Subtype,
+      E_Class_Wide_Type,
+      E_Class_Wide_Subtype,
+      E_Record_Type,
+      E_Record_Subtype,
+      E_Record_Type_With_Private,
+      E_Record_Subtype_With_Private,
+      E_Private_Type,
+      E_Private_Subtype,
+      E_Limited_Private_Type,
+      E_Limited_Private_Subtype,
+      E_Incomplete_Type,
+      E_Incomplete_Subtype,
+      E_Task_Type,
+      E_Task_Subtype,
+      E_Protected_Type,
+      E_Protected_Subtype,
+      E_Exception_Type,
+      E_Subprogram_Type,
+      E_Enumeration_Literal,
+      E_Function,
+      E_Operator,
+      E_Procedure,
+      E_Abstract_State,
+      E_Entry,
+      E_Entry_Family,
+      E_Block,
+      E_Entry_Index_Parameter,
+      E_Exception,
+      E_Generic_Function,
+      E_Generic_Procedure,
+      E_Generic_Package,
+      E_Label,
+      E_Loop,
+      E_Return_Statement,
+      E_Package,
+      E_Package_Body,
+      E_Protected_Object,
+      E_Protected_Body,
+      E_Task_Body,
+      E_Subprogram_Body
+   );
+
+   subtype Access_Kind                 is Entity_Kind range
+       E_Access_Type ..
+       E_Anonymous_Access_Type;
+
+   subtype Array_Kind                  is Entity_Kind range
+       E_Array_Type ..
+       E_String_Literal_Subtype;
+
+   subtype Object_Kind                 is Entity_Kind range
+       E_Component ..
+       E_Generic_In_Parameter;
+
+   subtype Record_Kind                 is Entity_Kind range
+       E_Class_Wide_Type ..
+       E_Record_Subtype_With_Private;
+
+   subtype Scalar_Kind                 is Entity_Kind range
+       E_Enumeration_Type ..
+       E_Floating_Point_Subtype;
+
+   subtype Type_Kind                   is Entity_Kind range
+       E_Enumeration_Type ..
+       E_Subprogram_Type;
+
+   type Node_Record (Is_Extension : Boolean := False) is record
+      Flag16 : Boolean;
+      Nkind : Node_Kind;
+   end record;
+
+   function N_To_E is new Unchecked_Conversion (Node_Kind, Entity_Kind);
+
+   type Arr is array (Node_Id) of Node_Record;
+
+   Nodes : Arr;
+
+end Debug10_Pkg;