Fix algo constexpr tests in Debug mode

Message ID d0e2e7a0-8a94-08c4-6e6f-61eadb5d2958@gmail.com
State New
Headers show
Series
  • Fix algo constexpr tests in Debug mode
Related show

Commit Message

François Dumont Sept. 28, 2019, 9:12 p.m.
Here is what I just commited.

I try to use the asm trick in the _GLIBCXX_DEBUG_VERIFY_COND_AT but 
didn't notice any enhancement. So for now I kept my solution to just 
have a non-constexpr call compiler error.

I fix my patch to use __builtin_is_constant_evaluated rather than 
std::is_constant_evaluated in __valid_range.

     * include/bits/stl_algobase.h (__memmove): Return _Tp*.
     (__memmove): Loop as long as __n is not 0.
     (__copy_move<>::__copy_m): Likewise.
     (__copy_move_backward<>::__copy_move_b): Likewise.
     * testsuite/25_algorithms/copy/constexpr.cc: Add check on copied 
values.
     * testsuite/25_algorithms/copy_backward/constexpr.cc: Likewise.
     * testsuite/25_algorithms/copy/constexpr_neg.cc: New.
     * testsuite/25_algorithms/copy_backward/constexpr.cc: New.

     * include/debug/forward_list
(_Sequence_traits<__debug::forward_list<>>::_S_size): Returns __dp_sign
     distance when not empty.
     * include/debug/list
     (_Sequence_traits<__debug::list<>>::_S_size): Likewise.
     * include/debug/helper_functions.h (__dp_sign_max_size): New
     _Distance_precision enum entry.
     * include/debug/safe_iterator.h
     (__copy_move_a(_II, _II, const _Safe_iterator<>&)): Check for output
     iterator _M_can_advance as soon as input range distance precision is
     strictly higher than __dp_size.
     (__copy_move_a(const _Safe_iterator<>&, const _Safe_iterator<>&,
     const _Safe_iterator<>&)): Likewise.
     (__copy_move_backward_a(_II, _II, const _Safe_iterator<>&)): Likewise.
     (__copy_move_backward_a(const _Safe_iterator<>&,
     const _Safe_iterator<>&, const _Safe_iterator<>&)): Likewise.
     (__equal_aux(_II, _II, const _Safe_iterator<>&)): Likewise.
     (__equal_aux(const _Safe_iterator<>&,
     const _Safe_iterator<>&, const _Safe_iterator<>&)): Likewise.

François

On 9/27/19 6:45 PM, Jonathan Wakely wrote:
> On 27/09/19 18:24 +0200, François Dumont wrote:

>> On 9/27/19 2:11 PM, Jonathan Wakely wrote:

>>> On 19/09/19 22:27 +0200, François Dumont wrote:

>>>> Hi

>>>>

>>>>     I start working on making recently added constexpr tests to 

>>>> work in Debug mode.

>>>

>>> The attached patch seems to be necessary for that, right?

>>>

>>>

>> On my side I had done this, almost the same.

>>

>> For the moment there is a FIXME in macros.h to find out how to 

>> generate a nice compilation error when the condition is not meant.

>>

>> static_assert can't be called in this context, too bad.

>>

>> I also try to define a function with a 

>> __attribute__((__error__("because"))) attribute. But when I make it 

>> constexpr gcc complains about missing definition. When I provide a 

>> definition gcc complains that this attribute must be on a 

>> declaration. And when I split declaration and definition gcc does not 

>> produce the expected compilation error.

>

> Yes, I've tried similar things without success.

>

>> Unless you have the solution I consider that we need help from the 

>> front-end.

>>

>> For the moment if Debug mode finds a problem it will be reported as 

>> _M_error function not being constexpr !

>

> A reasonable workaround is to do:

>

> #ifdef _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED

>  if (__builtin_is_constant_evaluated())

>    asm("Debug Mode assertion failed");

>  else

> #endif

>  if (!(Cond))

>    __gnu_debug::_Error_formatter::...

>

> The builtin is available even for C++98, whereas

> std::is_constant_evaluated() is only available for C++20.

>

> This produces errors that include lines like:

>

> asm.cc:12:17:   in ‘constexpr’ expansion of ‘f(-1)’

> asm.cc:4:7: error: inline assembly is not a constant expression

>    4 |       asm("debug mode assertion failed");

>      |       ^~~

> asm.cc:8:3: note: in expansion of macro ‘CHECK’

>    8 |   _GLIBCXX_ASSERT(i > 0);

>      |   ^~~~~

> asm.cc:4:7: note: only unevaluated inline assembly is allowed in a 

> ‘constexpr’ function in C++2a

>    4 |       asm("debug mode assertion failed");

>      |       ^~~

> asm.cc:8:3: note: in expansion of macro ‘CHECK’

>    8 |   CHECK(i > 0);

>      |   ^~~~~

>

> It's not ideal, but it does show the failed condition and the text

> "debug mode assertion failed" (or whatever message you choose to use

> there).

>

>

>

Comments

Jonathan Wakely Sept. 30, 2019, 9:03 a.m. | #1
On 28/09/19 23:12 +0200, François Dumont wrote:
>Here is what I just commited.


