On Tue, 9 May 2023, Patrick Palka wrote:

> After diagnosing and recovering from unstable satisfaction, it's
> possible to evaluate an atom for the first time noisily rather than
> quietly.  The satisfaction cache tries to handle this situation
> gracefully, but apparently not gracefully enough: we inserted an empty
> slot in the cache, and left it empty, which later makes
> hash_table::check_complete_insertion unhappy.  This patch fixes this by
> removing the empty slot in this case.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
>       PR c++/109752
> 
> gcc/cp/ChangeLog:
> 
>       * constraint.cc (satisfaction_cache::satisfaction_cache): In the
>       unexpected case of evaluating an atom for the first time noisily,
>       clear the cache slot that we inserted.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/cpp2a/concepts-pr109752.C: New test.
> ---
>  gcc/cp/constraint.cc                          | 14 +++++++---
>  .../g++.dg/cpp2a/concepts-pr109752.C          | 26 +++++++++++++++++++
>  2 files changed, 37 insertions(+), 3 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-pr109752.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 675299aa4cd..bdaa82c8741 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -2687,9 +2687,17 @@ satisfaction_cache
>        *slot = entry;
>      }
>    else
> -    /* We shouldn't get here, but if we do, let's just leave 'entry'
> -       empty, effectively disabling the cache.  */
> -    return;
> +    {
> +      /* We're evaluating this atom for the first time, and doing so noisily.
> +      This shouldn't happen outside of error recovery situations involving
> +      unstable satisfaction.  Let's just leave 'entry' empty, effectively
> +      disabling the cache, and remove the empty slot.  */
> +      gcc_checking_assert (seen_error ());
> +      /* To appease hash_table::check_complete_insertion.  */
> +      *slot = ggc_alloc<sat_entry> ();
> +      sat_cache->clear_slot (slot);
> +      return;

Whoops, this 'return;' is rather unnecessary, so consider it removed.

> +    }
>  }
>  
>  /* Returns the cached satisfaction result if we have one and we're not
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr109752.C 
> b/gcc/testsuite/g++.dg/cpp2a/concepts-pr109752.C
> new file mode 100644
> index 00000000000..d54ce295e50
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr109752.C
> @@ -0,0 +1,26 @@
> +// PR c++/109752
> +// { dg-do compile { target c++20 } }
> +
> +template <typename _Tp, typename... _Args>
> +  inline constexpr bool is_constructible_v = __is_constructible(_Tp, 
> _Args...);
> +    template<typename _Tp, typename _Up>
> +      concept __weakly_eq_cmp_with
> + = requires(_Tp __t, _Up __u) {    { __u != __t } ; // { dg-error "changed 
> from" }
> + };
> +  template<typename _Tp>
> +    concept regular =  is_constructible_v<_Tp>  && __weakly_eq_cmp_with<_Tp, 
> _Tp>;
> +  template<typename _Iter> concept incrementable = true
> +&& regular<_Iter>
> +&& requires(_Iter __i) { { __i++ } ;}
> +;
> +template<typename D>
> +struct iterator_interface
> +{
> +  friend constexpr bool operator>=(D lhs, D rhs) requires 
> __weakly_eq_cmp_with<D, D> { return true; }
> +};
> +template<typename T>
> +struct iterator : iterator_interface<iterator<T>>
> +{
> +    bool operator==(iterator) const;
> +};
> +static_assert(incrementable<iterator<int>>); // { dg-error "assert" }
> -- 
> 2.40.1.476.g69c786637d
> 
> 

Reply via email to