| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| //===-- Definition of macros from fenv.h ----------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_HDR_FENV_MACROS_H | ||
| #define LLVM_LIBC_HDR_FENV_MACROS_H | ||
|
|
||
| #ifdef LIBC_FULL_BUILD | ||
|
|
||
| #include "include/llvm-libc-macros/fenv-macros.h" | ||
|
|
||
| #else // Overlay mode | ||
|
|
||
| #include <fenv.h> | ||
|
|
||
| #endif // LLVM_LIBC_FULL_BUILD | ||
|
|
||
| #endif // LLVM_LIBC_HDR_FENV_MACROS_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,350 @@ | ||
| // -*- C++ -*- | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| // WARNING, this entire header is generated by | ||
| // utils/generate_indic_conjunct_break_table.py | ||
| // DO NOT MODIFY! | ||
|
|
||
| // UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE | ||
| // | ||
| // See Terms of Use <https://www.unicode.org/copyright.html> | ||
| // for definitions of Unicode Inc.'s Data Files and Software. | ||
| // | ||
| // NOTICE TO USER: Carefully read the following legal agreement. | ||
| // BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S | ||
| // DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), | ||
| // YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE | ||
| // TERMS AND CONDITIONS OF THIS AGREEMENT. | ||
| // IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE | ||
| // THE DATA FILES OR SOFTWARE. | ||
| // | ||
| // COPYRIGHT AND PERMISSION NOTICE | ||
| // | ||
| // Copyright (c) 1991-2022 Unicode, Inc. All rights reserved. | ||
| // Distributed under the Terms of Use in https://www.unicode.org/copyright.html. | ||
| // | ||
| // Permission is hereby granted, free of charge, to any person obtaining | ||
| // a copy of the Unicode data files and any associated documentation | ||
| // (the "Data Files") or Unicode software and any associated documentation | ||
| // (the "Software") to deal in the Data Files or Software | ||
| // without restriction, including without limitation the rights to use, | ||
| // copy, modify, merge, publish, distribute, and/or sell copies of | ||
| // the Data Files or Software, and to permit persons to whom the Data Files | ||
| // or Software are furnished to do so, provided that either | ||
| // (a) this copyright and permission notice appear with all copies | ||
| // of the Data Files or Software, or | ||
| // (b) this copyright and permission notice appear in associated | ||
| // Documentation. | ||
| // | ||
| // THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF | ||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | ||
| // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| // NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
| // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS | ||
| // NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL | ||
| // DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
| // DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
| // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
| // PERFORMANCE OF THE DATA FILES OR SOFTWARE. | ||
| // | ||
| // Except as contained in this notice, the name of a copyright holder | ||
| // shall not be used in advertising or otherwise to promote the sale, | ||
| // use or other dealings in these Data Files or Software without prior | ||
| // written authorization of the copyright holder. | ||
|
|
||
| #ifndef _LIBCPP___FORMAT_INDIC_CONJUNCT_BREAK_TABLE_H | ||
| #define _LIBCPP___FORMAT_INDIC_CONJUNCT_BREAK_TABLE_H | ||
|
|
||
| #include <__algorithm/ranges_upper_bound.h> | ||
| #include <__config> | ||
| #include <__iterator/access.h> | ||
| #include <cstddef> | ||
| #include <cstdint> | ||
|
|
||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||
| # pragma GCC system_header | ||
| #endif | ||
|
|
||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||
|
|
||
| #if _LIBCPP_STD_VER >= 20 | ||
|
|
||
| namespace __indic_conjunct_break { | ||
|
|
||
| enum class __property : uint8_t { | ||
| // Values generated from the data files. | ||
| __Consonant, | ||
| __Extend, | ||
| __Linker, | ||
|
|
||
| // The code unit has none of above properties. | ||
| __none | ||
| }; | ||
|
|
||
| /// The entries of the indic conjunct break property table. | ||
| /// | ||
| /// The data is generated from | ||
| /// - https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt | ||
| /// | ||
| /// The data has 3 values | ||
| /// - bits [0, 1] The property. One of the values generated from the datafiles | ||
| /// of \ref __property | ||
| /// - bits [2, 10] The size of the range. | ||
| /// - bits [11, 31] The lower bound code point of the range. The upper bound of | ||
| /// the range is lower bound + size. | ||
| /// | ||
| /// The 9 bits for the size allow a maximum range of 512 elements. Some ranges | ||
| /// in the Unicode tables are larger. They are stored in multiple consecutive | ||
| /// ranges in the data table. An alternative would be to store the sizes in a | ||
| /// separate 16-bit value. The original MSVC STL code had such an approach, but | ||
| /// this approach uses less space for the data and is about 4% faster in the | ||
| /// following benchmark. | ||
| /// libcxx/benchmarks/std_format_spec_string_unicode.bench.cpp | ||
| // clang-format off | ||
| _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { | ||
| 0x00180139, | ||
| 0x001a807d, | ||
| 0x00241811, | ||
| 0x002c88b1, | ||
| 0x002df801, | ||
| 0x002e0805, | ||
| 0x002e2005, | ||
| 0x002e3801, | ||
| 0x00308029, | ||
| 0x00325851, | ||
| 0x00338001, | ||
| 0x0036b019, | ||
| 0x0036f815, | ||
| 0x00373805, | ||
| 0x0037500d, | ||
| 0x00388801, | ||
| 0x00398069, | ||
| 0x003f5821, | ||
| 0x003fe801, | ||
| 0x0040b00d, | ||
| 0x0040d821, | ||
| 0x00412809, | ||
| 0x00414811, | ||
| 0x0042c809, | ||
| 0x0044c01d, | ||
| 0x0046505d, | ||
| 0x00471871, | ||
| 0x0048a890, | ||
| 0x0049e001, | ||
| 0x004a6802, | ||
| 0x004a880d, | ||
| 0x004ac01c, | ||
| 0x004bc01c, | ||
| 0x004ca84c, | ||
| 0x004d5018, | ||
| 0x004d9000, | ||
| 0x004db00c, | ||
| 0x004de001, | ||
| 0x004e6802, | ||
| 0x004ee004, | ||
| 0x004ef800, | ||
| 0x004f8004, | ||
| 0x004ff001, | ||
| 0x0051e001, | ||
| 0x0054a84c, | ||
| 0x00555018, | ||
| 0x00559004, | ||
| 0x0055a810, | ||
| 0x0055e001, | ||
| 0x00566802, | ||
| 0x0057c800, | ||
| 0x0058a84c, | ||
| 0x00595018, | ||
| 0x00599004, | ||
| 0x0059a810, | ||
| 0x0059e001, | ||
| 0x005a6802, | ||
| 0x005ae004, | ||
| 0x005af800, | ||
| 0x005b8800, | ||
| 0x0060a84c, | ||
| 0x0061503c, | ||
| 0x0061e001, | ||
| 0x00626802, | ||
| 0x0062a805, | ||
| 0x0062c008, | ||
| 0x0065e001, | ||
| 0x0068a894, | ||
| 0x0069d805, | ||
| 0x006a6802, | ||
| 0x0071c009, | ||
| 0x0072400d, | ||
| 0x0075c009, | ||
| 0x0076400d, | ||
| 0x0078c005, | ||
| 0x0079a801, | ||
| 0x0079b801, | ||
| 0x0079c801, | ||
| 0x007b8805, | ||
| 0x007ba001, | ||
| 0x007bd00d, | ||
| 0x007c0001, | ||
| 0x007c1009, | ||
| 0x007c3005, | ||
| 0x007e3001, | ||
| 0x0081b801, | ||
| 0x0081c805, | ||
| 0x00846801, | ||
| 0x009ae809, | ||
| 0x00b8a001, | ||
| 0x00be9001, | ||
| 0x00bee801, | ||
| 0x00c54801, | ||
| 0x00c9c809, | ||
| 0x00d0b805, | ||
| 0x00d30001, | ||
| 0x00d3a81d, | ||
| 0x00d3f801, | ||
| 0x00d58035, | ||
| 0x00d5f83d, | ||
| 0x00d9a001, | ||
| 0x00db5821, | ||
| 0x00dd5801, | ||
| 0x00df3001, | ||
| 0x00e1b801, | ||
| 0x00e68009, | ||
| 0x00e6a031, | ||
| 0x00e71019, | ||
| 0x00e76801, | ||
| 0x00e7a001, | ||
| 0x00e7c005, | ||
| 0x00ee00fd, | ||
| 0x01006801, | ||
| 0x01068031, | ||
| 0x01070801, | ||
| 0x0107282d, | ||
| 0x01677809, | ||
| 0x016bf801, | ||
| 0x016f007d, | ||
| 0x01815015, | ||
| 0x0184c805, | ||
| 0x05337801, | ||
| 0x0533a025, | ||
| 0x0534f005, | ||
| 0x05378005, | ||
| 0x05416001, | ||
| 0x05470045, | ||
| 0x05495809, | ||
| 0x054d9801, | ||
| 0x05558001, | ||
| 0x05559009, | ||
| 0x0555b805, | ||
| 0x0555f005, | ||
| 0x05560801, | ||
| 0x0557b001, | ||
| 0x055f6801, | ||
| 0x07d8f001, | ||
| 0x07f1003d, | ||
| 0x080fe801, | ||
| 0x08170001, | ||
| 0x081bb011, | ||
| 0x08506801, | ||
| 0x08507801, | ||
| 0x0851c009, | ||
| 0x0851f801, | ||
| 0x08572805, | ||
| 0x0869200d, | ||
| 0x08755805, | ||
| 0x0877e809, | ||
| 0x087a3029, | ||
| 0x087c100d, | ||
| 0x08838001, | ||
| 0x0883f801, | ||
| 0x0885d001, | ||
| 0x08880009, | ||
| 0x08899805, | ||
| 0x088b9801, | ||
| 0x088e5001, | ||
| 0x0891b001, | ||
| 0x08974805, | ||
| 0x0899d805, | ||
| 0x089b3019, | ||
| 0x089b8011, | ||
| 0x08a23001, | ||
| 0x08a2f001, | ||
| 0x08a61801, | ||
| 0x08ae0001, | ||
| 0x08b5b801, | ||
| 0x08b95801, | ||
| 0x08c1d001, | ||
| 0x08c9f001, | ||
| 0x08ca1801, | ||
| 0x08d1a001, | ||
| 0x08d23801, | ||
| 0x08d4c801, | ||
| 0x08ea1001, | ||
| 0x08ea2005, | ||
| 0x08ecb801, | ||
| 0x08fa1001, | ||
| 0x0b578011, | ||
| 0x0b598019, | ||
| 0x0de4f001, | ||
| 0x0e8b2801, | ||
| 0x0e8b3809, | ||
| 0x0e8b7011, | ||
| 0x0e8bd81d, | ||
| 0x0e8c2819, | ||
| 0x0e8d500d, | ||
| 0x0e921009, | ||
| 0x0f000019, | ||
| 0x0f004041, | ||
| 0x0f00d819, | ||
| 0x0f011805, | ||
| 0x0f013011, | ||
| 0x0f047801, | ||
| 0x0f098019, | ||
| 0x0f157001, | ||
| 0x0f17600d, | ||
| 0x0f27600d, | ||
| 0x0f468019, | ||
| 0x0f4a2019}; | ||
| // clang-format on | ||
|
|
||
| /// Returns the indic conjuct break property of a code point. | ||
| [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __property __get_property(const char32_t __code_point) noexcept { | ||
| // The algorithm searches for the upper bound of the range and, when found, | ||
| // steps back one entry. This algorithm is used since the code point can be | ||
| // anywhere in the range. After a lower bound is found the next step is to | ||
| // compare whether the code unit is indeed in the range. | ||
| // | ||
| // Since the entry contains a code unit, size, and property the code point | ||
| // being sought needs to be adjusted. Just shifting the code point to the | ||
| // proper position doesn't work; suppose an entry has property 0, size 1, | ||
| // and lower bound 3. This results in the entry 0x1810. | ||
| // When searching for code point 3 it will search for 0x1800, find 0x1810 | ||
| // and moves to the previous entry. Thus the lower bound value will never | ||
| // be found. | ||
| // The simple solution is to set the bits belonging to the property and | ||
| // size. Then the upper bound for code point 3 will return the entry after | ||
| // 0x1810. After moving to the previous entry the algorithm arrives at the | ||
| // correct entry. | ||
| ptrdiff_t __i = std::ranges::upper_bound(__entries, (__code_point << 11) | 0x7ffu) - __entries; | ||
| if (__i == 0) | ||
| return __property::__none; | ||
|
|
||
| --__i; | ||
| uint32_t __upper_bound = (__entries[__i] >> 11) + ((__entries[__i] >> 2) & 0b1'1111'1111); | ||
| if (__code_point <= __upper_bound) | ||
| return static_cast<__property>(__entries[__i] & 0b11); | ||
|
|
||
| return __property::__none; | ||
| } | ||
|
|
||
| } // namespace __indic_conjunct_break | ||
|
|
||
| #endif //_LIBCPP_STD_VER >= 20 | ||
|
|
||
| _LIBCPP_END_NAMESPACE_STD | ||
|
|
||
| #endif // _LIBCPP___FORMAT_INDIC_CONJUNCT_BREAK_TABLE_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // UNSUPPORTED: no-exceptions | ||
|
|
||
| // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME | ||
|
|
||
| // XFAIL: availability-fp_to_chars-missing | ||
|
|
||
| #include <cstdint> | ||
| #include <format> | ||
| #include <string_view> | ||
|
|
||
| #include "fuzz.h" | ||
|
|
||
| extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size) { | ||
| try { | ||
| [[maybe_unused]] auto result = std::vformat(std::string_view{(const char*)(data), size}, std::make_format_args()); | ||
| } catch (std::format_error const&) { | ||
| // If the fuzzing input isn't a valid thing we can format and we detect it, it's okay. We are looking for crashes. | ||
| return 0; | ||
| } | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // 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, c++20 | ||
|
|
||
| // template<> | ||
| // class bad_expected_access<void> : public exception { | ||
| // protected: | ||
| // bad_expected_access() noexcept; | ||
| // bad_expected_access(const bad_expected_access&) noexcept; | ||
| // bad_expected_access(bad_expected_access&&) noexcept; | ||
| // bad_expected_access& operator=(const bad_expected_access&) noexcept; | ||
| // bad_expected_access& operator=(bad_expected_access&&) noexcept; | ||
| // ~bad_expected_access(); | ||
| // | ||
| // public: | ||
| // const char* what() const noexcept override; | ||
| // }; | ||
|
|
||
| #include <cassert> | ||
| #include <exception> | ||
| #include <expected> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
||
| #include "test_macros.h" | ||
|
|
||
| struct Inherit : std::bad_expected_access<void> {}; | ||
|
|
||
| int main(int, char**) { | ||
| // base class | ||
| static_assert(std::is_base_of_v<std::exception, std::bad_expected_access<void>>); | ||
|
|
||
| // default constructor | ||
| { | ||
| Inherit exc; | ||
| ASSERT_NOEXCEPT(Inherit()); | ||
| } | ||
|
|
||
| // copy constructor | ||
| { | ||
| Inherit exc; | ||
| Inherit copy(exc); | ||
| ASSERT_NOEXCEPT(Inherit(exc)); | ||
| } | ||
|
|
||
| // move constructor | ||
| { | ||
| Inherit exc; | ||
| Inherit copy(std::move(exc)); | ||
| ASSERT_NOEXCEPT(Inherit(std::move(exc))); | ||
| } | ||
|
|
||
| // copy assignment | ||
| { | ||
| Inherit exc; | ||
| Inherit copy; | ||
| [[maybe_unused]] Inherit& result = (copy = exc); | ||
| ASSERT_NOEXCEPT(copy = exc); | ||
| } | ||
|
|
||
| // move assignment | ||
| { | ||
| Inherit exc; | ||
| Inherit copy; | ||
| [[maybe_unused]] Inherit& result = (copy = std::move(exc)); | ||
| ASSERT_NOEXCEPT(copy = std::move(exc)); | ||
| } | ||
|
|
||
| // what() | ||
| { | ||
| Inherit exc; | ||
| char const* what = exc.what(); | ||
| assert(what != nullptr); | ||
| ASSERT_NOEXCEPT(exc.what()); | ||
| } | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // 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, c++20 | ||
|
|
||
| // const char* what() const noexcept override; | ||
|
|
||
| #include <expected> | ||
| #include <cassert> | ||
| #include <utility> | ||
|
|
||
| #include "test_macros.h" | ||
|
|
||
| struct Foo {}; | ||
|
|
||
| int main(int, char**) { | ||
| { | ||
| std::bad_expected_access<int> const exc(99); | ||
| char const* what = exc.what(); | ||
| assert(what != nullptr); | ||
| ASSERT_NOEXCEPT(exc.what()); | ||
| } | ||
| { | ||
| std::bad_expected_access<Foo> const exc(Foo{}); | ||
| char const* what = exc.what(); | ||
| assert(what != nullptr); | ||
| ASSERT_NOEXCEPT(exc.what()); | ||
| } | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,381 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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, c++20 | ||
|
|
||
| // <functional> | ||
|
|
||
| // template<class F, class... Args> | ||
| // constexpr unspecified bind_back(F&& f, Args&&... args); | ||
|
|
||
| #include <functional> | ||
|
|
||
| #include <cassert> | ||
| #include <concepts> | ||
| #include <tuple> | ||
| #include <utility> | ||
|
|
||
| #include "callable_types.h" | ||
| #include "types.h" | ||
|
|
||
| constexpr void test_basic_bindings() { | ||
| { // Bind arguments, call without arguments | ||
| { | ||
| auto f = std::bind_back(MakeTuple{}); | ||
| assert(f() == std::make_tuple()); | ||
| } | ||
| { | ||
| auto f = std::bind_back(MakeTuple{}, Elem<1>{}); | ||
| assert(f() == std::make_tuple(Elem<1>{})); | ||
| } | ||
| { | ||
| auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}); | ||
| assert(f() == std::make_tuple(Elem<1>{}, Elem<2>{})); | ||
| } | ||
| { | ||
| auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{}); | ||
| assert(f() == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{})); | ||
| } | ||
| } | ||
|
|
||
| { // Bind no arguments, call with arguments | ||
| { | ||
| auto f = std::bind_back(MakeTuple{}); | ||
| assert(f(Elem<1>{}) == std::make_tuple(Elem<1>{})); | ||
| } | ||
| { | ||
| auto f = std::bind_back(MakeTuple{}); | ||
| assert(f(Elem<1>{}, Elem<2>{}) == std::make_tuple(Elem<1>{}, Elem<2>{})); | ||
| } | ||
| { | ||
| auto f = std::bind_back(MakeTuple{}); | ||
| assert(f(Elem<1>{}, Elem<2>{}, Elem<3>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{})); | ||
| } | ||
| } | ||
|
|
||
| { // Bind arguments, call with arguments | ||
| { | ||
| auto f = std::bind_back(MakeTuple{}, Elem<1>{}); | ||
| assert(f(Elem<10>{}) == std::make_tuple(Elem<10>{}, Elem<1>{})); | ||
| } | ||
| { | ||
| auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}); | ||
| assert(f(Elem<10>{}) == std::make_tuple(Elem<10>{}, Elem<1>{}, Elem<2>{})); | ||
| } | ||
| { | ||
| auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{}); | ||
| assert(f(Elem<10>{}) == std::make_tuple(Elem<10>{}, Elem<1>{}, Elem<2>{}, Elem<3>{})); | ||
| } | ||
|
|
||
| { | ||
| auto f = std::bind_back(MakeTuple{}, Elem<1>{}); | ||
| assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<10>{}, Elem<11>{}, Elem<1>{})); | ||
| } | ||
| { | ||
| auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}); | ||
| assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<10>{}, Elem<11>{}, Elem<1>{}, Elem<2>{})); | ||
| } | ||
| { | ||
| auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{}); | ||
| assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<10>{}, Elem<11>{}, Elem<1>{}, Elem<2>{}, Elem<3>{})); | ||
| } | ||
| { | ||
| auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{}); | ||
| assert(f(Elem<10>{}, Elem<11>{}, Elem<12>{}) == | ||
| std::make_tuple(Elem<10>{}, Elem<11>{}, Elem<12>{}, Elem<1>{}, Elem<2>{}, Elem<3>{})); | ||
| } | ||
| } | ||
|
|
||
| { // Basic tests with fundamental types | ||
| int n = 2; | ||
| int m = 1; | ||
| int sum = 0; | ||
| auto add = [](int x, int y) { return x + y; }; | ||
| auto add_n = [](int a, int b, int c, int d, int e, int f) { return a + b + c + d + e + f; }; | ||
| auto add_ref = [&](int x, int y) -> int& { return sum = x + y; }; | ||
| auto add_rref = [&](int x, int y) -> int&& { return std::move(sum = x + y); }; | ||
|
|
||
| auto a = std::bind_back(add, m, n); | ||
| assert(a() == 3); | ||
|
|
||
| auto b = std::bind_back(add_n, m, n, m, m, m, m); | ||
| assert(b() == 7); | ||
|
|
||
| auto c = std::bind_back(add_n, n, m); | ||
| assert(c(1, 1, 1, 1) == 7); | ||
|
|
||
| auto d = std::bind_back(add_ref, n, m); | ||
| std::same_as<int&> decltype(auto) dresult(d()); | ||
| assert(dresult == 3); | ||
|
|
||
| auto e = std::bind_back(add_rref, n, m); | ||
| std::same_as<int&&> decltype(auto) eresult(e()); | ||
| assert(eresult == 3); | ||
|
|
||
| auto f = std::bind_back(add, n); | ||
| assert(f(3) == 5); | ||
|
|
||
| auto g = std::bind_back(add, n, 1); | ||
| assert(g() == 3); | ||
|
|
||
| auto h = std::bind_back(add_n, 1, 1, 1); | ||
| assert(h(2, 2, 2) == 9); | ||
|
|
||
| auto i = std::bind_back(add_ref, n); | ||
| std::same_as<int&> decltype(auto) iresult(i(5)); | ||
| assert(iresult == 7); | ||
|
|
||
| auto j = std::bind_back(add_rref, m); | ||
| std::same_as<int&&> decltype(auto) jresult(j(4)); | ||
| assert(jresult == 5); | ||
| } | ||
| } | ||
|
|
||
| constexpr void test_edge_cases() { | ||
| { // Make sure we don't treat std::reference_wrapper specially. | ||
| auto sub = [](std::reference_wrapper<int> a, std::reference_wrapper<int> b) { return a.get() - b.get(); }; | ||
|
|
||
| int i = 1; | ||
| int j = 2; | ||
| auto f = std::bind_back(sub, std::ref(i)); | ||
| assert(f(std::ref(j)) == 1); | ||
| } | ||
|
|
||
| { // Make sure we can call a function that's a pointer to a member function. | ||
| struct MemberFunction { | ||
| constexpr int foo(int x, int y) { return x * y; } | ||
| }; | ||
|
|
||
| MemberFunction value; | ||
| auto fn = std::bind_back(&MemberFunction::foo, 2, 3); | ||
| assert(fn(value) == 6); | ||
| } | ||
|
|
||
| { // Make sure we can call a function that's a pointer to a member object. | ||
| struct MemberObject { | ||
| int obj; | ||
| }; | ||
|
|
||
| MemberObject value{.obj = 3}; | ||
| auto fn = std::bind_back(&MemberObject::obj); | ||
| assert(fn(value) == 3); | ||
| } | ||
| } | ||
|
|
||
| constexpr void test_passing_arguments() { | ||
| { // Make sure that we copy the bound arguments into the unspecified-type. | ||
| auto add = [](int x, int y) { return x + y; }; | ||
| int n = 2; | ||
| auto f = std::bind_back(add, n, 1); | ||
| n = 100; | ||
| assert(f() == 3); | ||
| } | ||
|
|
||
| { // Make sure we pass the bound arguments to the function object | ||
| // with the right value category. | ||
| { | ||
| auto was_copied = [](CopyMoveInfo info) { return info.copy_kind == CopyMoveInfo::copy; }; | ||
| CopyMoveInfo info; | ||
| auto f = std::bind_back(was_copied, info); | ||
| assert(f()); | ||
| } | ||
|
|
||
| { | ||
| auto was_moved = [](CopyMoveInfo info) { return info.copy_kind == CopyMoveInfo::move; }; | ||
| CopyMoveInfo info; | ||
| auto f = std::bind_back(was_moved, info); | ||
| assert(std::move(f)()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| constexpr void test_function_objects() { | ||
| { // Make sure we call the correctly cv-ref qualified operator() | ||
| // based on the value category of the bind_back unspecified-type. | ||
| struct X { | ||
| constexpr int operator()() & { return 1; } | ||
| constexpr int operator()() const& { return 2; } | ||
| constexpr int operator()() && { return 3; } | ||
| constexpr int operator()() const&& { return 4; } | ||
| }; | ||
|
|
||
| auto f = std::bind_back(X{}); | ||
| using F = decltype(f); | ||
| assert(static_cast<F&>(f)() == 1); | ||
| assert(static_cast<const F&>(f)() == 2); | ||
| assert(static_cast<F&&>(f)() == 3); | ||
| assert(static_cast<const F&&>(f)() == 4); | ||
| } | ||
|
|
||
| // Make sure the `bind_back` unspecified-type does not model invocable | ||
| // when the call would select a differently-qualified operator(). | ||
| // | ||
| // For example, if the call to `operator()() &` is ill-formed, the call to the unspecified-type | ||
| // should be ill-formed and not fall back to the `operator()() const&` overload. | ||
| { // Make sure we delete the & overload when the underlying call isn't valid. | ||
| { | ||
| struct X { | ||
| void operator()() & = delete; | ||
| void operator()() const&; | ||
| void operator()() &&; | ||
| void operator()() const&&; | ||
| }; | ||
|
|
||
| using F = decltype(std::bind_back(X{})); | ||
| static_assert(!std::invocable<F&>); | ||
| static_assert(std::invocable<const F&>); | ||
| static_assert(std::invocable<F>); | ||
| static_assert(std::invocable<const F>); | ||
| } | ||
|
|
||
| // There's no way to make sure we delete the const& overload when the underlying call isn't valid, | ||
| // so we can't check this one. | ||
|
|
||
| { // Make sure we delete the && overload when the underlying call isn't valid. | ||
| struct X { | ||
| void operator()() &; | ||
| void operator()() const&; | ||
| void operator()() && = delete; | ||
| void operator()() const&&; | ||
| }; | ||
|
|
||
| using F = decltype(std::bind_back(X{})); | ||
| static_assert(std::invocable<F&>); | ||
| static_assert(std::invocable<const F&>); | ||
| static_assert(!std::invocable<F>); | ||
| static_assert(std::invocable<const F>); | ||
| } | ||
|
|
||
| { // Make sure we delete the const&& overload when the underlying call isn't valid. | ||
| struct X { | ||
| void operator()() &; | ||
| void operator()() const&; | ||
| void operator()() &&; | ||
| void operator()() const&& = delete; | ||
| }; | ||
|
|
||
| using F = decltype(std::bind_back(X{})); | ||
| static_assert(std::invocable<F&>); | ||
| static_assert(std::invocable<const F&>); | ||
| static_assert(std::invocable<F>); | ||
| static_assert(!std::invocable<const F>); | ||
| } | ||
| } | ||
|
|
||
| { // Extra value category tests | ||
| struct X {}; | ||
|
|
||
| { | ||
| struct Y { | ||
| void operator()(X&&) const&; | ||
| void operator()(X&&) && = delete; | ||
| }; | ||
|
|
||
| using F = decltype(std::bind_back(Y{})); | ||
| static_assert(std::invocable<F&, X>); | ||
| static_assert(!std::invocable<F, X>); | ||
| } | ||
|
|
||
| { | ||
| struct Y { | ||
| void operator()(const X&) const; | ||
| void operator()(X&&) const = delete; | ||
| }; | ||
|
|
||
| using F = decltype(std::bind_back(Y{}, X{})); | ||
| static_assert(std::invocable<F&>); | ||
| static_assert(!std::invocable<F>); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| constexpr void test_return_type() { | ||
| { // Test properties of the constructor of the unspecified-type returned by bind_back. | ||
| { // Test move constructor when function is move only. | ||
| MoveOnlyCallable<bool> value(true); | ||
| auto f = std::bind_back(std::move(value), 1); | ||
| assert(f()); | ||
| assert(f(1, 2, 3)); | ||
|
|
||
| auto f1 = std::move(f); | ||
| assert(!f()); | ||
| assert(f1()); | ||
| assert(f1(1, 2, 3)); | ||
|
|
||
| using F = decltype(f); | ||
| static_assert(std::is_move_constructible<F>::value); | ||
| static_assert(!std::is_copy_constructible<F>::value); | ||
| static_assert(!std::is_move_assignable<F>::value); | ||
| static_assert(!std::is_copy_assignable<F>::value); | ||
| } | ||
|
|
||
| { // Test move constructor when function is copyable but not assignable. | ||
| CopyCallable<bool> value(true); | ||
| auto f = std::bind_back(value, 1); | ||
| assert(f()); | ||
| assert(f(1, 2, 3)); | ||
|
|
||
| auto f1 = std::move(f); | ||
| assert(!f()); | ||
| assert(f1()); | ||
| assert(f1(1, 2, 3)); | ||
|
|
||
| auto f2 = std::bind_back(std::move(value), 1); | ||
| assert(f1()); | ||
| assert(f2()); | ||
| assert(f2(1, 2, 3)); | ||
|
|
||
| using F = decltype(f); | ||
| static_assert(std::is_move_constructible<F>::value); | ||
| static_assert(std::is_copy_constructible<F>::value); | ||
| static_assert(!std::is_move_assignable<F>::value); | ||
| static_assert(!std::is_copy_assignable<F>::value); | ||
| } | ||
|
|
||
| { // Test constructors when function is copy assignable. | ||
| using F = decltype(std::bind_back(std::declval<CopyAssignableWrapper&>(), 1)); | ||
| static_assert(std::is_move_constructible<F>::value); | ||
| static_assert(std::is_copy_constructible<F>::value); | ||
| static_assert(std::is_move_assignable<F>::value); | ||
| static_assert(std::is_copy_assignable<F>::value); | ||
| } | ||
|
|
||
| { // Test constructors when function is move assignable only. | ||
| using F = decltype(std::bind_back(std::declval<MoveAssignableWrapper>(), 1)); | ||
| static_assert(std::is_move_constructible<F>::value); | ||
| static_assert(!std::is_copy_constructible<F>::value); | ||
| static_assert(std::is_move_assignable<F>::value); | ||
| static_assert(!std::is_copy_assignable<F>::value); | ||
| } | ||
| } | ||
|
|
||
| { // Make sure bind_back's unspecified type's operator() is SFINAE-friendly. | ||
| using F = decltype(std::bind_back(std::declval<int (*)(int, int)>(), 1)); | ||
| static_assert(!std::is_invocable<F>::value); | ||
| static_assert(std::is_invocable<F, int>::value); | ||
| static_assert(!std::is_invocable<F, void*>::value); | ||
| static_assert(!std::is_invocable<F, int, int>::value); | ||
| } | ||
| } | ||
|
|
||
| constexpr bool test() { | ||
| test_basic_bindings(); | ||
| test_edge_cases(); | ||
| test_passing_arguments(); | ||
| test_function_objects(); | ||
| test_return_type(); | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| test(); | ||
| static_assert(test()); | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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, c++20 | ||
|
|
||
| // <functional> | ||
|
|
||
| // template<class F, class... Args> | ||
| // constexpr unspecified bind_back(F&& f, Args&&... args); | ||
|
|
||
| #include <functional> | ||
|
|
||
| #include "types.h" | ||
|
|
||
| constexpr int pass(int n) { return n; } | ||
|
|
||
| void test() { | ||
| { // Test calling constexpr function from non-constexpr `bind_back` result | ||
| auto f1 = std::bind_back(pass, 1); | ||
| static_assert(f1() == 1); // expected-error {{static assertion expression is not an integral constant expression}} | ||
| } | ||
|
|
||
| { // Test calling `bind_back` with template function | ||
| auto f1 = std::bind_back(do_nothing, 2); | ||
| // expected-error@-1 {{no matching function for call to 'bind_back'}} | ||
| } | ||
|
|
||
| { // Mandates: is_constructible_v<decay_t<F>, F> | ||
| struct F { | ||
| F() = default; | ||
| F(const F&) = default; | ||
| F(F&) = delete; | ||
|
|
||
| void operator()() {} | ||
| }; | ||
|
|
||
| F f; | ||
| auto f1 = std::bind_back(f); | ||
| // expected-error-re@*:* {{static assertion failed{{.*}}bind_back requires decay_t<F> to be constructible from F}} | ||
| } | ||
|
|
||
| { // Mandates: is_move_constructible_v<decay_t<F>> | ||
| struct F { | ||
| F() = default; | ||
| F(const F&) = default; | ||
| F(F&&) = delete; | ||
|
|
||
| void operator()() {} | ||
| }; | ||
|
|
||
| F f; | ||
| auto f1 = std::bind_back(f); | ||
| // expected-error-re@*:* {{static assertion failed{{.*}}bind_back requires decay_t<F> to be move constructible}} | ||
| } | ||
|
|
||
| { // Mandates: (is_constructible_v<decay_t<Args>, Args> && ...) | ||
| struct Arg { | ||
| Arg() = default; | ||
| Arg(const Arg&) = default; | ||
| Arg(Arg&) = delete; | ||
| }; | ||
|
|
||
| Arg x; | ||
| auto f = std::bind_back([](const Arg&) {}, x); | ||
| // expected-error-re@*:* {{static assertion failed{{.*}}bind_back requires all decay_t<Args> to be constructible from respective Args}} | ||
| // expected-error@*:* {{no matching constructor for initialization}} | ||
| } | ||
|
|
||
| { // Mandates: (is_move_constructible_v<decay_t<Args>> && ...) | ||
| struct Arg { | ||
| Arg() = default; | ||
| Arg(const Arg&) = default; | ||
| Arg(Arg&&) = delete; | ||
| }; | ||
|
|
||
| Arg x; | ||
| auto f = std::bind_back([](Arg&) {}, x); | ||
| // expected-error-re@*:* {{static assertion failed{{.*}}bind_back requires all decay_t<Args> to be move constructible}} | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef TEST_STD_UTILITIES_FUNCTION_OBJECTS_FUNC_BIND_PARTIAL_TYPES_H | ||
| #define TEST_STD_UTILITIES_FUNCTION_OBJECTS_FUNC_BIND_PARTIAL_TYPES_H | ||
|
|
||
| #include <tuple> | ||
| #include <utility> | ||
|
|
||
| struct MakeTuple { | ||
| template <class... Args> | ||
| constexpr auto operator()(Args&&... args) const { | ||
| return std::make_tuple(std::forward<Args>(args)...); | ||
| } | ||
| }; | ||
|
|
||
| template <int X> | ||
| struct Elem { | ||
| template <int Y> | ||
| constexpr bool operator==(const Elem<Y>&) const { | ||
| return X == Y; | ||
| } | ||
| }; | ||
|
|
||
| struct CopyMoveInfo { | ||
| enum { none, copy, move } copy_kind; | ||
|
|
||
| constexpr CopyMoveInfo() : copy_kind(none) {} | ||
| constexpr CopyMoveInfo(const CopyMoveInfo&) : copy_kind(copy) {} | ||
| constexpr CopyMoveInfo(CopyMoveInfo&&) : copy_kind(move) {} | ||
| }; | ||
|
|
||
| template <class T> | ||
| T do_nothing(T t) { | ||
| return t; | ||
| } | ||
|
|
||
| #endif // TEST_STD_UTILITIES_FUNCTION_OBJECTS_FUNC_BIND_PARTIAL_TYPES_H |