diff --git a/include/oneapi/dpl/pstl/iterator_impl.h b/include/oneapi/dpl/pstl/iterator_impl.h index 6863e3c1380..929eec7c773 100644 --- a/include/oneapi/dpl/pstl/iterator_impl.h +++ b/include/oneapi/dpl/pstl/iterator_impl.h @@ -516,14 +516,14 @@ class transform_iterator { __my_it_ = __input.__my_it_; - // If copy assignment is available, copy the functor, otherwise skip it. - // For non-copy assignable functors, this copy assignment operator departs from the sycl 2020 specification - // requirement of device copyable types for copy assignment to be the same as a bitwise copy of the object. - // TODO: Explore (ABI breaking) change to use std::optional or similar and using copy constructor to implement - // copy assignment to better comply with SYCL 2020 specification. - if constexpr (std::is_copy_assignable_v<_UnaryFunc>) + // Implement functor copy assignment via destroy + copy-construct rather than _UnaryFunc::operator=. + // This supports copy assignment of functors which are not copy assignable (like c++17 lambdas). + // For a unary functor who's copy assignment operator differs from its copy constructor, the semantics of this + // copy assignment will follow that of its copy constructor. + if (this != std::addressof(__input)) { - __my_unary_func_ = __input.__my_unary_func_; + __my_unary_func_.~_UnaryFunc(); + ::new (std::addressof(__my_unary_func_)) _UnaryFunc(__input.__my_unary_func_); } return *this; } diff --git a/test/parallel_api/iterator/transform_iterator_constructible.pass.cpp b/test/parallel_api/iterator/transform_iterator_constructible.pass.cpp index 589b5b2fe20..215214a7f48 100644 --- a/test/parallel_api/iterator/transform_iterator_constructible.pass.cpp +++ b/test/parallel_api/iterator/transform_iterator_constructible.pass.cpp @@ -101,11 +101,11 @@ test_copy_assignment() EXPECT_EQ(9, trans6[5], "transform_iterator returns the incorrect result"); - //should NOT copy __x state of functor (but still allows assignment of iterator) + //should still copy __x state of functor (despite not being copy-assignable) trans6 = trans5; //trans6 functor.__x remains the same, but iterator has been updated to be 100 elements later in the counting iter - EXPECT_EQ(109, trans6[5], "transform_iterator assignment with non-copy-assignable functor copies functor"); + EXPECT_EQ(108, trans6[5], "transform_iterator assignment with non-copy-assignable functor still copies functor"); } void