From 32121b96b6163a280e56a65e9a0295eb5343b397 Mon Sep 17 00:00:00 2001
From: Jakub Jelinek <jakub@redhat.com>
Date: Wed, 17 Apr 2002 19:17:55 +0200
Subject: [PATCH] re PR c++/6316 (trap when compiling file)

	PR c++/6316
	* decl2.c (finish_file): Clear DECL_EXTERNAL in a separate loop
	before expanding.

	* g++.dg/opt/inline1.C: New test.

From-SVN: r52434
---
 gcc/cp/ChangeLog                   |  6 +++++
 gcc/cp/decl2.c                     | 11 +++++++-
 gcc/testsuite/ChangeLog            |  2 ++
 gcc/testsuite/g++.dg/opt/inline1.C | 43 ++++++++++++++++++++++++++++++
 4 files changed, 61 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/opt/inline1.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 4f41e4f58a34..b7e31a4fdc5b 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2002-04-17  Jakub Jelinek  <jakub@redhat.com>
+
+	PR c++/6316
+	* decl2.c (finish_file): Clear DECL_EXTERNAL in a separate loop
+	before expanding.
+
 2002-04-16  Mark Mitchell  <mark@codesourcery.com>
 
 	* init.c (begin_init_stmts): Remove commented out code.
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 2eece8aed05a..1b4daa100139 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -3432,7 +3432,11 @@ finish_file ()
 	 not defined when they really are.  This keeps these functions
 	 from being put out unnecessarily.  But, we must stop lying
 	 when the functions are referenced, or if they are not comdat
-	 since they need to be put out now.  */
+	 since they need to be put out now.
+	 This is done in a separate for cycle, because if some deferred
+	 function is contained in another deferred function later in
+	 deferred_fns varray, rest_of_compilation would skip this
+	 function and we really cannot expand the same function twice. */
       for (i = 0; i < deferred_fns_used; ++i)
 	{
 	  tree decl = VARRAY_TREE (deferred_fns, i);
@@ -3441,6 +3445,11 @@ finish_file ()
 	      && DECL_INITIAL (decl)
 	      && DECL_NEEDED_P (decl))
 	    DECL_EXTERNAL (decl) = 0;
+	}
+
+      for (i = 0; i < deferred_fns_used; ++i)
+	{
+	  tree decl = VARRAY_TREE (deferred_fns, i);
 
 	  /* If we're going to need to write this function out, and
 	     there's already a body for it, create RTL for it now.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 36ea8b773b27..3fb38ece2d4e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -2,6 +2,8 @@
 
 	* gcc.dg/20020416-1.c: New test.
 
+	* g++.dg/opt/inline1.C: New test.
+
 2002-04-16  Jakub Jelinek  <jakub@redhat.com>
 
 	* gcc.dg/altivec-5.c: New test.
diff --git a/gcc/testsuite/g++.dg/opt/inline1.C b/gcc/testsuite/g++.dg/opt/inline1.C
new file mode 100644
index 000000000000..55b931138a11
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/inline1.C
@@ -0,0 +1,43 @@
+// PR c++/6316
+// This testcase ICEd because when deferred bar()::F::F() was being
+// expanded, containing bar() was still deferred and had DECL_EXTERNAL set
+// (and DECL_NOT_REALLY_EXTERN too).
+// { dg-do compile }
+// { dg-options "-O3" }
+
+struct A { ~A() throw() {} };
+template<typename T, typename U> struct B { U a; B(const T *); };
+typedef B<char, A> C;
+struct D { D(); };
+struct E { virtual ~E(); };
+
+E *bar ();
+
+void
+foo ()
+{
+  E *a = bar ();
+}
+
+extern char *z [];
+
+E *
+bar ()
+{
+  struct F : public E
+  {
+    F ()
+    {
+      for (int i = 0; i < 2; i++)
+	C e = z[i];
+    }
+    D x, y;
+  };
+  return new F ();
+}
+
+int
+main ()
+{
+  foo ();
+}
-- 
GitLab