Ok.

On Thu, Apr 19, 2018, 12:27 PM Jakub Jelinek <ja...@redhat.com> wrote:

> Hi!
>
> The following testcase ICEs starting with r259457 PR80290 fix.
>
> The problem is that the refcount is just 8-bit and if we need more than 256
> refcounts for one tinst_level, we fail an assertion.
>
> As discovered by Richard, the in_system_header_p member is write-only
> since r138031:
> grep in_system_header_p cp/*.[ch]
> cp/cp-tree.h:  bool in_system_header_p;
> cp/pt.c:  new_level->in_system_header_p = in_system_header_at
> (input_location);
> so we can easily even without using bitfields enlarge the refcount to
> 16-bits and make it far less likely to hit the assertion.
>
> This patch implements also saturation, once the refcount goes to 65535, it
> becomes immutable and we then never return the tinst_level into the free
> list.  It doesn't matter that much, because it is still GC allocated and
> can
> be freed during ggc_collect if nothing refers to it.
>
> I've tested the patch on the testcase also with 8-bit refcount and 255 as
> rlimit_infinity.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> 2018-04-19  Jakub Jelinek  <ja...@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.
>
>         * g++.dg/cpp0x/pr85462.C: New test.
>
> --- gcc/cp/cp-tree.h.jj 2018-04-19 09:42:44.409864659 +0200
> +++ gcc/cp/cp-tree.h    2018-04-19 12:33:25.339085905 +0200
> @@ -5927,14 +5927,19 @@ struct GTY((chain_next ("%h.next"))) tin
>    /* 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);
> --- gcc/cp/pt.c.jj      2018-04-18 10:45:22.901720592 +0200
> +++ gcc/cp/pt.c 2018-04-19 12:33:17.704080557 +0200
> @@ -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;
> @@ -10143,8 +10143,7 @@ push_tinst_level_loc (tree tldcl, tree t
>    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);
> --- gcc/testsuite/g++.dg/cpp0x/pr85462.C.jj     2018-04-19
> 19:16:50.994498502 +0200
> +++ gcc/testsuite/g++.dg/cpp0x/pr85462.C        2018-04-19
> 19:20:38.961594082 +0200
> @@ -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 (); }
> +};
>
>         Jakub
>

Reply via email to