Thanks. In my branch I had a lot more _GLIBCXX20_CONSTEXPR additions
in the debug mode headers. Is it not needed on __check_singular,
__foreign_iterator etc. ?

>I try to use the asm trick in the _GLIBCXX_DEBUG_VERIFY_COND_AT but 

>didn't notice any enhancement. So for now I kept my solution to just 

>have a non-constexpr call compiler error.


You won't see any improvement in the testsuite, because the compiler
flags for the testsuite suppress diagnostic notes. But I'd expect it
to give better output for users with the default compiler flags.


>diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h

>index a672f8b2b39..f25b8b76df6 100644

>--- a/libstdc++-v3/include/bits/stl_algo.h

>+++ b/libstdc++-v3/include/bits/stl_algo.h

>@@ -5054,8 +5054,8 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO

>    *  @param  __last1   Another iterator.

>    *  @param  __last2   Another iterator.

>    *  @param  __result  An iterator pointing to the end of the merged range.

>-   *  @return         An iterator pointing to the first element <em>not less

>-   *                  than</em> @e val.

>+   *  @return   An output iterator equal to @p __result + (__last1 - __first1)

>+   *            + (__last2 - __first2).

>    *

>    *  Merges the ranges @p [__first1,__last1) and @p [__first2,__last2) into

>    *  the sorted range @p [__result, __result + (__last1-__first1) +

>@@ -5102,8 +5102,8 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO

>    *  @param  __last2   Another iterator.

>    *  @param  __result  An iterator pointing to the end of the merged range.

>    *  @param  __comp    A functor to use for comparisons.

>-   *  @return         An iterator pointing to the first element "not less

>-   *                  than" @e val.

>+   *  @return   An output iterator equal to @p __result + (__last1 - __first1)

>+   *            + (__last2 - __first2).

>    *

>    *  Merges the ranges @p [__first1,__last1) and @p [__first2,__last2) into

>    *  the sorted range @p [__result, __result + (__last1-__first1) +


These changes are fine but should have been a separate, unrelated
commit.


>@@ -157,10 +192,16 @@ namespace __gnu_debug

>    *  otherwise.

>   */

>   template<typename _InputIterator>

>+    _GLIBCXX20_CONSTEXPR

>     inline bool

>     __valid_range(_InputIterator __first, _InputIterator __last,

> 		  typename _Distance_traits<_InputIterator>::__type& __dist)

>     {

>+#ifdef __cpp_lib_is_constant_evaluated

>+      if (std::is_constant_evaluated())

>+	// Detected by the compiler directly.

>+	return true;

>+#endif


Should this be using the built-in, not the C++20 function?

In practice it's probably equivalent, because the function is only
going to be constant-evaluated when called from C++20 code, and in
that case the std::is_constant_evaluated() function will be available.
It just seems inconsistent to use the built-in in one place and not in
the other.

>       typedef typename std::__is_integer<_InputIterator>::__type _Integral;

>       return __valid_range_aux(__first, __last, __dist, _Integral());

>     }

>@@ -180,11 +221,17 @@ namespace __gnu_debug

> #endif

> 

>   template<typename _InputIterator>

>+    _GLIBCXX_CONSTEXPR

>     inline bool

>     __valid_range(_InputIterator __first, _InputIterator __last)

>     {

>-      typename _Distance_traits<_InputIterator>::__type __dist;

>-      return __valid_range(__first, __last, __dist);

>+#ifdef _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED

>+      if (__builtin_is_constant_evaluated())

>+	// Detected by the compiler directly.

>+	return true;

>+#endif

>+      typedef typename std::__is_integer<_InputIterator>::__type _Integral;

>+      return __valid_range_aux(__first, __last, _Integral());

>     }

> 

>   template<typename _Iterator, typename _Sequence, typename _Category>
François Dumont Sept. 30, 2019, 8:21 p.m. | #2
On 9/30/19 11:03 AM, Jonathan Wakely wrote:
> On 28/09/19 23:12 +0200, François Dumont wrote:

>> Here is what I just commited.

>

> Thanks. In my branch I had a lot more _GLIBCXX20_CONSTEXPR additions

> in the debug mode headers. Is it not needed on __check_singular,

> __foreign_iterator etc. ?


Yes, I know, I just limited myself to fixing testsuite tests for the 
moment. I'll check if those need it too.

>

>> I try to use the asm trick in the _GLIBCXX_DEBUG_VERIFY_COND_AT but 

>> didn't notice any enhancement. So for now I kept my solution to just 

>> have a non-constexpr call compiler error.

>

> You won't see any improvement in the testsuite, because the compiler

> flags for the testsuite suppress diagnostic notes. But I'd expect it

> to give better output for users with the default compiler flags.

Ok, I didn't know, I'll give it another try then outside testsuite.
>

>

>> diff --git a/libstdc++-v3/include/bits/stl_algo.h 

>> b/libstdc++-v3/include/bits/stl_algo.h

>> index a672f8b2b39..f25b8b76df6 100644

>> --- a/libstdc++-v3/include/bits/stl_algo.h

>> +++ b/libstdc++-v3/include/bits/stl_algo.h

>> @@ -5054,8 +5054,8 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO

>>    *  @param  __last1   Another iterator.

>>    *  @param  __last2   Another iterator.

>>    *  @param  __result  An iterator pointing to the end of the merged 

>> range.

>> -   *  @return         An iterator pointing to the first element 

>> <em>not less

>> -   *                  than</em> @e val.

>> +   *  @return   An output iterator equal to @p __result + (__last1 - 

>> __first1)

>> +   *            + (__last2 - __first2).

>>    *

>>    *  Merges the ranges @p [__first1,__last1) and @p 

>> [__first2,__last2) into

>>    *  the sorted range @p [__result, __result + (__last1-__first1) +

>> @@ -5102,8 +5102,8 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO

>>    *  @param  __last2   Another iterator.

>>    *  @param  __result  An iterator pointing to the end of the merged 

>> range.

>>    *  @param  __comp    A functor to use for comparisons.

>> -   *  @return         An iterator pointing to the first element "not 

>> less

>> -   *                  than" @e val.

>> +   *  @return   An output iterator equal to @p __result + (__last1 - 

>> __first1)

>> +   *            + (__last2 - __first2).

>>    *

>>    *  Merges the ranges @p [__first1,__last1) and @p 

>> [__first2,__last2) into

>>    *  the sorted range @p [__result, __result + (__last1-__first1) +

>

> These changes are fine but should have been a separate, unrelated

> commit.


Ok, sorry, I consider that just a comment change was fine.


>

>

>> @@ -157,10 +192,16 @@ namespace __gnu_debug

>>    *  otherwise.

>>   */

>>   template<typename _InputIterator>

>> +    _GLIBCXX20_CONSTEXPR

>>     inline bool

>>     __valid_range(_InputIterator __first, _InputIterator __last,

>>           typename _Distance_traits<_InputIterator>::__type& __dist)

>>     {

>> +#ifdef __cpp_lib_is_constant_evaluated

>> +      if (std::is_constant_evaluated())

>> +    // Detected by the compiler directly.

>> +    return true;

>> +#endif

>

> Should this be using the built-in, not the C++20 function?

>

>

> In practice it's probably equivalent, because the function is only

> going to be constant-evaluated when called from C++20 code, and in

> that case the std::is_constant_evaluated() function will be available.



Yes, this is why I did it this way. And moreover it is using std::pair 
move assignment operator which is also C++20 constexpr.

>

> It just seems inconsistent to use the built-in in one place and not in

> the other.


It is also the reason why the simple simple __valid_range is not using 
the other anymore.

Maybe once I'll have check all the algo calls I'll find out that this 
one need _GLIBCXX_CONSTEXPR.

I got the sensation that library is being 'constexpr' decorated only 
when needed and when properly Standardise so are the Debug helpers.

François
Jonathan Wakely Oct. 1, 2019, 11:20 a.m. | #3
On 30/09/19 22:21 +0200, François Dumont wrote:
>On 9/30/19 11:03 AM, Jonathan Wakely wrote:

>>These changes are fine but should have been a separate, unrelated

>>commit.

>

>Ok, sorry, I consider that just a comment change was fine.


It's fine, but it is unrelated so should be a separate commit. That
makes it easier to backport the documentation fix independently of the
rest of the patch. Or if the patch had to be reverted for some reason,
we wouldn't also revert the doc fix if it was in a separate commit.

Unrelated changes should usually be separate commits.


>>>@@ -157,10 +192,16 @@ namespace __gnu_debug

>>>   *  otherwise.

>>>  */

>>>  template<typename _InputIterator>

>>>+    _GLIBCXX20_CONSTEXPR

>>>    inline bool

>>>    __valid_range(_InputIterator __first, _InputIterator __last,

>>>          typename _Distance_traits<_InputIterator>::__type& __dist)

>>>    {

>>>+#ifdef __cpp_lib_is_constant_evaluated

>>>+      if (std::is_constant_evaluated())

>>>+    // Detected by the compiler directly.

>>>+    return true;

>>>+#endif

>>

>>Should this be using the built-in, not the C++20 function?

>>

>>

>>In practice it's probably equivalent, because the function is only

>>going to be constant-evaluated when called from C++20 code, and in

>>that case the std::is_constant_evaluated() function will be available.

>

>

>Yes, this is why I did it this way. And moreover it is using std::pair 

>move assignment operator which is also C++20 constexpr.

>

>>

>>It just seems inconsistent to use the built-in in one place and not in

>>the other.

>

>It is also the reason why the simple simple __valid_range is not using 

>the other anymore.

>

>Maybe once I'll have check all the algo calls I'll find out that this 

>one need _GLIBCXX_CONSTEXPR.

>

>I got the sensation that library is being 'constexpr' decorated only 

>when needed and when properly Standardise so are the Debug helpers.


The standard says when something should be a constexpr function, we
don't get to decide. So if a function is not constexpr in C++17 and is
constexpr in C++20, we have to conform to that. For functions that are
not part of the standard and are our own implementation details, we
can choose when to make them constexpr. We could make all the debug
helpers use _GLIBCXX14_CONSTEXPR (or even _GLIBCXX_CONSTEXPR if they
meet the very restrictive C++11 constexpr requirements) but since they
are never going to be constant evaluated except in C++20, there
doesn't seem to be much point to doing that.
Jonathan Wakely Oct. 23, 2019, 3:26 p.m. | #4
On 28/09/19 23:12 +0200, François Dumont wrote:
>Here is what I just commited.

>

>I try to use the asm trick in the _GLIBCXX_DEBUG_VERIFY_COND_AT but 

>didn't notice any enhancement. So for now I kept my solution to just 

>have a non-constexpr call compiler error.

>

>I fix my patch to use __builtin_is_constant_evaluated rather than 

>std::is_constant_evaluated in __valid_range.

>

>    * include/bits/stl_algobase.h (__memmove): Return _Tp*.

>    (__memmove): Loop as long as __n is not 0.

>    (__copy_move<>::__copy_m): Likewise.

>    (__copy_move_backward<>::__copy_move_b): Likewise.

>    * testsuite/25_algorithms/copy/constexpr.cc: Add check on copied 

>values.

>    * testsuite/25_algorithms/copy_backward/constexpr.cc: Likewise.

>    * testsuite/25_algorithms/copy/constexpr_neg.cc: New.

>    * testsuite/25_algorithms/copy_backward/constexpr.cc: New.

>

>    * include/debug/forward_list

>(_Sequence_traits<__debug::forward_list<>>::_S_size): Returns __dp_sign

>    distance when not empty.

>    * include/debug/list

>    (_Sequence_traits<__debug::list<>>::_S_size): Likewise.

>    * include/debug/helper_functions.h (__dp_sign_max_size): New

>    _Distance_precision enum entry.

>    * include/debug/safe_iterator.h

>    (__copy_move_a(_II, _II, const _Safe_iterator<>&)): Check for output

>    iterator _M_can_advance as soon as input range distance precision is

>    strictly higher than __dp_size.

>    (__copy_move_a(const _Safe_iterator<>&, const _Safe_iterator<>&,

>    const _Safe_iterator<>&)): Likewise.

>    (__copy_move_backward_a(_II, _II, const _Safe_iterator<>&)): Likewise.

>    (__copy_move_backward_a(const _Safe_iterator<>&,

>    const _Safe_iterator<>&, const _Safe_iterator<>&)): Likewise.

>    (__equal_aux(_II, _II, const _Safe_iterator<>&)): Likewise.

>    (__equal_aux(const _Safe_iterator<>&,

>    const _Safe_iterator<>&, const _Safe_iterator<>&)): Likewise.


I'm going to commit this small fix.
commit d78a141b86aca5a1265ec2df96428ef387492a1f
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Oct 23 16:19:28 2019 +0100

    Only qualify function as constexpr for C++14 and later
    
    This helper function is not a valid constexpr function in C++11, so
    should only be marked constexpr for C++14 and later.
    
            * include/debug/helper_functions.h (__valid_range): Change
            _GLIBCXX_CONSTEXPR to _GLIBCXX14_CONSTEXPR.

diff --git a/libstdc++-v3/include/debug/helper_functions.h b/libstdc++-v3/include/debug/helper_functions.h
index 5a920bb9a6f..c3e7478f649 100644
--- a/libstdc++-v3/include/debug/helper_functions.h
+++ b/libstdc++-v3/include/debug/helper_functions.h
@@ -221,7 +221,7 @@ namespace __gnu_debug
 #endif
 
   template<typename _InputIterator>
-    _GLIBCXX_CONSTEXPR
+    _GLIBCXX14_CONSTEXPR
     inline bool
     __valid_range(_InputIterator __first, _InputIterator __last)
     {

Patch

diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h
index a672f8b2b39..f25b8b76df6 100644
--- a/libstdc++-v3/include/bits/stl_algo.h
+++ b/libstdc++-v3/include/bits/stl_algo.h
@@ -5054,8 +5054,8 @@  _GLIBCXX_BEGIN_NAMESPACE_ALGO
    *  @param  __last1   Another iterator.
    *  @param  __last2   Another iterator.
    *  @param  __result  An iterator pointing to the end of the merged range.
-   *  @return         An iterator pointing to the first element <em>not less
-   *                  than</em> @e val.
+   *  @return   An output iterator equal to @p __result + (__last1 - __first1)
+   *            + (__last2 - __first2).
    *
    *  Merges the ranges @p [__first1,__last1) and @p [__first2,__last2) into
    *  the sorted range @p [__result, __result + (__last1-__first1) +
@@ -5102,8 +5102,8 @@  _GLIBCXX_BEGIN_NAMESPACE_ALGO
    *  @param  __last2   Another iterator.
    *  @param  __result  An iterator pointing to the end of the merged range.
    *  @param  __comp    A functor to use for comparisons.
-   *  @return         An iterator pointing to the first element "not less
-   *                  than" @e val.
+   *  @return   An output iterator equal to @p __result + (__last1 - __first1)
+   *            + (__last2 - __first2).
    *
    *  Merges the ranges @p [__first1,__last1) and @p [__first2,__last2) into
    *  the sorted range @p [__result, __result + (__last1-__first1) +
diff --git a/libstdc++-v3/include/debug/functions.h b/libstdc++-v3/include/debug/functions.h
index f87838692c6..8c385b87244 100644
--- a/libstdc++-v3/include/debug/functions.h
+++ b/libstdc++-v3/include/debug/functions.h
@@ -219,6 +219,7 @@  namespace __gnu_debug
   // Can't check if an input iterator sequence is sorted, because we
   // can't step through the sequence.
   template<typename _InputIterator>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_sorted_aux(const _InputIterator&, const _InputIterator&,
                        std::input_iterator_tag)
@@ -227,6 +228,7 @@  namespace __gnu_debug
   // Can verify if a forward iterator sequence is in fact sorted using
   // std::__is_sorted
   template<typename _ForwardIterator>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_sorted_aux(_ForwardIterator __first, _ForwardIterator __last,
                        std::forward_iterator_tag)
@@ -245,6 +247,7 @@  namespace __gnu_debug
   // Can't check if an input iterator sequence is sorted, because we can't step
   // through the sequence.
   template<typename _InputIterator, typename _Predicate>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_sorted_aux(const _InputIterator&, const _InputIterator&,
                        _Predicate, std::input_iterator_tag)
@@ -253,6 +256,7 @@  namespace __gnu_debug
   // Can verify if a forward iterator sequence is in fact sorted using
   // std::__is_sorted
   template<typename _ForwardIterator, typename _Predicate>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_sorted_aux(_ForwardIterator __first, _ForwardIterator __last,
                        _Predicate __pred, std::forward_iterator_tag)
@@ -270,31 +274,26 @@  namespace __gnu_debug
 
   // Determine if a sequence is sorted.
   template<typename _InputIterator>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_sorted(const _InputIterator& __first, const _InputIterator& __last)
     {
-      // Verify that the < operator for elements in the sequence is a
-      // StrictWeakOrdering by checking that it is irreflexive.
-      __glibcxx_assert(__first == __last || !(*__first < *__first));
-
       return __check_sorted_aux(__first, __last,
 				std::__iterator_category(__first));
     }
 
   template<typename _InputIterator, typename _Predicate>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_sorted(const _InputIterator& __first, const _InputIterator& __last,
                    _Predicate __pred)
     {
-      // Verify that the predicate is StrictWeakOrdering by checking that it
-      // is irreflexive.
-      __glibcxx_assert(__first == __last || !__pred(*__first, *__first));
-
       return __check_sorted_aux(__first, __last, __pred,
 				std::__iterator_category(__first));
     }
 
   template<typename _InputIterator>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_sorted_set_aux(const _InputIterator& __first,
 			   const _InputIterator& __last,
@@ -302,6 +301,7 @@  namespace __gnu_debug
     { return __check_sorted(__first, __last); }
 
   template<typename _InputIterator>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_sorted_set_aux(const _InputIterator&,
 			   const _InputIterator&,
@@ -309,6 +309,7 @@  namespace __gnu_debug
     { return true; }
 
   template<typename _InputIterator, typename _Predicate>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_sorted_set_aux(const _InputIterator& __first,
 			   const _InputIterator& __last,
@@ -316,6 +317,7 @@  namespace __gnu_debug
     { return __check_sorted(__first, __last, __pred); }
 
   template<typename _InputIterator, typename _Predicate>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_sorted_set_aux(const _InputIterator&,
 			   const _InputIterator&, _Predicate,
@@ -324,6 +326,7 @@  namespace __gnu_debug
 
   // ... special variant used in std::merge, std::includes, std::set_*.
   template<typename _InputIterator1, typename _InputIterator2>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_sorted_set(const _InputIterator1& __first,
 		       const _InputIterator1& __last,
@@ -341,6 +344,7 @@  namespace __gnu_debug
 
   template<typename _InputIterator1, typename _InputIterator2,
 	   typename _Predicate>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_sorted_set(const _InputIterator1& __first,
 		       const _InputIterator1& __last,
@@ -360,6 +364,7 @@  namespace __gnu_debug
   // 270. Binary search requirements overly strict
   // Determine if a sequence is partitioned w.r.t. this element.
   template<typename _ForwardIterator, typename _Tp>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_partitioned_lower(_ForwardIterator __first,
 			      _ForwardIterator __last, const _Tp& __value)
@@ -376,6 +381,7 @@  namespace __gnu_debug
     }
 
   template<typename _ForwardIterator, typename _Tp>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_partitioned_upper(_ForwardIterator __first,
 			      _ForwardIterator __last, const _Tp& __value)
@@ -393,6 +399,7 @@  namespace __gnu_debug
 
   // Determine if a sequence is partitioned w.r.t. this element.
   template<typename _ForwardIterator, typename _Tp, typename _Pred>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_partitioned_lower(_ForwardIterator __first,
 			      _ForwardIterator __last, const _Tp& __value,
@@ -410,6 +417,7 @@  namespace __gnu_debug
     }
 
   template<typename _ForwardIterator, typename _Tp, typename _Pred>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __check_partitioned_upper(_ForwardIterator __first,
 			      _ForwardIterator __last, const _Tp& __value,
@@ -435,35 +443,41 @@  namespace __gnu_debug
 
     template<typename _It,
 	     typename = decltype(__deref<_It>() < __deref<_It>())>
+      _GLIBCXX20_CONSTEXPR
       static bool
       _S_is_valid(_It __it)
       { return !(*__it < *__it); }
 
     // Fallback method if operator doesn't exist.
     template<typename... _Args>
+      _GLIBCXX20_CONSTEXPR
       static bool
       _S_is_valid(_Args...)
       { return true; }
 
     template<typename _It, typename _Pred, typename
 	= decltype(std::declval<_Pred>()(__deref<_It>(), __deref<_It>()))>
+      _GLIBCXX20_CONSTEXPR
       static bool
       _S_is_valid_pred(_It __it, _Pred __pred)
       { return !__pred(*__it, *__it); }
 
     // Fallback method if predicate can't be invoked.
     template<typename... _Args>
+      _GLIBCXX20_CONSTEXPR
       static bool
       _S_is_valid_pred(_Args...)
       { return true; }
   };
 
   template<typename _Iterator>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __is_irreflexive(_Iterator __it)
     { return _Irreflexive_checker::_S_is_valid(__it); }
 
   template<typename _Iterator, typename _Pred>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __is_irreflexive_pred(_Iterator __it, _Pred __pred)
     { return _Irreflexive_checker::_S_is_valid_pred(__it, __pred); }
diff --git a/libstdc++-v3/include/debug/helper_functions.h b/libstdc++-v3/include/debug/helper_functions.h
index 9429bb90a55..5a920bb9a6f 100644
--- a/libstdc++-v3/include/debug/helper_functions.h
+++ b/libstdc++-v3/include/debug/helper_functions.h
@@ -88,12 +88,14 @@  namespace __gnu_debug
    *	precision.
   */
   template<typename _Iterator>
+    _GLIBCXX_CONSTEXPR
     inline typename _Distance_traits<_Iterator>::__type
     __get_distance(_Iterator __lhs, _Iterator __rhs,
 		   std::random_access_iterator_tag)
     { return std::make_pair(__rhs - __lhs, __dp_exact); }
 
   template<typename _Iterator>
+    _GLIBCXX_CONSTEXPR
     inline typename _Distance_traits<_Iterator>::__type
     __get_distance(_Iterator __lhs, _Iterator __rhs,
 		   std::input_iterator_tag)
@@ -105,6 +107,7 @@  namespace __gnu_debug
     }
 
   template<typename _Iterator>
+    _GLIBCXX_CONSTEXPR
     inline typename _Distance_traits<_Iterator>::__type
     __get_distance(_Iterator __lhs, _Iterator __rhs)
     { return __get_distance(__lhs, __rhs, std::__iterator_category(__lhs)); }
@@ -114,6 +117,13 @@  namespace __gnu_debug
    *  iterators.
   */
   template<typename _Integral>
+    _GLIBCXX_CONSTEXPR
+    inline bool
+    __valid_range_aux(_Integral, _Integral, std::__true_type)
+    { return true; }
+
+  template<typename _Integral>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __valid_range_aux(_Integral, _Integral,
 		      typename _Distance_traits<_Integral>::__type& __dist,
@@ -123,10 +133,35 @@  namespace __gnu_debug
       return true;
     }
 
+  template<typename _InputIterator>
+    _GLIBCXX_CONSTEXPR
+    inline bool
+    __valid_range_aux(_InputIterator __first, _InputIterator __last,
+		      std::input_iterator_tag)
+    { return true; }
+
+  template<typename _InputIterator>
+    _GLIBCXX_CONSTEXPR
+    inline bool
+    __valid_range_aux(_InputIterator __first, _InputIterator __last,
+		      std::random_access_iterator_tag)
+    { return __first <= __last; }
+
   /** We have iterators, so figure out what kind of iterators they are
    *  to see if we can check the range ahead of time.
   */
   template<typename _InputIterator>
+    _GLIBCXX_CONSTEXPR
+    inline bool
+    __valid_range_aux(_InputIterator __first, _InputIterator __last,
+		      std::__false_type)
+    {
+      return __valid_range_aux(__first, __last,
+			       std::__iterator_category(__first));
+    }
+
+  template<typename _InputIterator>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __valid_range_aux(_InputIterator __first, _InputIterator __last,
 		      typename _Distance_traits<_InputIterator>::__type& __dist,
@@ -157,10 +192,16 @@  namespace __gnu_debug
    *  otherwise.
   */
   template<typename _InputIterator>
+    _GLIBCXX20_CONSTEXPR
     inline bool
     __valid_range(_InputIterator __first, _InputIterator __last,
 		  typename _Distance_traits<_InputIterator>::__type& __dist)
     {
+#ifdef __cpp_lib_is_constant_evaluated
+      if (std::is_constant_evaluated())
+	// Detected by the compiler directly.
+	return true;
+#endif
       typedef typename std::__is_integer<_InputIterator>::__type _Integral;
       return __valid_range_aux(__first, __last, __dist, _Integral());
     }
@@ -180,11 +221,17 @@  namespace __gnu_debug
 #endif
 
   template<typename _InputIterator>
+    _GLIBCXX_CONSTEXPR
     inline bool
     __valid_range(_InputIterator __first, _InputIterator __last)
     {
-      typename _Distance_traits<_InputIterator>::__type __dist;
-      return __valid_range(__first, __last, __dist);
+#ifdef _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED
+      if (__builtin_is_constant_evaluated())
+	// Detected by the compiler directly.
+	return true;
+#endif
+      typedef typename std::__is_integer<_InputIterator>::__type _Integral;
+      return __valid_range_aux(__first, __last, _Integral());
     }
 
   template<typename _Iterator, typename _Sequence, typename _Category>
@@ -201,6 +248,7 @@  namespace __gnu_debug
 
   // Fallback method, always ok.
   template<typename _InputIterator, typename _Size>
+    _GLIBCXX_CONSTEXPR
     inline bool
     __can_advance(_InputIterator, _Size)
     { return true; }
@@ -218,6 +266,7 @@  namespace __gnu_debug
    *  thanks to the < operator.
    */
   template<typename _Iterator>
+    _GLIBCXX_CONSTEXPR
     inline _Iterator
     __base(_Iterator __it)
     { return __it; }
diff --git a/libstdc++-v3/include/debug/macros.h b/libstdc++-v3/include/debug/macros.h
index b598192cb3e..97e54fd8390 100644
--- a/libstdc++-v3/include/debug/macros.h
+++ b/libstdc++-v3/include/debug/macros.h
@@ -38,10 +38,20 @@ 
  * the user error and where the error is reported.
  *
  */
-#define _GLIBCXX_DEBUG_VERIFY_COND_AT(_Cond,_ErrMsg,_File,_Line,_Func)	\
+#if 0 /* defined _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED */
+# define _GLIBCXX_DEBUG_VERIFY_COND_AT(_Cond,_ErrMsg,_File,_Line,_Func)	\
+  if (__builtin_is_constant_evaluated())				\
+    /* FIXME: Compilation error here when !_Cond. */			\
+    break;								\
   if (! (_Cond))							\
     __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func)		\
       ._ErrMsg._M_error()
+#else
+# define _GLIBCXX_DEBUG_VERIFY_COND_AT(_Cond,_ErrMsg,_File,_Line,_Func)	\
+  if (! (_Cond))							\
+    __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func)		\
+      ._ErrMsg._M_error()
+#endif
 
 #define _GLIBCXX_DEBUG_VERIFY_AT_F(_Cond,_ErrMsg,_File,_Line,_Func)	\
   do									\
@@ -291,9 +301,43 @@  _GLIBCXX_DEBUG_VERIFY(! this->empty(),					\
 		      _M_message(__gnu_debug::__msg_empty)	        \
                       ._M_sequence(*this, "this"))
 
+// Verify that a predicate is irreflexive
+#define __glibcxx_check_irreflexive(_First,_Last)			\
+  _GLIBCXX_DEBUG_VERIFY(_First == _Last || !(*_First < *_First),	\
+			_M_message(__gnu_debug::__msg_irreflexive_ordering) \
+			._M_iterator_value_type(_First, "< operator type"))
+
+#if __cplusplus >= 201103L
+# define __glibcxx_check_irreflexive2(_First,_Last)			\
+  _GLIBCXX_DEBUG_VERIFY(_First == _Last					\
+			|| __gnu_debug::__is_irreflexive(_First),	\
+			_M_message(__gnu_debug::__msg_irreflexive_ordering) \
+			._M_iterator_value_type(_First, "< operator type"))
+#else
+# define __glibcxx_check_irreflexive2(_First,_Last)
+#endif
+
+#define __glibcxx_check_irreflexive_pred(_First,_Last,_Pred)		\
+  _GLIBCXX_DEBUG_VERIFY(_First == _Last || !_Pred(*_First, *_First),	\
+			_M_message(__gnu_debug::__msg_irreflexive_ordering) \
+			._M_instance(_Pred, "functor")			\
+			._M_iterator_value_type(_First, "ordered type"))
+
+#if __cplusplus >= 201103L
+# define __glibcxx_check_irreflexive_pred2(_First,_Last,_Pred)		\
+  _GLIBCXX_DEBUG_VERIFY(_First == _Last					\
+			||__gnu_debug::__is_irreflexive_pred(_First, _Pred), \
+			_M_message(__gnu_debug::__msg_irreflexive_ordering) \
+			._M_instance(_Pred, "functor")			\
+			._M_iterator_value_type(_First, "ordered type"))
+#else
+# define __glibcxx_check_irreflexive_pred2(_First,_Last,_Pred)
+#endif
+
 // Verify that the iterator range [_First, _Last) is sorted
 #define __glibcxx_check_sorted(_First,_Last)				\
 __glibcxx_check_valid_range(_First,_Last);				\
+__glibcxx_check_irreflexive(_First,_Last);				\
  _GLIBCXX_DEBUG_VERIFY(__gnu_debug::__check_sorted(			\
 			__gnu_debug::__base(_First),			\
 			__gnu_debug::__base(_Last)),			\
@@ -305,6 +349,7 @@  __glibcxx_check_valid_range(_First,_Last);				\
     predicate _Pred. */
 #define __glibcxx_check_sorted_pred(_First,_Last,_Pred)			\
 __glibcxx_check_valid_range(_First,_Last);				\
+__glibcxx_check_irreflexive_pred(_First,_Last,_Pred);			\
 _GLIBCXX_DEBUG_VERIFY(__gnu_debug::__check_sorted(			\
 			__gnu_debug::__base(_First),			\
 			__gnu_debug::__base(_Last), _Pred),		\
@@ -423,37 +468,4 @@  _GLIBCXX_DEBUG_VERIFY(_This.get_allocator() == _Other.get_allocator(),	\
 #define __glibcxx_check_string_len(_String,_Len) \
   _GLIBCXX_DEBUG_PEDASSERT(_String != 0 || _Len == 0)
 
-// Verify that a predicate is irreflexive
-#define __glibcxx_check_irreflexive(_First,_Last)			\
-  _GLIBCXX_DEBUG_VERIFY(_First == _Last || !(*_First < *_First),	\
-			_M_message(__gnu_debug::__msg_irreflexive_ordering) \
-			._M_iterator_value_type(_First, "< operator type"))
-
-#if __cplusplus >= 201103L
-# define __glibcxx_check_irreflexive2(_First,_Last)			\
-  _GLIBCXX_DEBUG_VERIFY(_First == _Last					\
-			|| __gnu_debug::__is_irreflexive(_First),	\
-			_M_message(__gnu_debug::__msg_irreflexive_ordering) \
-			._M_iterator_value_type(_First, "< operator type"))
-#else
-# define __glibcxx_check_irreflexive2(_First,_Last)
-#endif
-
-#define __glibcxx_check_irreflexive_pred(_First,_Last,_Pred)		\
-  _GLIBCXX_DEBUG_VERIFY(_First == _Last	|| !_Pred(*_First, *_First),		\
-			_M_message(__gnu_debug::__msg_irreflexive_ordering) \
-			._M_instance(_Pred, "functor")			\
-			._M_iterator_value_type(_First, "ordered type"))
-
-#if __cplusplus >= 201103L
-# define __glibcxx_check_irreflexive_pred2(_First,_Last,_Pred)		\
-  _GLIBCXX_DEBUG_VERIFY(_First == _Last					\
-			||__gnu_debug::__is_irreflexive_pred(_First, _Pred), \
-			_M_message(__gnu_debug::__msg_irreflexive_ordering) \
-			._M_instance(_Pred, "functor")			\
-			._M_iterator_value_type(_First, "ordered type"))
-#else
-# define __glibcxx_check_irreflexive_pred2(_First,_Last,_Pred)
-#endif
-
 #endif
diff --git a/libstdc++-v3/testsuite/25_algorithms/binary_search/constexpr.cc b/libstdc++-v3/testsuite/25_algorithms/binary_search/constexpr.cc
index 8406b3d147f..205a96a223b 100644
--- a/libstdc++-v3/testsuite/25_algorithms/binary_search/constexpr.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/binary_search/constexpr.cc
@@ -29,7 +29,7 @@  test()
   const auto out4 = std::binary_search(ca0.begin(), ca0.end(), 5);
 
   const auto out5 = std::binary_search(ca0.begin(), ca0.end(), 5,
-				       std::equal_to<int>());
+				       std::less<int>());
 
   return true;
 }
diff --git a/libstdc++-v3/testsuite/25_algorithms/is_sorted/constexpr.cc b/libstdc++-v3/testsuite/25_algorithms/is_sorted/constexpr.cc
index 0be2f5fed62..f549b3d9307 100644
--- a/libstdc++-v3/testsuite/25_algorithms/is_sorted/constexpr.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/is_sorted/constexpr.cc
@@ -26,7 +26,7 @@  constexpr std::array<int, 12> ca0{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}};
 constexpr auto outv = std::is_sorted(ca0.begin(), ca0.end());
 
 constexpr auto outw = std::is_sorted(ca0.begin(), ca0.end(),
-				     std::equal_to<int>());
+				     std::less<int>());
 
 constexpr bool
 test()
diff --git a/libstdc++-v3/testsuite/25_algorithms/merge/constexpr.cc b/libstdc++-v3/testsuite/25_algorithms/merge/constexpr.cc
index cc8d3755da4..794453dd50c 100644
--- a/libstdc++-v3/testsuite/25_algorithms/merge/constexpr.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/merge/constexpr.cc
@@ -26,7 +26,7 @@  test()
 {
   constexpr std::array<int, 12> ca0{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}};
   constexpr std::array<int, 12> cas{{3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}};
-  constexpr std::array<int, 3> camm{{-4, -5, -6}};
+  constexpr std::array<int, 3> camm{{-6, -5, -4}};
   std::array<int, 24> out0{{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
 
   const auto outdd = std::merge(ca0.begin(), ca0.end(),
@@ -34,7 +34,7 @@  test()
 
   const auto outee = std::merge(ca0.begin(), ca0.end(),
 				camm.begin(), camm.end(), out0.begin(),
-				[](int i, int j){ return i < -j; });
+				[](int i, int j){ return i < j; });
 
   return true;
 }