re PR c++/85462 (internal compiler error: in inc_refcount_use, at cp/pt.c:8955)
authorJakub Jelinek <jakub@redhat.com>
Fri, 20 Apr 2018 07:56:52 +0000 (09:56 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 20 Apr 2018 07:56:52 +0000 (09:56 +0200)
PR c++/85462
* cp-tree.h (tinst_level): Remove in_system_header_p member,
change refcount member from unsigned char to unsigned short,
add refcount_infinity static data member, adjust comments.
* pt.c (tinst_level::refcount_infinity): Define.
(inc_refcount_use): Remove assert, don't increment if refcount
is already refcount_infinity, adjust comment.
(dec_refcount_use): Remove assert, don't decrement if refcount
is refcount_infinity, adjust comment.
(push_tinst_level_loc): Formatting fix.

* g++.dg/cpp0x/pr85462.C: New test.

From-SVN: r259516

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/pr85462.C [new file with mode: 0644]

index e4c3deb26fbf708e19aa0ef5341a123adea09f19..099407b9a14302c9c851bbfae5bb7b6341787b1c 100644 (file)
@@ -1,3 +1,16 @@
+2018-04-20  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/85462
+       * cp-tree.h (tinst_level): Remove in_system_header_p member,
+       change refcount member from unsigned char to unsigned short,
+       add refcount_infinity static data member, adjust comments.
+       * pt.c (tinst_level::refcount_infinity): Define.
+       (inc_refcount_use): Remove assert, don't increment if refcount
+       is already refcount_infinity, adjust comment.
+       (dec_refcount_use): Remove assert, don't decrement if refcount
+       is refcount_infinity, adjust comment.
+       (push_tinst_level_loc): Formatting fix.
+
 2018-04-19  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/84611
index 8c5c84e22b2259472c3eff1a57ff9bf276663cf9..5af4928e2fba38d1950f8c58898ad7afcb13db92 100644 (file)
@@ -5927,14 +5927,19 @@ struct GTY((chain_next ("%h.next"))) tinst_level {
   /* The location where the template is instantiated.  */
   location_t locus;
 
-  /* errorcount+sorrycount when we pushed this level.  */
+  /* errorcount + sorrycount when we pushed this level.  */
   unsigned short errors;
 
-  /* True if the location is in a system header.  */
-  bool in_system_header_p;
+  /* Count references to this object.  If refcount reaches
+     refcount_infinity value, we don't increment or decrement the
+     refcount anymore, as the refcount isn't accurate anymore.
+     The object can be still garbage collected if unreferenced from
+     anywhere, which might keep referenced objects referenced longer than
+     otherwise necessary.  Hitting the infinity is rare though.  */
+  unsigned short refcount;
 
-  /* Count references to this object.  */
-  unsigned char refcount;
+  /* Infinity value for the above refcount.  */
+  static const unsigned short refcount_infinity = (unsigned short) ~0;
 };
 
 bool decl_spec_seq_has_spec_p (const cp_decl_specifier_seq *, cp_decl_spec);
index 1370e21ad5957418bde608b91eb6bd5cb0b13ff8..e2a12b963ad23d195cd51d1c739b3f5479543df6 100644 (file)
@@ -8945,15 +8945,14 @@ tinst_level::to_list ()
   return ret;
 }
 
-/* Increment OBJ's refcount.  */
+const unsigned short tinst_level::refcount_infinity;
+
+/* Increment OBJ's refcount unless it is already infinite.  */
 static tinst_level *
 inc_refcount_use (tinst_level *obj)
 {
-  if (obj)
-    {
-      ++obj->refcount;
-      gcc_assert (obj->refcount != 0);
-    }
+  if (obj && obj->refcount != tinst_level::refcount_infinity)
+    ++obj->refcount;
   return obj;
 }
 
@@ -8966,15 +8965,16 @@ tinst_level::free (tinst_level *obj)
   tinst_level_freelist ().free (obj);
 }
 
-/* Decrement OBJ's refcount.  If it reaches zero, release OBJ's DECL
-   and OBJ, and start over with the tinst_level object that used to be
-   referenced by OBJ's NEXT.  */
+/* Decrement OBJ's refcount if not infinite.  If it reaches zero, release
+   OBJ's DECL and OBJ, and start over with the tinst_level object that
+   used to be referenced by OBJ's NEXT.  */
 static void
 dec_refcount_use (tinst_level *obj)
 {
-  while (obj && !--obj->refcount)
+  while (obj
+        && obj->refcount != tinst_level::refcount_infinity
+        && !--obj->refcount)
     {
-      gcc_assert (obj->refcount+1 != 0);
       tinst_level *next = obj->next;
       tinst_level::free (obj);
       obj = next;
@@ -10145,8 +10145,7 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc)
   new_level->tldcl = tldcl;
   new_level->targs = targs;
   new_level->locus = loc;
-  new_level->errors = errorcount+sorrycount;
-  new_level->in_system_header_p = in_system_header_at (input_location);
+  new_level->errors = errorcount + sorrycount;
   new_level->next = NULL;
   new_level->refcount = 0;
   set_refcount_ptr (new_level->next, current_tinst_level);
index 2e8c9a3fbedd23a82e1c467594af26243bbf47a5..3450e1dca70bf8f3d9ed1a13e18c719cb530a9e3 100644 (file)
@@ -1,3 +1,8 @@
+2018-04-20  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/85462
+       * g++.dg/cpp0x/pr85462.C: New test.
+
 2018-04-19  H.J. Lu  <hongjiu.lu@intel.com>
 
        * gcc.target/i386/pr85404.c: Require CET target.
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr85462.C b/gcc/testsuite/g++.dg/cpp0x/pr85462.C
new file mode 100644 (file)
index 0000000..8134d9c
--- /dev/null
@@ -0,0 +1,38 @@
+// PR c++/85462
+// { dg-do compile { target c++11 } }
+
+template <class T> struct D { using d = T *; };
+template <class, class, class> struct E;
+template <class T, class U> struct E<T, U, U> { using d = typename D<T>::d; };
+template <class T> struct G { using d = typename E<T, int, int>::d; };
+template <class T, class U> typename G<T>::d foo (U);
+#define A(n) class A##n {};
+#define B(n) A(n##0) A(n##1) A(n##2) A(n##3) A(n##4) A(n##5) A(n##6) A(n##7) A(n##8) A(n##9)
+#define C(n) B(n##0) B(n##1) B(n##2) B(n##3) B(n##4) B(n##5) B(n##6) B(n##7) B(n##8) B(n##9)
+#define D(n) C(n##0) C(n##1) C(n##2) C(n##3) C(n##4)
+D(1)
+class H;
+template <typename>
+struct I
+{
+  bool bar ();
+#undef A
+#define A(n) void f##n (A##n *);
+D(1)
+  void baz ();
+};
+A1000 v;
+template <typename T>
+bool I<T>::bar ()
+{
+#undef A
+#define A(n) A##n k##n = *foo<A##n> (v); f##n (&k##n);
+D(1)
+  foo<H> (v);
+  baz ();
+  return false;
+}
+struct J : I<int>
+{
+  void qux () { bar (); }
+};