[PR82155] Fix crash in dwarf2out_abstract_function
authorPierre-Marie de Rodat <derodat@adacore.com>
Mon, 25 Sep 2017 12:26:36 +0000 (12:26 +0000)
committerPierre-Marie de Rodat <pmderodat@gcc.gnu.org>
Mon, 25 Sep 2017 12:26:36 +0000 (12:26 +0000)
This patch is an attempt to fix the crash reported in PR82155.

When generating a C++ class method for a class that is itself nested in
a class method, dwarf2out_early_global_decl currently leaves the
existing context DIE as it is if it already exists.  However, it is
possible that this call happens at a point where this context DIE is
just a declaration that is itself not located in its own context.

From there, if dwarf2out_early_global_decl is not called on any of the
FUNCTION_DECL in the context chain, DIEs will be left badly scoped and
some (such as the nested method) will be removed by the type pruning
machinery.  As a consequence, dwarf2out_abstract_function will will
crash when called on the corresponding DECL because it asserts that the
DECL has a DIE.

This patch fixes this crash making dwarf2out_early_global_decl process
context DIEs the same way we process abstract origins for FUNCTION_DECL:
if the corresponding DIE exists but is only a declaration, call
dwarf2out_decl anyway on it so that it is turned into a more complete
DIE and so that it is relocated in the proper context.

Bootstrapped and regtested on x86_64-linux.

gcc/

PR debug/82155
* dwarf2out.c (dwarf2out_early_global_decl): Call dwarf2out_decl
on the FUNCTION_DECL function context if it has a DIE that is a
declaration.

gcc/testsuite/

* g++.dg/pr82155.C: New testcase.

From-SVN: r253147

gcc/ChangeLog
gcc/dwarf2out.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/pr82155.C [new file with mode: 0644]

index f618113eb6f59dd96536258ce05ae92a6e3f2afa..b3dadab4357beba152c1d8d25b896fa0661b8815 100644 (file)
@@ -1,3 +1,10 @@
+2017-09-25  Pierre-Marie de Rodat  <derodat@adacore.com>
+
+       PR debug/82155
+       * dwarf2out.c (dwarf2out_early_global_decl): Call dwarf2out_decl
+       on the FUNCTION_DECL function context if it has a DIE that is a
+       declaration.
+
 2017-09-25  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/82285
index dda569f78628f87ab3ccd93973caed8d50fe038a..e97ceb61b46ed6cedcae8f424b3c05786be96b34 100644 (file)
@@ -25490,10 +25490,16 @@ dwarf2out_early_global_decl (tree decl)
             so that all nested DIEs are generated at the proper scope in the
             first shot.  */
          tree context = decl_function_context (decl);
-         if (context != NULL && lookup_decl_die (context) == NULL)
+         if (context != NULL)
            {
+             dw_die_ref context_die = lookup_decl_die (context);
              current_function_decl = context;
-             dwarf2out_decl (context);
+
+             /* Avoid emitting DIEs multiple times, but still process CONTEXT
+                enough so that it lands in its own context.  This avoids type
+                pruning issues later on.  */
+             if (context_die == NULL || is_declaration_die (context_die))
+               dwarf2out_decl (context);
            }
 
          /* Emit an abstract origin of a function first.  This happens
index 333e2c8f62c9bd64f5535e28acbc71a1e291b891..8cdcbc66bd4e3f98ce31b033e6d75a55f727ac68 100644 (file)
@@ -1,3 +1,7 @@
+2017-09-25  Pierre-Marie de Rodat  <derodat@adacore.com>
+
+       * g++.dg/pr82155.C: New testcase.
+
 2017-09-25  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/82285
diff --git a/gcc/testsuite/g++.dg/pr82155.C b/gcc/testsuite/g++.dg/pr82155.C
new file mode 100644 (file)
index 0000000..75d9b61
--- /dev/null
@@ -0,0 +1,36 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-g -O2" } */
+
+template <typename a> struct b { a c; };
+template <typename d> struct e { d *operator->(); };
+template <typename d> class h {
+public:
+  typedef e<d> ag;
+};
+class i {
+protected:
+  i(int);
+};
+class j {
+  virtual void k(int) = 0;
+
+public:
+  int f;
+  void l() { k(f); }
+};
+struct m : i {
+  int cn;
+  m() : i(cn) {
+    struct n : j {
+      n() {}
+      void k(int) {}
+    };
+  }
+};
+struct o {
+  o() {
+    for (h<b<b<j *>>>::ag g;;)
+      g->c.c->l();
+  }
+};
+void fn1() { o(); }