diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 675299aa4cd..c81e024e0e2 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -2687,9 +2687,16 @@ 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 ()); + /* Appease hash_table::check_complete_insertion. */ + *slot = ggc_alloc (); + sat_cache->clear_slot (slot); + } } /* 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 + inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...); + template + concept __weakly_eq_cmp_with + = requires(_Tp __t, _Up __u) { { __u != __t } ; // { dg-error "changed from" } + }; + template + concept regular = is_constructible_v<_Tp> && __weakly_eq_cmp_with<_Tp, _Tp>; + template concept incrementable = true +&& regular<_Iter> +&& requires(_Iter __i) { { __i++ } ;} +; +template +struct iterator_interface +{ + friend constexpr bool operator>=(D lhs, D rhs) requires __weakly_eq_cmp_with { return true; } +}; +template +struct iterator : iterator_interface> +{ + bool operator==(iterator) const; +}; +static_assert(incrementable>); // { dg-error "assert" }