From bb04d66687fd37bfc3cc6945cdeabf946ba9dfe7 Mon Sep 17 00:00:00 2001 From: Sedat Dilek Date: Wed, 30 Mar 2022 18:03:22 +0200 Subject: [PATCH] Add libc++ patches from upstream (post version 14.0.0) Details see Debian bug #1008657 ("clang-14: Integrate post v14.0.0 upstream patches") Link: https://bugs.debian.org/1008657 Signed-off-by: Sedat Dilek --- ...und-to-avoid-breaking-users-of-span-.patch | 390 ++++++++++++++++++ ...orkaround-for-pre-ranges-CTAD-in-std.patch | 78 ++++ debian/patches/series | 4 + 3 files changed, 472 insertions(+) create mode 100644 debian/patches/0001-libc-Add-workaround-to-avoid-breaking-users-of-span-.patch create mode 100644 debian/patches/0002-libc-Re-enable-workaround-for-pre-ranges-CTAD-in-std.patch diff --git a/debian/patches/0001-libc-Add-workaround-to-avoid-breaking-users-of-span-.patch b/debian/patches/0001-libc-Add-workaround-to-avoid-breaking-users-of-span-.patch new file mode 100644 index 00000000..e59a5605 --- /dev/null +++ b/debian/patches/0001-libc-Add-workaround-to-avoid-breaking-users-of-span-.patch @@ -0,0 +1,390 @@ +From add3ab7f4c8a7f25c2940889d397cbdc9f267666 Mon Sep 17 00:00:00 2001 +From: Louis Dionne +Date: Mon, 14 Mar 2022 11:50:02 -0400 +Subject: [PATCH] [libc++] Add workaround to avoid breaking users of + when are disabled + +Back in 3a208c68942e, we implemented the range-based constructor for . +However, in doing so, we removed a previous non-standard constructor that +we provided before shipping . Unfortunately, that breaks code that +was relying on a range-based constructor until we ship all of . + +This patch reintroduces the old non-conforming constructors and tests +that were removed in 3a208c68942e and uses them whenever is +not provided (e.g. in LLVM 14). This is only a temporary workaround +until we enable by default in C++20, which should hopefully +happen by LLVM 15. + +The goal is to cherry-pick this workaround back to the LLVM 14 release +branch, since I suspect the constructor removal may otherwise cause +breakage out there, like the breakage I saw internally. + +We could have avoided this situation by waiting for C++20 to be finalized +before shipping std::span. For example, we could have guarded it with +something like _LIBCPP_HAS_NO_INCOMPLETE_RANGES to prevent users from +accidentally starting to depend on it before it is stable. We did not +have these mechanisms when std::span was first implemented, though. + +NOTE: This is a pretty modified version of d4c39f1ab94 since that one +didn't apply properly onto the release/14.x branch. + +(cherry picked from commit d4c39f1ab94abc1dd4fff1e82dd4fa97265940e1) + +Differential Revision: https://reviews.llvm.org/D121739 +--- + libcxx/include/span | 50 ++++++- + .../containers/views/span.cons/range.pass.cpp | 141 ++++++++++++++++++ + .../views/span.cons/range.verify.cpp | 118 +++++++++++++++ + 3 files changed, 306 insertions(+), 3 deletions(-) + create mode 100644 libcxx/test/libcxx/containers/views/span.cons/range.pass.cpp + create mode 100644 libcxx/test/libcxx/containers/views/span.cons/range.verify.cpp + +diff --git a/libcxx/include/span b/libcxx/include/span +index fd95ecca17f7..b8dbc7e01fd6 100644 +--- a/libcxx/include/span ++++ b/libcxx/include/span +@@ -170,7 +170,25 @@ struct __is_std_span : false_type {}; + template + struct __is_std_span> : true_type {}; + +-#if !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) ++#if defined(_LIBCPP_HAS_NO_CONCEPTS) || defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) ++// This is a temporary workaround until we ship -- we've unfortunately been ++// shipping before its API was finalized, and we used to provide a constructor ++// from container types that had the requirements below. To avoid breaking code that ++// has started relying on the range-based constructor until we ship all of , ++// we emulate the constructor requirements like this. ++template ++struct __span_compatible_range : false_type { }; ++ ++template ++struct __span_compatible_range<_Range, _ElementType, void_t< ++ enable_if_t>::value>, ++ enable_if_t>::value>, ++ enable_if_t>>, ++ decltype(data(declval<_Range>())), ++ decltype(size(declval<_Range>())), ++ enable_if_t()))>(*)[], _ElementType(*)[]>> ++>> : true_type { }; ++#else + template + concept __span_compatible_range = + ranges::contiguous_range<_Range> && +@@ -248,7 +266,22 @@ public: + _LIBCPP_INLINE_VISIBILITY + constexpr span(const array<_OtherElementType, _Extent>& __arr) noexcept : __data{__arr.data()} {} + +-#if !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) ++#if defined(_LIBCPP_HAS_NO_CONCEPTS) || defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) ++ template ::value ++ >> ++ _LIBCPP_INLINE_VISIBILITY ++ constexpr explicit span(_Container& __c) : __data{std::data(__c)} { ++ _LIBCPP_ASSERT(std::size(__c) == _Extent, "size mismatch in span's constructor (range)"); ++ } ++ template ::value ++ >> ++ _LIBCPP_INLINE_VISIBILITY ++ constexpr explicit span(const _Container& __c) : __data{std::data(__c)} { ++ _LIBCPP_ASSERT(std::size(__c) == _Extent, "size mismatch in span's constructor (range)"); ++ } ++#else + template <__span_compatible_range _Range> + _LIBCPP_INLINE_VISIBILITY + constexpr explicit span(_Range&& __r) : __data{ranges::data(__r)} { +@@ -434,7 +467,18 @@ public: + _LIBCPP_INLINE_VISIBILITY + constexpr span(const array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {} + +-#if !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) ++#if defined(_LIBCPP_HAS_NO_CONCEPTS) || defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) ++ template ::value ++ >> ++ _LIBCPP_INLINE_VISIBILITY ++ constexpr span(_Container& __c) : __data(std::data(__c)), __size{std::size(__c)} {} ++ template ::value ++ >> ++ _LIBCPP_INLINE_VISIBILITY ++ constexpr span(const _Container& __c) : __data(std::data(__c)), __size{std::size(__c)} {} ++#else + template <__span_compatible_range _Range> + _LIBCPP_INLINE_VISIBILITY + constexpr span(_Range&& __r) : __data(ranges::data(__r)), __size{ranges::size(__r)} {} +diff --git a/libcxx/test/libcxx/containers/views/span.cons/range.pass.cpp b/libcxx/test/libcxx/containers/views/span.cons/range.pass.cpp +new file mode 100644 +index 000000000000..efa1001bdb5b +--- /dev/null ++++ b/libcxx/test/libcxx/containers/views/span.cons/range.pass.cpp +@@ -0,0 +1,141 @@ ++//===---------------------------------------------------------------------===// ++// ++// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. ++// See https://llvm.org/LICENSE.txt for license information. ++// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ++// ++//===---------------------------------------------------------------------===// ++// UNSUPPORTED: c++03, c++11, c++14, c++17 ++ ++// ++ ++// template ++// constexpr explicit(Extent != dynamic_extent) span(Container&); ++// template ++// constexpr explicit(Extent != dynamic_extent) span(Container const&); ++ ++// This test checks for libc++'s non-conforming temporary extension to std::span ++// to support construction from containers that look like contiguous ranges. ++// ++// This extension is only supported when we don't ship , and we can ++// remove it once we get rid of _LIBCPP_HAS_NO_INCOMPLETE_RANGES. ++ ++#include ++#include ++#include ++#include ++ ++#include "test_macros.h" ++ ++// Look ma - I'm a container! ++template ++struct IsAContainer { ++ constexpr IsAContainer() : v_{} {} ++ constexpr size_t size() const {return 1;} ++ constexpr T *data() {return &v_;} ++ constexpr const T *data() const {return &v_;} ++ constexpr T *begin() {return &v_;} ++ constexpr const T *begin() const {return &v_;} ++ constexpr T *end() {return &v_ + 1;} ++ constexpr const T *end() const {return &v_ + 1;} ++ ++ constexpr T const *getV() const {return &v_;} // for checking ++ T v_; ++}; ++ ++ ++void checkCV() ++{ ++ std::vector v = {1,2,3}; ++ ++// Types the same ++ { ++ std::span< int> s1{v}; // a span< int> pointing at int. ++ } ++ ++// types different ++ { ++ std::span s1{v}; // a span pointing at int. ++ std::span< volatile int> s2{v}; // a span< volatile int> pointing at int. ++ std::span< volatile int> s3{v}; // a span< volatile int> pointing at const int. ++ std::span s4{v}; // a span pointing at int. ++ } ++ ++// Constructing a const view from a temporary ++ { ++ std::span s1{IsAContainer()}; ++ std::span s3{std::vector()}; ++ (void) s1; ++ (void) s3; ++ } ++} ++ ++ ++template ++constexpr bool testConstexprSpan() ++{ ++ constexpr IsAContainer val{}; ++ std::span s1{val}; ++ return s1.data() == val.getV() && s1.size() == 1; ++} ++ ++template ++constexpr bool testConstexprSpanStatic() ++{ ++ constexpr IsAContainer val{}; ++ std::span s1{val}; ++ return s1.data() == val.getV() && s1.size() == 1; ++} ++ ++template ++void testRuntimeSpan() ++{ ++ IsAContainer val{}; ++ const IsAContainer cVal; ++ std::span s1{val}; ++ std::span s2{cVal}; ++ assert(s1.data() == val.getV() && s1.size() == 1); ++ assert(s2.data() == cVal.getV() && s2.size() == 1); ++} ++ ++template ++void testRuntimeSpanStatic() ++{ ++ IsAContainer val{}; ++ const IsAContainer cVal; ++ std::span s1{val}; ++ std::span s2{cVal}; ++ assert(s1.data() == val.getV() && s1.size() == 1); ++ assert(s2.data() == cVal.getV() && s2.size() == 1); ++} ++ ++struct A{}; ++ ++int main(int, char**) ++{ ++ static_assert(testConstexprSpan(), ""); ++ static_assert(testConstexprSpan(), ""); ++ static_assert(testConstexprSpan(), ""); ++ static_assert(testConstexprSpan(), ""); ++ ++ static_assert(testConstexprSpanStatic(), ""); ++ static_assert(testConstexprSpanStatic(), ""); ++ static_assert(testConstexprSpanStatic(), ""); ++ static_assert(testConstexprSpanStatic(), ""); ++ ++ testRuntimeSpan(); ++ testRuntimeSpan(); ++ testRuntimeSpan(); ++ testRuntimeSpan(); ++ testRuntimeSpan(); ++ ++ testRuntimeSpanStatic(); ++ testRuntimeSpanStatic(); ++ testRuntimeSpanStatic(); ++ testRuntimeSpanStatic(); ++ testRuntimeSpanStatic(); ++ ++ checkCV(); ++ ++ return 0; ++} +diff --git a/libcxx/test/libcxx/containers/views/span.cons/range.verify.cpp b/libcxx/test/libcxx/containers/views/span.cons/range.verify.cpp +new file mode 100644 +index 000000000000..f0edf4f93536 +--- /dev/null ++++ b/libcxx/test/libcxx/containers/views/span.cons/range.verify.cpp +@@ -0,0 +1,118 @@ ++//===---------------------------------------------------------------------===// ++// ++// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. ++// See https://llvm.org/LICENSE.txt for license information. ++// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ++// ++//===---------------------------------------------------------------------===// ++// UNSUPPORTED: c++03, c++11, c++14, c++17 ++ ++// ++ ++// template ++// constexpr explicit(Extent != dynamic_extent) span(Container&); ++// template ++// constexpr explicit(Extent != dynamic_extent) span(Container const&); ++ ++// This test checks for libc++'s non-conforming temporary extension to std::span ++// to support construction from containers that look like contiguous ranges. ++// ++// This extension is only supported when we don't ship , and we can ++// remove it once we get rid of _LIBCPP_HAS_NO_INCOMPLETE_RANGES. ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "test_macros.h" ++ ++// Look ma - I'm a container! ++template ++struct IsAContainer { ++ constexpr IsAContainer() : v_{} {} ++ constexpr size_t size() const {return 1;} ++ constexpr T *data() {return &v_;} ++ constexpr const T *data() const {return &v_;} ++ ++ constexpr const T *getV() const {return &v_;} // for checking ++ T v_; ++}; ++ ++template ++struct NotAContainerNoData { ++ size_t size() const {return 0;} ++}; ++ ++template ++struct NotAContainerNoSize { ++ const T *data() const {return nullptr;} ++}; ++ ++template ++struct NotAContainerPrivate { ++private: ++ size_t size() const {return 0;} ++ const T *data() const {return nullptr;} ++}; ++ ++template ++std::span createImplicitSpan(container c) { ++ return {c}; // expected-error {{chosen constructor is explicit in copy-initialization}} ++} ++ ++int main(int, char**) ++{ ++ ++// Making non-const spans from const sources (a temporary binds to `const &`) ++ { ++ std::span s1{IsAContainer()}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ std::span s3{std::vector()}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ } ++ ++// Missing size and/or data ++ { ++ std::span s1{NotAContainerNoData()}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ std::span s3{NotAContainerNoSize()}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ std::span s5{NotAContainerPrivate()}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ ++// Again with the standard containers ++ std::span s11{std::deque()}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ std::span s13{std::list()}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ std::span s15{std::forward_list()}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ } ++ ++// Not the same type ++ { ++ IsAContainer c; ++ std::span s1{c}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ } ++ ++// CV wrong ++ { ++ IsAContainer c; ++ IsAContainer cv; ++ IsAContainer< volatile int> v; ++ ++ std::span< int> s1{c}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ std::span< int> s2{v}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ std::span< int> s3{cv}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ std::span s4{v}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ std::span s5{cv}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ std::span< volatile int> s6{c}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ std::span< volatile int> s7{cv}; // expected-error {{no matching constructor for initialization of 'std::span'}} ++ } ++ ++// explicit constructor necessary ++ { ++ IsAContainer c; ++ const IsAContainer cc; ++ ++ createImplicitSpan(c); ++ createImplicitSpan(cc); ++ } ++ ++ return 0; ++} +-- +2.35.1 + diff --git a/debian/patches/0002-libc-Re-enable-workaround-for-pre-ranges-CTAD-in-std.patch b/debian/patches/0002-libc-Re-enable-workaround-for-pre-ranges-CTAD-in-std.patch new file mode 100644 index 00000000..70666362 --- /dev/null +++ b/debian/patches/0002-libc-Re-enable-workaround-for-pre-ranges-CTAD-in-std.patch @@ -0,0 +1,78 @@ +From 3f43d803382d57e3fc010ca19833077d1023e9c9 Mon Sep 17 00:00:00 2001 +From: Louis Dionne +Date: Mon, 21 Mar 2022 17:05:06 -0400 +Subject: [PATCH] [libc++] Re-enable workaround for pre-ranges CTAD in + std::span + +See https://reviews.llvm.org/D121626 for details -- this re-enables the +CTAD we removed, since it does break some stuff as well (even though it's +not nearly as bad as the removed constructors fixed by D121626). + +(cherry picked from commit 6a7f0551178e966a686dd48dfa2ea045a35addef) + +Differential Revision: https://reviews.llvm.org/D122201 +--- + libcxx/include/span | 8 +++++++- + .../test/std/containers/views/span.cons/deduct.pass.cpp | 6 ------ + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/libcxx/include/span b/libcxx/include/span +index b8dbc7e01fd6..f33569031730 100644 +--- a/libcxx/include/span ++++ b/libcxx/include/span +@@ -622,7 +622,13 @@ template + template + span(const array<_Tp, _Sz>&) -> span; + +-#if !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) ++#if defined(_LIBCPP_HAS_NO_CONCEPTS) || defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) ++template ++ span(_Container&) -> span; ++ ++template ++ span(const _Container&) -> span; ++#else + template + span(_Range&&) -> span>>; + #endif +diff --git a/libcxx/test/std/containers/views/span.cons/deduct.pass.cpp b/libcxx/test/std/containers/views/span.cons/deduct.pass.cpp +index 81632fed711d..e632feca2e1f 100644 +--- a/libcxx/test/std/containers/views/span.cons/deduct.pass.cpp ++++ b/libcxx/test/std/containers/views/span.cons/deduct.pass.cpp +@@ -6,7 +6,6 @@ + // + //===----------------------------------------------------------------------===// + // UNSUPPORTED: c++03, c++11, c++14, c++17 +-// UNSUPPORTED: libcpp-no-concepts + + // + +@@ -86,7 +85,6 @@ void test_std_array() { + } + } + +-#ifndef _LIBCPP_HAS_NO_INCOMPLETE_RANGES + void test_range_std_container() { + { + std::string str{"ABCDE"}; +@@ -104,17 +102,13 @@ void test_range_std_container() { + assert(s.data() == str.data()); + } + } +-#endif // _LIBCPP_HAS_NO_INCOMPLETE_RANGES + + int main(int, char**) + { + test_iterator_sentinel(); + test_c_array(); + test_std_array(); +- +-#ifndef _LIBCPP_HAS_NO_INCOMPLETE_RANGES + test_range_std_container(); +-#endif // _LIBCPP_HAS_NO_INCOMPLETE_RANGES + + return 0; + } +-- +2.35.1 + diff --git a/debian/patches/series b/debian/patches/series index df956934..fc005ac4 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -150,3 +150,7 @@ wasm-ld-path.diff python3-scan-build.py revert-update-doc.diff fix-typo.diff + +# libc++ patches from upstream (post version 14.0.0) +0001-libc-Add-workaround-to-avoid-breaking-users-of-span-.patch +0002-libc-Re-enable-workaround-for-pre-ranges-CTAD-in-std.patch