[PATCH 1/3] C++20 constexpr lib part 1/3

Ed Smith-Rowland via gcc-patches gcc-patches@gcc.gnu.org
Thu Jun 27 16:54:00 GMT 2019


On 6/27/19 11:41 AM, Jonathan Wakely wrote:
> On 26/06/19 19:13 -0400, Ed Smith-Rowland via libstdc++ wrote:
>> Here is the first of three patches for C++20 constexpr library.
>>
>> ?????? Implement C++20 p0202 - Add constexpr Modifiers to Functions 
>> in <algorithm> and <utility> Headers.
>> ???? ??Implement C++20 p1023 - constexpr comparison operators for 
>> std::array.
>>
>> I believe I have answered peoples concerns with the last patch 
>> attempts [https://gcc.gnu.org/ml/libstdc++/2019-03/msg00132.html].
>>
>> The patch is large because of test cases but really just boils down 
>> to adding constexpr for c++2a.
>
> I still have some concerns about the changes like:
>
> ?????? template<typename _Iterator, typename _Value>
> +?????????? _GLIBCXX20_CONSTEXPR
> ?????????? bool
> -?????????? operator()(_Iterator __it, _Value& __val) const
> +?????????? operator()(_Iterator __it, const _Value& __val) const
> ?????????? { return *__it < __val; }
>
Make a type where operator< changes the rhs.?? I was thinking you'd want 
a compare to operate on const things but I guess we have to be ready for 
anything.?? I was also thinking < is left associative for a class member 
but i guess a class could have a thing that mutates the rhs too.?? 
Nothing got hit in any of my testing.?? If this is a thing we probably 
should make a general test for things like this somewhere.?? Maybe 
someone wants to log references or something.

1. I'll experiment to see if I really need these (I *thought* I did, but...)

2. If I still do then I'll make overloads?

>
> I think that might change semantics for some types, and I haven't yet
> figured out if we care about those cases or not. I'll try to come up
> with some examples that change meaning.
>
> This could use _GLIBCXX14_CONSTEXPR:
>
> +?? /**
> +???? * A constexpr wrapper for __builtin_memmove.
> +???? * @param __num The number of elements of type _Tp (not bytes).
>
> I don't think we want a Doxygen comment for this, as it's not part of
> the public API. Just a normal comment is fine.
>
> +???? */
> +?? template<bool _IsMove, typename _Tp>
> +?????? _GLIBCXX20_CONSTEXPR
> +?????? inline void*
> +?????? __memmove(_Tp* __dst, const _Tp* __src, size_t __num)
> +?????? {
> +#if __cplusplus > 201703L \
> +?????? && defined(_GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED)
> +?????????? if (__builtin_is_constant_evaluated())
> +?????? {
> +?????????? for(; __num > 0; --__num)
> +?????????????? {
> +?????????????????? if constexpr (_IsMove)
> +?????????????? *__dst = std::move(*__src);
> +?????????????????? else
> +?????????????? *__dst = *__src;
>
> Do we need this _IsMove condition here? We should only be using this
> function for trivially copyable types, in which case copy vs move
> shouldn't matter, should it?
>
> Oh ... is it because we also end up using this __memmove function for
> non-trivially copyable types, during constant evaluation? Hmm. Then
> it's more than just a wrapper for __builtin_memmove, right? It's
> "either memmove or constexpr range copy", or something.

Yup.?? I'm also bad at naming things.?? Furthermore, I expect the 
standards people to want to have our versions of memcpy, memcmp, memmove 
that we own and can make constexpr.?? These are such important concepts.

Also, part 2 brings in constexpr swap. Maybe this is the may to 
implement an actual memmove?

>
> I don't think this will work in a constant expression:
>
> ?? /// Assign @p __new_val to @p __obj and return its previous value.
> ?? template <typename _Tp, typename _Up = _Tp>
> +?????? _GLIBCXX20_CONSTEXPR
> ?????? inline _Tp
> ?????? exchange(_Tp& __obj, _Up&& __new_val)
> ?????? { return std::__exchange(__obj, std::forward<_Up>(__new_val)); }
>
> Because std::__exchange hasn't been marked constexpr. The test passes
> because it doesn't call it in a context that requires constant
> evaluation:
>
> ??const auto x = std::exchange(e, pi);
Derp.
>
> I see the same problem in other tests too:
>
> +?? constexpr std::array<int, 12> car{{0, 1, 2, 3, 4, 5, 6, 6, 8, 9, 9, 
> 11}};
> +
> +?? const auto out0x = std::adjacent_find(car.begin(), car.end());
> +
> +?? const auto out1x = std::adjacent_find(car.begin(), car.end(),
> +?????????????????????????????????????? std::equal_to<int>())

I will go through all the tests and make sure that some nontrivial 
calculation is done that contributes to a final bool return.?? And clean 
up the mess.?? I did this in chunk 2 but I guess I left a lot of chunk 1.

Come to think of it, we could build *insane* concepts after this.?? For 
good or ill.

Ed



More information about the Gcc-patches mailing list