Commit 0b3ec8f4 by Jonathan Wakely Committed by Jonathan Wakely

PR libstdc++/78420 Make std::less etc. yield total order for pointers

In order for std::less<T*> etc. to meet the total order requirements of
[comparisons] p2 we need to cast unrelated pointers to uintptr_t before
comparing them. Those casts aren't allowed in constant expressions, so
only cast when __builtin_constant_p says the result of the comparison is
not a compile-time constant (because the arguments are not constants, or
the result of the comparison is unspecified). When the result is
constant just compare the pointers directly without casting.

This ensures that the function can be called in constant expressions
with suitable arguments, but still yields a total order even for
otherwise unspecified pointer comparisons.

For std::less<void> etc. add new overloads for pointers, which use
std::less<common_type_t<T*,U*>> directly. Also change the generic
overloads to detect when the comparison would call a built-in relational
operator with pointer operands, and dispatch that case to the
corresponding specialization for void pointers.

	PR libstdc++/78420
	* include/bits/stl_function.h (greater<_Tp*>, less<_Tp*>)
	(greater_equal<_Tp*>, less_equal<_Tp>*): Add partial specializations
	to ensure total order for pointers.
	(greater<void>, less<void>, greater_equal<void>, less_equal<void>):
	Add operator() overloads for pointer arguments and make generic
	overloads dispatch to new _S_cmp functions when comparisons would
	use built-in operators for pointers.
	* testsuite/20_util/function_objects/comparisons_pointer.cc: New.

From-SVN: r258540
parent dcdfd478
2018-03-14 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/78420
* include/bits/stl_function.h (greater<_Tp*>, less<_Tp*>)
(greater_equal<_Tp*>, less_equal<_Tp>*): Add partial specializations
to ensure total order for pointers.
(greater<void>, less<void>, greater_equal<void>, less_equal<void>):
Add operator() overloads for pointer arguments and make generic
overloads dispatch to new _S_cmp functions when comparisons would
use built-in operators for pointers.
* testsuite/20_util/function_objects/comparisons_pointer.cc: New.
2018-03-12 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/84773
......
// Copyright (C) 2018 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-do run }
#include <functional>
#include <sstream>
#include <testsuite_hooks.h>
int b[8];
int a[8];
void
test01()
{
auto p = a + 8;
std::greater<int*> gt;
std::stringstream ss;
ss << gt(p, b) << ' ' << gt(b, p) << ' ' << (!gt(p, b) && !gt(b, p));
int sum = 0, n = 0;
while (ss >> n)
sum += n;
VERIFY( sum == 1 );
#if __cplusplus >= 201402L
static_assert( gt(a+1, a), "constexpr greater<int*>" );
static_assert( !gt(a, a+1), "constexpr greater<int*>" );
ss.str("");
ss.clear();
sum = 0;
auto p2 = a + 8;
std::greater<> gt2;
ss << gt2(p2, b) << ' ' << gt2(b, p2) << ' ' << (!gt2(p2, b) && !gt2(b, p2));
while (ss >> n)
sum += n;
VERIFY( sum == 1 );
static_assert( gt2(a+1, a), "constexpr greater<>" );
static_assert( !gt2(a, a+1), "constexpr greater<>" );
#endif
}
void
test02()
{
auto p = a + 8;
std::less<int*> lt;
std::stringstream ss;
ss << lt(p, b) << ' ' << lt(b, p) << ' ' << (!lt(p, b) && !lt(b, p));
int sum = 0, n = 0;
while (ss >> n)
sum += n;
VERIFY( sum == 1 );
#if __cplusplus >= 201402L
static_assert( lt(a, a+1), "constexpr less<int*>" );
static_assert( !lt(a+1, a), "constexpr less<int*>" );
ss.str("");
ss.clear();
sum = 0;
auto p2 = a + 8;
std::less<> lt2;
ss << lt2(p2, b) << ' ' << lt2(b, p2) << ' ' << (!lt2(p2, b) && !lt2(b, p2));
while (ss >> n)
sum += n;
VERIFY( sum == 1 );
static_assert( lt2(a, a+1), "constexpr less<>" );
static_assert( !lt2(a+1, a), "constexpr less<>" );
#endif
}
void
test03()
{
auto p = a + 8;
std::greater_equal<int*> ge;
std::stringstream ss;
ss << !ge(p, b) << ' ' << !ge(b, p) << ' ' << (ge(p, b) && ge(b, p));
int sum = 0, n = 0;
while (ss >> n)
sum += n;
VERIFY( sum == 1 );
#if __cplusplus >= 201402L
static_assert( !ge(a, a+1), "constexpr greater_equal<int*>" );
static_assert( ge(a, a), "constexpr greater_equal<int*>" );
static_assert( ge(a+1, a), "constexpr greater_equal<int*>" );
ss.str("");
ss.clear();
sum = 0;
auto p2 = a + 8;
std::greater_equal<> ge2;
ss << !ge2(p2, b) << ' ' << !ge2(b, p2) << ' ' << (ge2(p2, b) && ge2(b, p2));
while (ss >> n)
sum += n;
VERIFY( sum == 1 );
static_assert( !ge2(a, a+1), "constexpr greater_equal<>" );
static_assert( ge2(a, a), "constexpr greater_equal<>" );
static_assert( ge2(a+1, a), "constexpr greater_equal<>" );
#endif
}
void
test04()
{
auto p = a + 8;
std::less_equal<int*> le;
std::stringstream ss;
ss << !le(p, b) << ' ' << !le(b, p) << ' ' << (le(p, b) && le(b, p));
int sum = 0, n = 0;
while (ss >> n)
sum += n;
VERIFY( sum == 1 );
#if __cplusplus >= 201402L
static_assert( !le(a+1, a), "constexpr less_equal<int*>" );
static_assert( le(a, a), "constexpr less_equal<int*>" );
static_assert( le(a, a+1), "constexpr less_equal<int*>" );
ss.str("");
ss.clear();
sum = 0;
auto p2 = a + 8;
std::less_equal<> le2;
ss << !le2(p2, b) << ' ' << !le2(b, p2) << ' ' << (le2(p2, b) && le2(b, p2));
while (ss >> n)
sum += n;
VERIFY( sum == 1 );
static_assert( !le2(a+1, a), "constexpr less_equal<>" );
static_assert( le2(a, a), "constexpr less_equal<>" );
static_assert( le2(a, a+1), "constexpr less_equal<>" );
#endif
}
struct X {
operator const X*() const { return this; }
};
X x;
X y[4];
void
test05()
{
std::less<const X*> lt;
auto p = y + 4;
std::stringstream ss;
ss << lt(x, p) << ' ' << lt(p, x) << ' ' << (!lt(p, x) && !lt(x, p));
int sum = 0;
int n = 0;
while (ss >> n)
sum += n;
assert( sum == 1 );
#if __cplusplus >= 201402L
static_assert( lt(y, y+1), "constexpr less<const X*>" );
static_assert( !lt(y+1, y), "constexpr less<const X*>" );
ss.str("");
ss.clear();
sum = 0;
auto p2 = y + 4;
std::less<> lt2;
ss << lt2(x, p2) << ' ' << lt2(p2, x) << ' ' << (!lt2(x, p2) && !lt2(p2, x));
while (ss >> n)
sum += n;
VERIFY( sum == 1 );
static_assert( lt2(y, y+1), "constexpr less<>" );
static_assert( !lt2(y+1, y), "constexpr less<>" );
#endif
}
int
main()
{
test01();
test02();
test03();
test04();
test05();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment