diff mbox

[PR79542,Ada] Fix ICE in dwarf2out.c with nested func. inlining

Message ID e27c3959-8c90-76e1-35c5-3831f3b586b1@adacore.com
State New
Headers show

Commit Message

Pierre-Marie de Rodat May 26, 2017, 2:12 p.m. UTC
Hello,

Thanks for your suggestions, Jason.

On 05/08/2017 06:27 PM, Jason Merrill wrote:
>> That seems like a bug; if gen_typedef_die is going to generate a DIE
>> for a cloned typedef, it needs to associate the type with the DIE.

Hm… gen_typedef_die generates a DIE for a DECL node, but 
modified_type_die look for a DIE for the corresponding TYPE, and of 
course the lookup returns NULL. So just removing the “if 
(DECL_ABSTRACT_P (decl))” condition in gen_typedef_die is not enough to 
make the crash go away.

>> This is unnecessarily complicated; at this point we already know that
>> TYPE_NAME (qualified_type) is non-null and in the variable "name".

Fixed, thanks!

>> gen_typedef_die does create a DIE for them, it just doesn't do it
>> properly.  But we could change gen_typedef_die to abort in that case,
>> making this comment correct.
> 
> Something like this, which also avoids routinely creating DIEs for
> local typedefs that will only be pruned away later; this patch doesn't
> change the size of .debug_info in cc1plus.

I tried this, but I got a crash when compiling the Ada runtime 
(g-awk.adb). I could not extract a reproducer, but the idea is that 
because of the call to set_decl_origin_self, some DECLs have themselves 
as DECL_ABSTRACT_ORIGIN. As a result, my patch in modified_type_die does 
not prevent execution from calling gen_typedef_die with a DECL that has 
a non-null abstract origin. So I have to soften the assertion so that 
this specific case was still allowed in gen_typedef_die.

So here’s the update patch: bootstrapped and regtested fine on x86_64-linux.

Comments

Pierre-Marie de Rodat June 16, 2017, 4:37 p.m. UTC | #1
On 05/26/2017 04:12 PM, Pierre-Marie de Rodat wrote:
> I tried this, but I got a crash when compiling the Ada runtime 
> (g-awk.adb). I could not extract a reproducer, but the idea is that 
> because of the call to set_decl_origin_self, some DECLs have themselves 
> as DECL_ABSTRACT_ORIGIN. As a result, my patch in modified_type_die does 
> not prevent execution from calling gen_typedef_die with a DECL that has 
> a non-null abstract origin. So I have to soften the assertion so that 
> this specific case was still allowed in gen_typedef_die.
> 
> So here’s the update patch: bootstrapped and regtested fine on 
> x86_64-linux.

Ping for the updated patch, originally submitted at 
https://gcc.gnu.org/ml/gcc-patches/2017-05/msg02049.html

Thanks!
Pierre-Marie de Rodat July 24, 2017, 7:41 a.m. UTC | #2
I would like to ping for the updated patch, originally submitted at
<https://gcc.gnu.org/ml/gcc-patches/2017-05/msg02049.html>. Thank you in 
advance!
Pierre-Marie de Rodat July 31, 2017, 8:49 a.m. UTC | #3
Hello,

Ping for the updated patch, originally submitted at
<https://gcc.gnu.org/ml/gcc-patches/2017-05/msg02049.html>. Thank you in 
advance!
Jason Merrill Aug. 7, 2017, 6:42 p.m. UTC | #4
On 05/26/2017 10:12 AM, Pierre-Marie de Rodat wrote:
> On 05/08/2017 06:27 PM, Jason Merrill wrote:
>>> That seems like a bug; if gen_typedef_die is going to generate a DIE
>>> for a cloned typedef, it needs to associate the type with the DIE.
> 
> Hm… gen_typedef_die generates a DIE for a DECL node, but 
> modified_type_die look for a DIE for the corresponding TYPE, and of 
> course the lookup returns NULL. So just removing the “if 
> (DECL_ABSTRACT_P (decl))” condition in gen_typedef_die is not enough to 
> make the crash go away.

Right, the bug seems to be generating the useless DIE in the first place.

>>> gen_typedef_die does create a DIE for them, it just doesn't do it
>>> properly.  But we could change gen_typedef_die to abort in that case,
>>> making this comment correct.
>>
>> Something like this, which also avoids routinely creating DIEs for
>> local typedefs that will only be pruned away later; this patch doesn't
>> change the size of .debug_info in cc1plus.
> 
> I tried this, but I got a crash when compiling the Ada runtime 
> (g-awk.adb). I could not extract a reproducer, but the idea is that 
> because of the call to set_decl_origin_self, some DECLs have themselves 
> as DECL_ABSTRACT_ORIGIN. As a result, my patch in modified_type_die does 
> not prevent execution from calling gen_typedef_die with a DECL that has 
> a non-null abstract origin. So I have to soften the assertion so that 
> this specific case was still allowed in gen_typedef_die.

Perhaps the DECL_ABSTRACT_ORIGIN check in my patch should be 
decl_ultimate_origin instead, which should return null in that case?

Jason
diff mbox

Patch

From 334338c3ac5dbdeb3981a6302259d0be0b5efc11 Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <derodat@adacore.com>
Date: Tue, 9 May 2017 12:24:36 +0200
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 DECLs that have an ultimate
	origin are their own 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): Do nothing for DECLs with an ultimate
	origin.

gcc/testsuite/

	* gnat.dg/debug11.ads, gnat.dg/debug11.adb: New testcase.
---
 gcc/dwarf2out.c                   | 30 +++++++++++++++++++++++++++---
 gcc/testsuite/gnat.dg/debug11.adb | 38 ++++++++++++++++++++++++++++++++++++++
 gcc/testsuite/gnat.dg/debug11.ads |  5 +++++
 3 files changed, 70 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gnat.dg/debug11.adb
 create mode 100644 gcc/testsuite/gnat.dg/debug11.ads

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 98c5157..b4f5a69 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -12510,6 +12510,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);
@@ -24355,7 +24364,10 @@  gen_typedef_die (tree decl, dw_die_ref context_die)
   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);
+    {
+      gcc_assert (origin == decl);
+      add_abstract_origin_attribute (type_die, origin);
+    }
   else
     {
       tree type = TREE_TYPE (decl);
@@ -24531,15 +24543,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;
     }
 
@@ -24858,6 +24878,10 @@  process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die)
   else
     die = NULL;
 
+  if ((origin || DECL_ABSTRACT_ORIGIN (decl))
+      && TREE_CODE (decl_or_origin) == TYPE_DECL)
+    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/gnat.dg/debug11.adb b/gcc/testsuite/gnat.dg/debug11.adb
new file mode 100644
index 0000000..1e89346
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/debug11.adb
@@ -0,0 +1,38 @@ 
+--  { dg-options "-cargs -O2 -g -margs" }
+
+package body Debug11 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 Debug11;
diff --git a/gcc/testsuite/gnat.dg/debug11.ads b/gcc/testsuite/gnat.dg/debug11.ads
new file mode 100644
index 0000000..a53b084
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/debug11.ads
@@ -0,0 +1,5 @@ 
+package Debug11 is
+
+   procedure Compile (P : Natural);
+
+end Debug11;
-- 
2.3.3.199.g52cae64