[libcxx-commits] [PATCH] D154613: [libc++] Fix std::move algorithm with trivial move-only types

Louis Dionne via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jul 7 04:39:12 PDT 2023


ldionne added a comment.

In D154613#4479865 <https://reviews.llvm.org/D154613#4479865>, @alexfh wrote:

> It looks like this fix will take some time to converge. Can we first return to green, please? The premerge checks succeeded on https://reviews.llvm.org/D154595

See https://reviews.llvm.org/D154595#4480304



================
Comment at: libcxx/include/__string/constexpr_c_functions.h:186-189
+          is_copy_assignable<_Tp>::value    ? 0 :
+          is_move_assignable<_Tp>::value    ? 1 :
+          is_copy_constructible<_Tp>::value ? 2 :
+          is_move_constructible<_Tp>::value ? 3 : -1>());
----------------
philnik wrote:
> Would it make sense to first try construction? Then we could use `__constexpr_memmove` for `uninitialized_{copy, move}` too.
I actually ran into issues doing this (I think it triggers some issues in older standard modes), plus the semantics of this function (as currently written) are to perform an assignment, so I think trying the assignment first makes sense. I'm definitely willing to investigate, but I'd like to do that in its own patch. Are you OK with that?


================
Comment at: libcxx/include/__string/constexpr_c_functions.h:211
       for (; __count > 0; --__count)
-        __dest[__count - 1] = __src[__count - 1];
+        std::__assign_trivially_copyable(__dest + (__count - 1), __builtin_bit_cast(_Tp, __src[__count - 1]));
     } else {
----------------
philnik wrote:
> Why do you `bit_cast` here? Also, could we add a `__bit_cast` instead of using builtins randomly in the code?
I `bit_cast` in order to avoid having to deal with `_Tp` and `_Up` in the assignment -- I want to deal with a single type over there.

> Also, could we add a __bit_cast instead of using builtins randomly in the code?

Yes, I can do that.

Edit: I just tried introducing `__bit_cast` and using it, and it actually triggers some test failures in C++11 and C++14 mode:

```
In file included from libcxx/strings/c.strings/constexpr_memmove.pass.cpp:25:
In file included from include/c++/v1/__string/constexpr_c_functions.h:12:
include/c++/v1/__bit/bit_cast.h:36:10: error: call to deleted constructor of 'CopyConstructible'
  return __builtin_bit_cast(_ToType, __from);
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/c++/v1/__string/constexpr_c_functions.h:212:71: note: in instantiation of function template specialization 'std::__bit_cast<CopyConstructible, CopyConstructible>' requested here
        std::__assign_trivially_copyable(__dest + (__count - 1), std::__bit_cast<_Tp>(__src[__count - 1]));
                                                                      ^
libcxx/strings/c.strings/constexpr_memmove.pass.cpp:91:23: note: in instantiation of function template specialization 'std::__constexpr_memmove<CopyConstructible, CopyConstructible, 0>' requested here
  Dest* result = std::__constexpr_memmove(dst, src, std::__element_count(3));
                      ^
libcxx/strings/c.strings/constexpr_memmove.pass.cpp:111:3: note: in instantiation of function template specialization 'test_user_defined_types<CopyConstructible, CopyConstructible>' requested here
  test_user_defined_types<CopyConstructible, CopyConstructible>();
  ^
libcxx/strings/c.strings/constexpr_memmove.pass.cpp:40:3: note: 'CopyConstructible' has been explicitly marked deleted here
  CopyConstructible(CopyConstructible&&)                 = delete;
  ^
```

I think this is because RVO isn't mandated before C++17 (IIRC?), and so we actually require a move constructor to return from `__bit_cast` for some of the funky types I use in the test. So it looks like I might need to keep using `__builtin_bit_cast` directly here (even though I agree with you it would make more sense to use some `std::__bit_cast`).


================
Comment at: libcxx/test/std/containers/sequences/vector/vector.modifiers/erase_iter.pass.cpp:40
     {
-    int a1[] = {1, 2, 3, 4, 5};
-    std::vector<int> l1(a1, a1+5);
-    l1.erase(l1.begin());
-    assert(is_contiguous_container_asan_correct(l1));
-    assert(l1 == std::vector<int>(a1+1, a1+5));
+        int a1[] = {1, 2, 3, 4, 5};
+        std::vector<int> l1(a1, a1+5);
----------------
philnik wrote:
> Instead of moving all the code an indentation deeper, maybe move the braces an indentation higher? That would basically change this test to use two-space indentation instead of four spaces, like we do in new code. (or just clang-format the whole thing)
I'll clang-format it, you're right the diff is actually smaller.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154613/new/

https://reviews.llvm.org/D154613



More information about the libcxx-commits mailing list