diff options
Diffstat (limited to 'libcxx')
46 files changed, 595 insertions, 177 deletions
diff --git a/libcxx/cmake/caches/Generic-hardening-mode-extensive-observe-semantic.cmake b/libcxx/cmake/caches/Generic-hardening-mode-extensive-observe-semantic.cmake new file mode 100644 index 0000000..c843c02 --- /dev/null +++ b/libcxx/cmake/caches/Generic-hardening-mode-extensive-observe-semantic.cmake @@ -0,0 +1,2 @@ +set(LIBCXX_HARDENING_MODE "extensive" CACHE STRING "") +set(LIBCXX_TEST_PARAMS "assertion_semantic=observe" CACHE STRING "") diff --git a/libcxx/docs/Hardening.rst b/libcxx/docs/Hardening.rst index 1780884..1cdb360 100644 --- a/libcxx/docs/Hardening.rst +++ b/libcxx/docs/Hardening.rst @@ -39,6 +39,8 @@ modes are: Enabling hardening has no impact on the ABI. +.. _notes-for-users: + Notes for users --------------- @@ -72,6 +74,10 @@ to control the level by passing **one** of the following options to the compiler pre-built components. Most libc++ code is header-based, so a user-provided value for ``_LIBCPP_HARDENING_MODE`` will be mostly respected. +In some cases, users might want to override the assertion semantic used by the +library. This can be done similarly to setting the hardening mode; please refer +to the :ref:`relevant section <assertion-semantics>`. + Notes for vendors ----------------- @@ -260,6 +266,68 @@ output. This is less secure and increases the size of the binary (among other things, it has to store the error message strings) but makes the failure easier to debug. It also allows testing the error messages in our test suite. +This default behavior can be customized by users via :ref:`assertion semantics +<assertion-semantics>`; it can also be completely overridden by vendors by +providing a :ref:`custom assertion failure handler +<override-assertion-handler>`. + +.. _assertion-semantics: + +Assertion semantics +------------------- + +.. warning:: + + Assertion semantics are currently an experimental feature. + +.. note:: + + Assertion semantics are not available in the C++03 mode. + +What happens when an assertion fails depends on the assertion semantic being +used. Four assertion semantics are available, based on C++26 Contracts +evaluation semantics: + +- ``ignore`` evaluates the assertion but has no effect if it fails (note that it + differs from the Contracts ``ignore`` semantic which would not evaluate + the assertion at all); +- ``observe`` logs an error (indicating, if possible on the platform, that the + error is fatal) but continues execution; +- ``quick-enforce`` terminates the program as fast as possible via a trap + instruction. It is the default semantic for the production modes (``fast`` and + ``extensive``); +- ``enforce`` logs an error and then terminates the program. It is the default + semantic for the ``debug`` mode. + +Notes: + +- Continuing execution after a hardening check fails results in undefined + behavior; the ``observe`` semantic is meant to make adopting hardening easier + but should not be used outside of the adoption period; +- C++26 wording for Library Hardening precludes a conforming Hardened + implementation from using the Contracts ``ignore`` semantic when evaluating + hardened preconditions in the Library. Libc++ allows using this semantic for + hardened preconditions, but please be aware that using ``ignore`` does not + produce a conforming "Hardened" implementation, unlike the other semantics + above. + +The default assertion semantics are as follows: + +- ``fast``: ``quick-enforce``; +- ``extensive``: ``quick-enforce``; +- ``debug``: ``enforce``. + +The default assertion semantics can be overridden by passing **one** of the +following options to the compiler: + +- ``-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE`` +- ``-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_OBSERVE`` +- ``-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE`` +- ``-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE`` + +All the :ref:`same notes <notes-for-users>` apply to setting this macro as for +setting ``_LIBCPP_HARDENING_MODE``. + .. _override-assertion-handler: Overriding the assertion failure handler diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index d31ca01..74bfa97 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -88,6 +88,12 @@ Improvements and New Features - ``ctype::tolower`` and ``ctype::toupper`` have been optimized, resulting in a 2x performance improvement. +- As an experimental feature, Hardening now supports assertion semantics that allow customizing how a hardening + assertion failure is handled. The four available semantics, modeled on C++26 Contracts, are ``ignore``, ``observe``, + ``quick-enforce`` and ``enforce``. The ``observe`` semantic is intended to make it easier to adopt Hardening in + production but should not be used outside of this scenario. Please refer to the :ref:`Hardening documentation + <hardening>` for details. + Deprecations and Removals ------------------------- diff --git a/libcxx/docs/UserDocumentation.rst b/libcxx/docs/UserDocumentation.rst index 79f5908..415a599 100644 --- a/libcxx/docs/UserDocumentation.rst +++ b/libcxx/docs/UserDocumentation.rst @@ -72,6 +72,11 @@ when ``-fexperimental-library`` is passed: * ``std::chrono::tzdb`` and related time zone functionality * ``<syncstream>`` +Additionally, assertion semantics are an experimental feature that can be used +to customize the behavior of Hardening (see :ref:`here <assertion-semantics>`). +Assertion semantics mirror the evaluation semantics of C++26 Contracts but are +not a standard feature. + .. note:: Experimental libraries are experimental. * The contents of the ``<experimental/...>`` headers and the associated static diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index ed54751..51444ec 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -381,6 +381,7 @@ set(files __format/enable_insertable.h __format/escaped_output_table.h __format/extended_grapheme_cluster_table.h + __format/fmt_pair_like.h __format/format_arg.h __format/format_arg_store.h __format/format_args.h diff --git a/libcxx/include/__algorithm/copy.h b/libcxx/include/__algorithm/copy.h index ea98031..6387728 100644 --- a/libcxx/include/__algorithm/copy.h +++ b/libcxx/include/__algorithm/copy.h @@ -182,7 +182,7 @@ struct __copy_impl { } }; - template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator<_InIter>::value, int> = 0> + template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator_v<_InIter>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> operator()(_InIter __first, _InIter __last, _OutIter __result) const { std::__for_each_segment(__first, __last, _CopySegment<_InIter, _OutIter>(__result)); @@ -192,7 +192,7 @@ struct __copy_impl { template <class _InIter, class _OutIter, __enable_if_t<__has_random_access_iterator_category<_InIter>::value && - !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value, + !__is_segmented_iterator_v<_InIter> && __is_segmented_iterator_v<_OutIter>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> operator()(_InIter __first, _InIter __last, _OutIter __result) const { diff --git a/libcxx/include/__algorithm/copy_backward.h b/libcxx/include/__algorithm/copy_backward.h index 9f89064..807c64b 100644 --- a/libcxx/include/__algorithm/copy_backward.h +++ b/libcxx/include/__algorithm/copy_backward.h @@ -170,7 +170,7 @@ struct __copy_backward_impl { return std::make_pair(std::move(__original_last_iter), std::move(__result)); } - template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator<_InIter>::value, int> = 0> + template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator_v<_InIter>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> operator()(_InIter __first, _InIter __last, _OutIter __result) const { using _Traits = __segmented_iterator_traits<_InIter>; @@ -200,7 +200,7 @@ struct __copy_backward_impl { template <class _InIter, class _OutIter, __enable_if_t<__has_random_access_iterator_category<_InIter>::value && - !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value, + !__is_segmented_iterator_v<_InIter> && __is_segmented_iterator_v<_OutIter>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> operator()(_InIter __first, _InIter __last, _OutIter __result) const { diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h index a7d9374..8c8cb58 100644 --- a/libcxx/include/__algorithm/find.h +++ b/libcxx/include/__algorithm/find.h @@ -149,7 +149,7 @@ struct __find_segment; template <class _SegmentedIterator, class _Tp, class _Proj, - __enable_if_t<__is_segmented_iterator<_SegmentedIterator>::value, int> = 0> + __enable_if_t<__is_segmented_iterator_v<_SegmentedIterator>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _SegmentedIterator __find(_SegmentedIterator __first, _SegmentedIterator __last, const _Tp& __value, _Proj& __proj) { return std::__find_segment_if(std::move(__first), std::move(__last), __find_segment<_Tp>(__value), __proj); diff --git a/libcxx/include/__algorithm/for_each.h b/libcxx/include/__algorithm/for_each.h index 4167eec..e31fcae 100644 --- a/libcxx/include/__algorithm/for_each.h +++ b/libcxx/include/__algorithm/for_each.h @@ -39,7 +39,7 @@ __for_each(_InputIterator __first, _Sent __last, _Func& __f, _Proj& __proj) { template <class _SegmentedIterator, class _Func, class _Proj, - __enable_if_t<__is_segmented_iterator<_SegmentedIterator>::value, int> = 0> + __enable_if_t<__is_segmented_iterator_v<_SegmentedIterator>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _SegmentedIterator __for_each(_SegmentedIterator __first, _SegmentedIterator __last, _Func& __func, _Proj& __proj) { using __local_iterator_t = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator; diff --git a/libcxx/include/__algorithm/for_each_n.h b/libcxx/include/__algorithm/for_each_n.h index 9a6c6bb..04650e1 100644 --- a/libcxx/include/__algorithm/for_each_n.h +++ b/libcxx/include/__algorithm/for_each_n.h @@ -37,8 +37,8 @@ template <class _InputIterator, class _Func, class _Proj, __enable_if_t<!__has_random_access_iterator_category<_InputIterator>::value && - _Or< _Not<__is_segmented_iterator<_InputIterator> >, - _Not<__has_random_access_local_iterator<_InputIterator> > >::value, + _Or<integral_constant<bool, !__is_segmented_iterator_v<_InputIterator> >, + _Not<__has_random_access_local_iterator<_InputIterator> > >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator __for_each_n(_InputIterator __first, _Size __orig_n, _Func& __f, _Proj& __proj) { @@ -71,7 +71,7 @@ template <class _SegmentedIterator, class _Func, class _Proj, __enable_if_t<!__has_random_access_iterator_category<_SegmentedIterator>::value && - __is_segmented_iterator<_SegmentedIterator>::value && + __is_segmented_iterator_v<_SegmentedIterator> && __has_random_access_iterator_category< typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator>::value, int> = 0> diff --git a/libcxx/include/__algorithm/for_each_n_segment.h b/libcxx/include/__algorithm/for_each_n_segment.h index 1b522fb..a433df5 100644 --- a/libcxx/include/__algorithm/for_each_n_segment.h +++ b/libcxx/include/__algorithm/for_each_n_segment.h @@ -27,7 +27,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _SegmentedIterator, class _Size, class _Functor> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _SegmentedIterator __for_each_n_segment(_SegmentedIterator __first, _Size __orig_n, _Functor __func) { - static_assert(__is_segmented_iterator<_SegmentedIterator>::value && + static_assert(__is_segmented_iterator_v<_SegmentedIterator> && __has_random_access_iterator_category< typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator>::value, "__for_each_n_segment only works with segmented iterators with random-access local iterators"); diff --git a/libcxx/include/__algorithm/move.h b/libcxx/include/__algorithm/move.h index a3320e9..73b780d 100644 --- a/libcxx/include/__algorithm/move.h +++ b/libcxx/include/__algorithm/move.h @@ -65,7 +65,7 @@ struct __move_impl { } }; - template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator<_InIter>::value, int> = 0> + template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator_v<_InIter>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> operator()(_InIter __first, _InIter __last, _OutIter __result) const { std::__for_each_segment(__first, __last, _MoveSegment<_InIter, _OutIter>(__result)); @@ -75,7 +75,7 @@ struct __move_impl { template <class _InIter, class _OutIter, __enable_if_t<__has_random_access_iterator_category<_InIter>::value && - !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value, + !__is_segmented_iterator_v<_InIter> && __is_segmented_iterator_v<_OutIter>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> operator()(_InIter __first, _InIter __last, _OutIter __result) const { diff --git a/libcxx/include/__algorithm/move_backward.h b/libcxx/include/__algorithm/move_backward.h index 14482fe..e3e61c7b 100644 --- a/libcxx/include/__algorithm/move_backward.h +++ b/libcxx/include/__algorithm/move_backward.h @@ -51,7 +51,7 @@ struct __move_backward_impl { return std::make_pair(std::move(__original_last_iter), std::move(__result)); } - template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator<_InIter>::value, int> = 0> + template <class _InIter, class _OutIter, __enable_if_t<__is_segmented_iterator_v<_InIter>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> operator()(_InIter __first, _InIter __last, _OutIter __result) const { using _Traits = __segmented_iterator_traits<_InIter>; @@ -81,7 +81,7 @@ struct __move_backward_impl { template <class _InIter, class _OutIter, __enable_if_t<__has_random_access_iterator_category<_InIter>::value && - !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value, + !__is_segmented_iterator_v<_InIter> && __is_segmented_iterator_v<_OutIter>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> operator()(_InIter __first, _InIter __last, _OutIter __result) const { diff --git a/libcxx/include/__config b/libcxx/include/__config index 3fe377a..549aa06 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -38,6 +38,30 @@ # define _LIBCPP_FREESTANDING # endif +// NOLINTNEXTLINE(libcpp-cpp-version-check) +# if __cplusplus < 201103L +# define _LIBCPP_CXX03_LANG +# endif + +# if __has_feature(experimental_library) +# ifndef _LIBCPP_ENABLE_EXPERIMENTAL +# define _LIBCPP_ENABLE_EXPERIMENTAL +# endif +# endif + +// Incomplete features get their own specific disabling flags. This makes it +// easier to grep for target specific flags once the feature is complete. +# if defined(_LIBCPP_ENABLE_EXPERIMENTAL) || defined(_LIBCPP_BUILDING_LIBRARY) +# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 1 +# else +# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 0 +# endif + +# define _LIBCPP_HAS_EXPERIMENTAL_PSTL _LIBCPP_HAS_EXPERIMENTAL_LIBRARY +# define _LIBCPP_HAS_EXPERIMENTAL_TZDB _LIBCPP_HAS_EXPERIMENTAL_LIBRARY +# define _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM _LIBCPP_HAS_EXPERIMENTAL_LIBRARY +# define _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC _LIBCPP_HAS_EXPERIMENTAL_LIBRARY + // HARDENING { // TODO: Remove in LLVM 21. We're making this an error to catch folks who might not have migrated. @@ -147,16 +171,53 @@ _LIBCPP_HARDENING_MODE_EXTENSIVE, \ _LIBCPP_HARDENING_MODE_DEBUG # endif +// Hardening assertion semantics generally mirror the evaluation semantics of C++26 Contracts: +// - `ignore` evaluates the assertion but doesn't do anything if it fails (note that it differs from the Contracts +// `ignore` semantic which wouldn't evaluate the assertion at all); +// - `observe` logs an error (indicating, if possible, that the error is fatal) and continues execution; +// - `quick-enforce` terminates the program as fast as possible (via trapping); +// - `enforce` logs an error and then terminates the program. +// +// Notes: +// - Continuing execution after a hardening check fails results in undefined behavior; the `observe` semantic is meant +// to make adopting hardening easier but should not be used outside of this scenario; +// - C++26 wording for Library Hardening precludes a conforming Hardened implementation from using the Contracts +// `ignore` semantic when evaluating hardened preconditions in the Library. Libc++ allows using this semantic for +// hardened preconditions, however, be aware that using `ignore` does not produce a conforming "Hardened" +// implementation, unlike the other semantics above. +// clang-format off +# define _LIBCPP_ASSERTION_SEMANTIC_IGNORE (1 << 1) +# define _LIBCPP_ASSERTION_SEMANTIC_OBSERVE (1 << 2) +# define _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE (1 << 3) +# define _LIBCPP_ASSERTION_SEMANTIC_ENFORCE (1 << 4) +// clang-format on + +// Allow users to define an arbitrary assertion semantic; otherwise, use the default mapping from modes to semantics. +// The default is for production-capable modes to use `quick-enforce` (i.e., trap) and for the `debug` mode to use +// `enforce` (i.e., log and abort). +# ifndef _LIBCPP_ASSERTION_SEMANTIC + +# if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG +# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_ENFORCE +# else +# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE +# endif + +# else +# if !_LIBCPP_HAS_EXPERIMENTAL_LIBRARY +# error "Assertion semantics are an experimental feature." +# endif +# if defined(_LIBCPP_CXX03_LANG) +# error "Assertion semantics are not available in the C++03 mode." +# endif + +# endif // _LIBCPP_ASSERTION_SEMANTIC + // } HARDENING # define _LIBCPP_TOSTRING2(x) #x # define _LIBCPP_TOSTRING(x) _LIBCPP_TOSTRING2(x) -// NOLINTNEXTLINE(libcpp-cpp-version-check) -# if __cplusplus < 201103L -# define _LIBCPP_CXX03_LANG -# endif - # ifndef __has_constexpr_builtin # define __has_constexpr_builtin(x) 0 # endif @@ -190,25 +251,6 @@ _LIBCPP_HARDENING_MODE_DEBUG # define _LIBCPP_ABI_VCRUNTIME # endif -# if __has_feature(experimental_library) -# ifndef _LIBCPP_ENABLE_EXPERIMENTAL -# define _LIBCPP_ENABLE_EXPERIMENTAL -# endif -# endif - -// Incomplete features get their own specific disabling flags. This makes it -// easier to grep for target specific flags once the feature is complete. -# if defined(_LIBCPP_ENABLE_EXPERIMENTAL) || defined(_LIBCPP_BUILDING_LIBRARY) -# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 1 -# else -# define _LIBCPP_HAS_EXPERIMENTAL_LIBRARY 0 -# endif - -# define _LIBCPP_HAS_EXPERIMENTAL_PSTL _LIBCPP_HAS_EXPERIMENTAL_LIBRARY -# define _LIBCPP_HAS_EXPERIMENTAL_TZDB _LIBCPP_HAS_EXPERIMENTAL_LIBRARY -# define _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM _LIBCPP_HAS_EXPERIMENTAL_LIBRARY -# define _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC _LIBCPP_HAS_EXPERIMENTAL_LIBRARY - # if defined(__MVS__) # include <features.h> // for __NATIVE_ASCII_F # endif diff --git a/libcxx/include/__cxx03/__config b/libcxx/include/__cxx03/__config index ef47327..9b88a49 100644 --- a/libcxx/include/__cxx03/__config +++ b/libcxx/include/__cxx03/__config @@ -152,6 +152,10 @@ _LIBCPP_HARDENING_MODE_EXTENSIVE, \ _LIBCPP_HARDENING_MODE_DEBUG # endif +# ifdef _LIBCPP_ASSERTION_SEMANTIC +# error "Assertion semantics are not available in the C++03 mode." +# endif + // } HARDENING # define _LIBCPP_TOSTRING2(x) #x diff --git a/libcxx/include/__format/concepts.h b/libcxx/include/__format/concepts.h index 28297c6..5b60370 100644 --- a/libcxx/include/__format/concepts.h +++ b/libcxx/include/__format/concepts.h @@ -15,12 +15,8 @@ #include <__config> #include <__format/format_parse_context.h> #include <__fwd/format.h> -#include <__fwd/tuple.h> -#include <__tuple/tuple_size.h> -#include <__type_traits/is_specialization.h> #include <__type_traits/remove_const.h> #include <__type_traits/remove_reference.h> -#include <__utility/pair.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -65,16 +61,6 @@ concept __formattable = # if _LIBCPP_STD_VER >= 23 template <class _Tp, class _CharT> concept formattable = __formattable<_Tp, _CharT>; - -// [tuple.like] defines a tuple-like exposition only concept. This concept is -// not related to that. Therefore it uses a different name for the concept. -// -// TODO FMT Add a test to validate we fail when using that concept after P2165 -// has been implemented. -template <class _Tp> -concept __fmt_pair_like = - __is_specialization_v<_Tp, pair> || (__is_specialization_v<_Tp, tuple> && tuple_size_v<_Tp> == 2); - # endif // _LIBCPP_STD_VER >= 23 #endif // _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__format/fmt_pair_like.h b/libcxx/include/__format/fmt_pair_like.h new file mode 100644 index 0000000..d2f2f54 --- /dev/null +++ b/libcxx/include/__format/fmt_pair_like.h @@ -0,0 +1,42 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FMT_PAIR_LIKE_H +#define _LIBCPP___FORMAT_FMT_PAIR_LIKE_H + +#include <__config> +#include <__fwd/pair.h> +#include <__fwd/tuple.h> +#include <__tuple/tuple_size.h> +#include <__type_traits/is_specialization.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +// [tuple.like] defines a tuple-like exposition only concept. This concept is not related to that. Therefore it uses a +// different name for the concept. +// +// TODO FMT Add a test to validate we fail when using that concept after P2165 has been implemented. + +// [format.range.fmtkind]/2.2.1 and [tab:formatter.range.type]: +// "U is either a specialization of pair or a specialization of tuple such that tuple_size_v<U> is 2." +template <class _Tp> +concept __fmt_pair_like = + __is_specialization_v<_Tp, pair> || (__is_specialization_v<_Tp, tuple> && tuple_size_v<_Tp> == 2); + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FMT_PAIR_LIKE_H diff --git a/libcxx/include/__format/range_default_formatter.h b/libcxx/include/__format/range_default_formatter.h index 2769647..2d21906 100644 --- a/libcxx/include/__format/range_default_formatter.h +++ b/libcxx/include/__format/range_default_formatter.h @@ -18,6 +18,7 @@ #include <__chrono/statically_widen.h> #include <__config> #include <__format/concepts.h> +#include <__format/fmt_pair_like.h> #include <__format/formatter.h> #include <__format/range_format.h> #include <__format/range_formatter.h> diff --git a/libcxx/include/__format/range_format.h b/libcxx/include/__format/range_format.h index 139cfd9..fe43923 100644 --- a/libcxx/include/__format/range_format.h +++ b/libcxx/include/__format/range_format.h @@ -16,7 +16,7 @@ #include <__concepts/same_as.h> #include <__config> -#include <__format/concepts.h> +#include <__format/fmt_pair_like.h> #include <__ranges/concepts.h> #include <__type_traits/remove_cvref.h> diff --git a/libcxx/include/__format/range_formatter.h b/libcxx/include/__format/range_formatter.h index 0d7fe99..06d2b4c 100644 --- a/libcxx/include/__format/range_formatter.h +++ b/libcxx/include/__format/range_formatter.h @@ -20,6 +20,7 @@ #include <__config> #include <__format/buffer.h> #include <__format/concepts.h> +#include <__format/fmt_pair_like.h> #include <__format/format_context.h> #include <__format/format_error.h> #include <__format/formatter.h> diff --git a/libcxx/include/__iterator/segmented_iterator.h b/libcxx/include/__iterator/segmented_iterator.h index af27a7b..5df9737 100644 --- a/libcxx/include/__iterator/segmented_iterator.h +++ b/libcxx/include/__iterator/segmented_iterator.h @@ -67,13 +67,13 @@ struct __segmented_iterator_traits; */ template <class _Tp, size_t = 0> -struct __has_specialization : false_type {}; +inline const bool __has_specialization_v = false; template <class _Tp> -struct __has_specialization<_Tp, sizeof(_Tp) * 0> : true_type {}; +inline const bool __has_specialization_v<_Tp, sizeof(_Tp) * 0> = true; template <class _Iterator> -using __is_segmented_iterator _LIBCPP_NODEBUG = __has_specialization<__segmented_iterator_traits<_Iterator> >; +inline const bool __is_segmented_iterator_v = __has_specialization_v<__segmented_iterator_traits<_Iterator> >; template <class _SegmentedIterator> struct __has_random_access_local_iterator diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h index 4e0d76f..4307e78 100644 --- a/libcxx/include/__vector/vector.h +++ b/libcxx/include/__vector/vector.h @@ -341,59 +341,67 @@ public: } #endif - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return this->__alloc_; } // // Iterators // - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __make_iter(__add_alignment_assumption(this->__begin_)); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __make_iter(__add_alignment_assumption(this->__begin_)); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __make_iter(__add_alignment_assumption(this->__end_)); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __make_iter(__add_alignment_assumption(this->__end_)); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT { return reverse_iterator(end()); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator + rbegin() const _NOEXCEPT { return const_reverse_iterator(end()); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() _NOEXCEPT { return reverse_iterator(begin()); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT { return const_reverse_iterator(begin()); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { + return begin(); + } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { + return end(); + } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator + crbegin() const _NOEXCEPT { return rbegin(); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return rend(); } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { + return rend(); + } // // [vector.capacity], capacity // - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return static_cast<size_type>(this->__end_ - this->__begin_); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT { return static_cast<size_type>(this->__cap_ - this->__begin_); } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return this->__begin_ == this->__end_; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return std::min<size_type>(__alloc_traits::max_size(this->__alloc_), numeric_limits<difference_type>::max()); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void reserve(size_type __n); @@ -402,38 +410,39 @@ public: // // element access // - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference operator[](size_type __n) _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference operator[](size_type __n) _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds"); return this->__begin_[__n]; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __n) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference + operator[](size_type __n) const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds"); return this->__begin_[__n]; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference at(size_type __n) { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference at(size_type __n) { if (__n >= size()) this->__throw_out_of_range(); return this->__begin_[__n]; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference at(size_type __n) const { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference at(size_type __n) const { if (__n >= size()) this->__throw_out_of_range(); return this->__begin_[__n]; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector"); return *this->__begin_; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector"); return *this->__begin_; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector"); return *(this->__end_ - 1); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector"); return *(this->__end_ - 1); } @@ -441,11 +450,11 @@ public: // // [vector.data], data access // - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI value_type* data() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI value_type* data() _NOEXCEPT { return std::__to_address(this->__begin_); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const value_type* data() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const value_type* data() const _NOEXCEPT { return std::__to_address(this->__begin_); } diff --git a/libcxx/include/__vector/vector_bool.h b/libcxx/include/__vector/vector_bool.h index e921e65..bd7b28e 100644 --- a/libcxx/include/__vector/vector_bool.h +++ b/libcxx/include/__vector/vector_bool.h @@ -234,74 +234,89 @@ public: } #endif - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 allocator_type get_allocator() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 allocator_type get_allocator() const _NOEXCEPT { return allocator_type(this->__alloc_); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type max_size() const _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type capacity() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type max_size() const _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type capacity() const _NOEXCEPT { return __internal_cap_to_external(__cap_); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type size() const _NOEXCEPT { return __size_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type size() const _NOEXCEPT { + return __size_; + } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool empty() const _NOEXCEPT { return __size_ == 0; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reserve(size_type __n); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void shrink_to_fit() _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator begin() _NOEXCEPT { return __make_iter(0); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator begin() const _NOEXCEPT { return __make_iter(0); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator end() _NOEXCEPT { return __make_iter(__size_); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator end() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator begin() _NOEXCEPT { + return __make_iter(0); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator begin() const _NOEXCEPT { + return __make_iter(0); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator end() _NOEXCEPT { + return __make_iter(__size_); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator end() const _NOEXCEPT { return __make_iter(__size_); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reverse_iterator rbegin() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reverse_iterator rbegin() _NOEXCEPT { return reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator rbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator + rbegin() const _NOEXCEPT { return const_reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reverse_iterator rend() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reverse_iterator rend() _NOEXCEPT { return reverse_iterator(begin()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator rend() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator rend() const _NOEXCEPT { return const_reverse_iterator(begin()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator cbegin() const _NOEXCEPT { return __make_iter(0); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator cend() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator cbegin() const _NOEXCEPT { + return __make_iter(0); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator cend() const _NOEXCEPT { return __make_iter(__size_); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator crbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator + crbegin() const _NOEXCEPT { return rbegin(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator crend() const _NOEXCEPT { return rend(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator crend() const _NOEXCEPT { + return rend(); + } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator[](size_type __n) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator[](size_type __n) { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector<bool>::operator[] index out of bounds"); return __make_ref(__n); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference operator[](size_type __n) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference + operator[](size_type __n) const { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector<bool>::operator[] index out of bounds"); return __make_ref(__n); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference at(size_type __n); - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference at(size_type __n) const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference at(size_type __n); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference at(size_type __n) const; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference front() { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference front() { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "vector<bool>::front() called on an empty vector"); return __make_ref(0); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference front() const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference front() const { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "vector<bool>::front() called on an empty vector"); return __make_ref(0); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference back() { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference back() { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "vector<bool>::back() called on an empty vector"); return __make_ref(__size_ - 1); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference back() const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference back() const { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "vector<bool>::back() called on an empty vector"); return __make_ref(__size_ - 1); } diff --git a/libcxx/include/deque b/libcxx/include/deque index e33e7d3..395a107 100644 --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -461,9 +461,8 @@ private: __deque_iterator<_ValueType, _Pointer, _Reference, _MapPointer, _DiffType, _BlockSize>; public: - using __is_segmented_iterator _LIBCPP_NODEBUG = true_type; - using __segment_iterator _LIBCPP_NODEBUG = _MapPointer; - using __local_iterator _LIBCPP_NODEBUG = _Pointer; + using __segment_iterator _LIBCPP_NODEBUG = _MapPointer; + using __local_iterator _LIBCPP_NODEBUG = _Pointer; static _LIBCPP_HIDE_FROM_ABI __segment_iterator __segment(_Iterator __iter) { return __iter.__m_iter_; } static _LIBCPP_HIDE_FROM_ABI __local_iterator __local(_Iterator __iter) { return __iter.__ptr_; } diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 117556e..5857a83 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1338,6 +1338,7 @@ module std [system] { module enable_insertable { header "__format/enable_insertable.h" } module escaped_output_table { header "__format/escaped_output_table.h" } module extended_grapheme_cluster_table { header "__format/extended_grapheme_cluster_table.h" } + module fmt_pair_like { header "__format/fmt_pair_like.h" } module format_arg { header "__format/format_arg.h" } module format_arg_store { header "__format/format_arg_store.h" } module format_args { header "__format/format_args.h" } diff --git a/libcxx/test/libcxx/containers/sequences/deque/segmented_iterator.compile.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/segmented_iterator.compile.pass.cpp index 7ae67d8..b050da4 100644 --- a/libcxx/test/libcxx/containers/sequences/deque/segmented_iterator.compile.pass.cpp +++ b/libcxx/test/libcxx/containers/sequences/deque/segmented_iterator.compile.pass.cpp @@ -6,7 +6,9 @@ // //===----------------------------------------------------------------------===// +// XFAIL: FROZEN-CXX03-HEADERS-FIXME + #include <deque> using DequeIterator = typename std::deque<int>::iterator; -static_assert(std::__is_segmented_iterator<DequeIterator>::value, ""); +static_assert(std::__is_segmented_iterator_v<DequeIterator>, ""); diff --git a/libcxx/test/libcxx/diagnostics/vector.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/vector.nodiscard.verify.cpp index 51e90af..a5cad1a 100644 --- a/libcxx/test/libcxx/diagnostics/vector.nodiscard.verify.cpp +++ b/libcxx/test/libcxx/diagnostics/vector.nodiscard.verify.cpp @@ -10,14 +10,45 @@ // check that <vector> functions are marked [[nodiscard]] +#include <type_traits> #include <vector> -void test_vector() { - std::vector<int> vector; - vector.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +template <class VecT> +void test() { + VecT v; + + v.at(0); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.back(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.begin(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.capacity(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.cbegin(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.cend(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.crbegin(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.crend(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.empty(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.end(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.front(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.get_allocator(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.max_size(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.rbegin(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.rend(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v.size(); // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} + v[0]; // expected-warning 4 {{ignoring return value of function declared with 'nodiscard' attribute}} } -void test_vector_bool() { - std::vector<bool> vector; - vector.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +template <class VecT> +void test_non_vector_bool() { + VecT v; + + v.data(); // expected-warning 2 {{ignoring return value of function declared with 'nodiscard' attribute}} +} + +void instantiate() { + test<std::vector<int>>(); + test<const std::vector<int>>(); + test<std::vector<bool>>(); + test<const std::vector<bool>>(); + + test_non_vector_bool<std::vector<int>>(); + test_non_vector_bool<const std::vector<int>>(); } diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp index 6cd17c2..4e4074f 100644 --- a/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp @@ -14,4 +14,4 @@ using JoinView = decltype(std::views::join(std::declval<std::vector<std::vector<int>>&>())); using JoinIter = std::ranges::iterator_t<JoinView>; -static_assert(std::__is_segmented_iterator<JoinIter>::value); +static_assert(std::__is_segmented_iterator_v<JoinIter>); diff --git a/libcxx/test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp b/libcxx/test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp index 419a603..2bc4648 100644 --- a/libcxx/test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp +++ b/libcxx/test/libcxx/thread/thread.barrier/assert.arrive.pass.cpp @@ -8,6 +8,8 @@ // UNSUPPORTED: no-threads // UNSUPPORTED: c++03, c++11, c++14, c++17 // REQUIRES: libcpp-hardening-mode={{extensive|debug}} +// Without the assertion, the test will most likely time out. +// UNSUPPORTED: libcpp-assertion-semantic={{ignore|observe}} // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing diff --git a/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp b/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp index e6167955..30d36b5f 100644 --- a/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp +++ b/libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp @@ -18,6 +18,8 @@ // REQUIRES: has-unix-headers // REQUIRES: libcpp-hardening-mode={{extensive|debug}} +// Without the assertion, the test will most likely time out. +// UNSUPPORTED: libcpp-assertion-semantic={{ignore|observe}} // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing #include <latch> diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp index fbd2317..c46ab63 100644 --- a/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp +++ b/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp @@ -55,7 +55,6 @@ void test() { // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must be a specialization of std::expected}} // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}} // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}} - // expected-error@*:* 0-1{{excess elements in struct initializer}} } // !std::is_same_v<U:error_type, E> @@ -75,7 +74,6 @@ void test() { // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must be a specialization of std::expected}} // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}} // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}} - // expected-error@*:* 0-1{{excess elements in struct initializer}} } // !std::is_same_v<U:error_type, E> @@ -96,7 +94,6 @@ void test() { // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}} // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}} // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}} - // expected-error@*:* 0-1{{excess elements in struct initializer}} } // !std::is_same_v<U:error_type, E> @@ -116,7 +113,6 @@ void test() { // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}} // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}} // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}} - // expected-error@*:* 0-1{{excess elements in struct initializer}} } // !std::is_same_v<U:error_type, E> diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp index 553ac4c..af1fa53 100644 --- a/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp +++ b/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp @@ -55,7 +55,6 @@ void test() { // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(error()) must be a specialization of std::expected}} // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}} // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}} - // expected-error@*:* 0-1{{excess elements in struct initializer}} } // !std::is_same_v<G:value_type, T> @@ -75,7 +74,6 @@ void test() { // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(error()) must be a specialization of std::expected}} // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}} // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}} - // expected-error@*:* 0-1{{excess elements in struct initializer}} } // !std::is_same_v<G:value_type, T> @@ -95,7 +93,6 @@ void test() { // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}} // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}} // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}} - // expected-error@*:* 0-1{{excess elements in struct initializer}} } // !std::is_same_v<G:value_type, T> @@ -115,7 +112,6 @@ void test() { // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}} // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}} // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}} - // expected-error@*:* 0-1{{excess elements in struct initializer}} } // !std::is_same_v<G:value_type, T> diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/value.observers.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/value.observers.verify.cpp index 91a7db1..d2b62a9 100644 --- a/libcxx/test/libcxx/utilities/expected/expected.expected/value.observers.verify.cpp +++ b/libcxx/test/libcxx/utilities/expected/expected.expected/value.observers.verify.cpp @@ -124,8 +124,8 @@ void test() { #if _LIBCPP_HAS_EXCEPTIONS // expected-error-re@*:* {{call to deleted constructor of{{.*}}}} // expected-error-re@*:* {{call to deleted constructor of{{.*}}}} - // expected-error-re@*:* 1-2{{call to deleted constructor of{{.*}}}} - // expected-error-re@*:* 0-2{{call to deleted constructor of{{.*}}}} + // expected-error-re@*:* {{call to deleted constructor of{{.*}}}} + // expected-error-re@*:* {{call to deleted constructor of{{.*}}}} #endif } // clang-format on diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/and_then.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/and_then.mandates.verify.cpp index 1df6cbf..e1a7ec5 100644 --- a/libcxx/test/libcxx/utilities/expected/expected.void/and_then.mandates.verify.cpp +++ b/libcxx/test/libcxx/utilities/expected/expected.void/and_then.mandates.verify.cpp @@ -55,7 +55,6 @@ void test() { // expected-error-re@*:* {{static assertion failed {{.*}}The result of f() must be a specialization of std::expected}} // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}} // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}} - // expected-error@*:* 0-1{{excess elements in struct initializer}} } // !std::is_same_v<U:error_type, E> @@ -75,7 +74,6 @@ void test() { // expected-error-re@*:* {{static assertion failed {{.*}}The result of f() must be a specialization of std::expected}} // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}} // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}} - // expected-error@*:* 0-1{{excess elements in struct initializer}} } // !std::is_same_v<U:error_type, E> @@ -95,7 +93,6 @@ void test() { // expected-error-re@*:* {{static assertion failed {{.*}}The result of f() must be a specialization of std::expected}} // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}} // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}} - // expected-error@*:* 0-1{{excess elements in struct initializer}} } // !std::is_same_v<U:error_type, E> @@ -115,7 +112,6 @@ void test() { // expected-error-re@*:* {{static assertion failed {{.*}}The result of f() must be a specialization of std::expected}} // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}} // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}} - // expected-error@*:* 0-1{{excess elements in struct initializer}} } // !std::is_same_v<U:error_type, E> diff --git a/libcxx/test/std/containers/sequences/array/array.creation/to_array.verify.cpp b/libcxx/test/std/containers/sequences/array/array.creation/to_array.verify.cpp index e3efef9..9e7b456 100644 --- a/libcxx/test/std/containers/sequences/array/array.creation/to_array.verify.cpp +++ b/libcxx/test/std/containers/sequences/array/array.creation/to_array.verify.cpp @@ -28,14 +28,14 @@ int main(int, char**) { { MoveOnly mo[] = {MoveOnly{3}}; // expected-error@array:* {{to_array requires copy constructible elements}} - // expected-error-re@array:* 1-2{{{{(call to implicitly-deleted copy constructor of 'MoveOnly')|(call to deleted constructor of 'MoveOnly')}}}} + // expected-error-re@array:* {{{{(call to implicitly-deleted copy constructor of 'MoveOnly')|(call to deleted constructor of 'MoveOnly')}}}} std::to_array(mo); // expected-note {{requested here}} } { const MoveOnly cmo[] = {MoveOnly{3}}; // expected-error@array:* {{to_array requires move constructible elements}} - // expected-error-re@array:* 0-1{{{{(call to implicitly-deleted copy constructor of 'MoveOnly')|(call to deleted constructor of 'MoveOnly')}}}} + // expected-error-re@array:* {{{{(call to implicitly-deleted copy constructor of 'MoveOnly')|(call to deleted constructor of 'MoveOnly')}}}} std::to_array(std::move(cmo)); // expected-note {{requested here}} } diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/conversion.verify.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/conversion.verify.cpp index cd4d4d9..d46ba6f 100644 --- a/libcxx/test/std/containers/views/mdspan/mdspan/conversion.verify.cpp +++ b/libcxx/test/std/containers/views/mdspan/mdspan/conversion.verify.cpp @@ -43,7 +43,6 @@ void cant_construct_data_handle_type() { int data; std::mdspan<int, std::extents<int>, std::layout_right, convertible_accessor_but_not_handle<int>> m_nc(&data); // expected-error-re@*:* {{{{.*}}no matching constructor for initialization of {{.*}} (aka 'not_const_convertible_handle<const int>')}} - // expected-error@*:* 0-1{{no matching constructor for initialization of 'not_const_convertible_handle<const int>'}} // expected-error-re@*:* {{static assertion failed {{.*}}mdspan: incompatible data_handle_type for mdspan construction}} [[maybe_unused]] std:: mdspan<const int, std::extents<int>, std::layout_right, convertible_accessor_but_not_handle<const int>> m_c(m_nc); @@ -53,6 +52,5 @@ void mapping_constructible_despite_extents_compatibility() { int data; std::mdspan<int, std::extents<int>, always_convertible_layout> m(&data); // expected-error-re@*:* {{static assertion failed {{.*}}mdspan: incompatible extents for mdspan construction}} - // expected-error@*:* 0-1{{no matching constructor for initialization of 'std::extents<int, 5>'}} [[maybe_unused]] std::mdspan<int, std::extents<int, 5>, always_convertible_layout> m2(m); } diff --git a/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp b/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp index 4e24dbe..678483b 100644 --- a/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp +++ b/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp @@ -15,6 +15,7 @@ #include <concepts> #include <iterator> #include <ranges> +#include <sstream> #include <type_traits> #include <utility> @@ -45,7 +46,10 @@ constexpr bool test(CPO& o, Args&&...) { int a[10]; int arrays[10][10]; -//std::pair<int, int> pairs[10]; +std::pair<int, int> pairs[10]; +#ifndef TEST_HAS_NO_LOCALIZATION +std::istringstream stream; +#endif // [concept.swappable] static_assert(test(std::ranges::swap, a, a)); @@ -81,25 +85,50 @@ static_assert(test(std::ranges::ssize, a)); // views::empty<T> is not a CPO static_assert(test(std::views::iota, 1)); static_assert(test(std::views::iota, 1, 10)); -//static_assert(test(std::views::istream<int>, 1); +#ifndef TEST_HAS_NO_LOCALIZATION +static_assert(test(std::views::istream<int>, stream)); +#endif static_assert(test(std::views::single, 4)); +#if TEST_STD_VER >= 23 +static_assert(test(std::views::repeat, 1)); +#endif + // [range.adaptors] static_assert(test(std::views::all, a)); static_assert(test(std::views::common, a)); static_assert(test(std::views::counted, a, 10)); static_assert(test(std::views::drop, a, 10)); -//static_assert(test(std::views::drop_while, a, [](int x){ return x < 10; })); -//static_assert(test(std::views::elements<0>, pairs)); +static_assert(test(std::views::drop_while, a, [](int x) { return x < 10; })); +static_assert(test(std::views::elements<0>, pairs)); static_assert(test(std::views::filter, a, [](int x) { return x < 10; })); static_assert(test(std::views::join, arrays)); -//static_assert(test(std::views::split, a, 4)); +static_assert(test(std::views::keys, pairs)); static_assert(test(std::views::lazy_split, a, 4)); static_assert(test(std::views::reverse, a)); +static_assert(test(std::views::split, a, 4)); static_assert(test(std::views::take, a, 10)); -//static_assert(test(std::views::take_while, a, [](int x){ return x < 10; })); +static_assert(test(std::views::take_while, a, [](int x) { return x < 10; })); static_assert(test(std::views::transform, a, [](int x) { return x + 1; })); +static_assert(test(std::views::values, pairs)); #if TEST_STD_VER >= 23 +// static_assert(test(std::views::adjacent_transform<2>, [](int x, int y) { return x + y; }, a)); +// static_assert(test(std::views::adjacent<2>, a)); +// static_assert(test(std::views::as_const, a)); +static_assert(test(std::views::as_rvalue, a)); +// static_assert(test(std::views::cartesian_product, a, a, a)); +static_assert(test(std::views::chunk_by, a, [](int x, int y) { return x < y; })); +// static_assert(test(std::views::chunk, a, 1)); +// static_assert(test(std::views::enumerate, a)); +static_assert(test(std::views::join_with, 1)); +// static_assert(test(std::views::stride, a, 1)); static_assert(test(std::views::zip_transform, [](int x, int y) { return x + y; }, a, a)); +static_assert(test(std::views::zip, a, a)); +#endif + +#if TEST_STD_VER >= 26 +// static_assert(test(std::views::cache_latest, a)); +// static_assert(test(std::views::concat, a, a)); +// static_assert(test(std::views::to_input, a)); #endif diff --git a/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp b/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp index 6a63b65..eb100c1 100644 --- a/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp +++ b/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp @@ -69,8 +69,6 @@ void test() { 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}} - // expected-error@*:* 0-1{{call to deleted constructor of 'F'}} - // expected-error@*:* 0-1{{call to deleted constructor of 'Arg'}} } { // Mandates: (is_move_constructible_v<decay_t<Args>> && ...) diff --git a/libcxx/test/std/utilities/function.objects/func.bind_front/bind_front.verify.cpp b/libcxx/test/std/utilities/function.objects/func.bind_front/bind_front.verify.cpp index 27a1fba..5100259 100644 --- a/libcxx/test/std/utilities/function.objects/func.bind_front/bind_front.verify.cpp +++ b/libcxx/test/std/utilities/function.objects/func.bind_front/bind_front.verify.cpp @@ -42,5 +42,4 @@ void f() { auto d = std::bind_front(do_nothing, n); // expected-error {{no matching function for call to 'bind_front'}} auto t = std::bind_front(testNotMoveConst, NotMoveConst(0)); // expected-error {{no matching function for call to 'bind_front'}} - // expected-error@*:* 0-1{{call to deleted constructor of 'NotMoveConst'}} } diff --git a/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h index a279400..a091043 100644 --- a/libcxx/test/support/check_assertion.h +++ b/libcxx/test/support/check_assertion.h @@ -44,15 +44,32 @@ static constexpr const char* Marker = "###"; using MatchResult = std::pair<bool, std::string>; using Matcher = std::function<MatchResult(const std::string& /*text*/)>; -MatchResult MatchAssertionMessage(const std::string& text, std::string_view expected_message) { +// Using the marker makes matching more precise, but we cannot output the marker when the `observe` semantic is used +// (because it doesn't allow customizing the logging function). If the marker is not available, fall back to using less +// precise matching by just the error message. +MatchResult MatchAssertionMessage(const std::string& text, std::string_view expected_message, bool use_marker) { // Extract information from the error message. This has to stay synchronized with how we format assertions in the // library. - std::regex assertion_format(".*###\\n(.*):(\\d+): assertion (.*) failed: (.*)\\n###"); + std::string assertion_format_string = [&] { + if (use_marker) + return (".*###\\n(.*):(\\d+): assertion (.*) failed: (.*)\\n###"); + return ("(.*):(\\d+): assertion (.*) failed: (.*)\\n"); + }(); + std::regex assertion_format(assertion_format_string); std::smatch match_result; - bool has_match = std::regex_match(text, match_result, assertion_format); - assert(has_match); - assert(match_result.size() == 5); + // If a non-terminating assertion semantic is used, more than one assertion might be triggered before the process + // dies, so we cannot expect the entire target string to match. + bool has_match = std::regex_search(text, match_result, assertion_format); + if (!has_match || match_result.size() != 5) { + std::stringstream matching_error; + matching_error // + << "Failed to parse the assertion message.\n" // + << "Using marker: " << use_marker << "\n" // + << "Expected message: '" << expected_message.data() << "'\n" // + << "Stderr contents: '" << text.c_str() << "'\n"; + return MatchResult(/*success=*/false, matching_error.str()); + } const std::string& file = match_result[1]; int line = std::stoi(match_result[2]); @@ -72,9 +89,9 @@ MatchResult MatchAssertionMessage(const std::string& text, std::string_view expe return MatchResult(/*success=*/true, /*maybe_error=*/""); } -Matcher MakeAssertionMessageMatcher(std::string_view assertion_message) { +Matcher MakeAssertionMessageMatcher(std::string_view assertion_message, bool use_marker = true) { return [=](const std::string& text) { // - return MatchAssertionMessage(text, assertion_message); + return MatchAssertionMessage(text, assertion_message, use_marker); }; } @@ -85,13 +102,17 @@ Matcher MakeAnyMatcher() { } enum class DeathCause { - // Valid causes + // Valid causes. VerboseAbort = 1, StdAbort, StdTerminate, Trap, - // Invalid causes + // Causes that might be invalid or might stem from undefined behavior (relevant for non-terminating assertion + // semantics). DidNotDie, + Segfault, + ArithmeticError, + // Always invalid causes. SetupFailure, Unknown }; @@ -108,6 +129,16 @@ bool IsValidCause(DeathCause cause) { } } +bool IsTestSetupErrorCause(DeathCause cause) { + switch (cause) { + case DeathCause::SetupFailure: + case DeathCause::Unknown: + return true; + default: + return false; + } +} + std::string ToString(DeathCause cause) { switch (cause) { case DeathCause::VerboseAbort: @@ -120,10 +151,14 @@ std::string ToString(DeathCause cause) { return "trap"; case DeathCause::DidNotDie: return "<invalid cause (child did not die)>"; + case DeathCause::Segfault: + return "<invalid cause (segmentation fault)>"; + case DeathCause::ArithmeticError: + return "<invalid cause (fatal arithmetic error)>"; case DeathCause::SetupFailure: - return "<invalid cause (child failed to set up test environment)>"; + return "<test setup error (child failed to set up test environment)>"; case DeathCause::Unknown: - return "<invalid cause (cause unknown)>"; + return "<test setup error (test doesn't know how to interpret the death cause)>"; } assert(false && "Unreachable"); @@ -225,9 +260,38 @@ public: return DeathTestResult(Outcome::Success, cause); } - void PrintFailureDetails(std::string_view failure_description, std::string_view stmt, DeathCause cause) const { - std::fprintf( - stderr, "Failure: EXPECT_DEATH( %s ) failed!\n(reason: %s)\n\n", stmt.data(), failure_description.data()); + // When non-terminating assertion semantics are used, the program will invoke UB which might or might not crash the + // process; we make sure that the execution produces the expected error message but otherwise consider the test run + // successful whether the child process dies or not. + template <class Func> + DeathTestResult RunWithoutGuaranteedDeath(Func&& func, const Matcher& matcher) { + std::signal(SIGABRT, [](int) { StopChildProcess(DeathCause::StdAbort); }); + std::set_terminate([] { StopChildProcess(DeathCause::StdTerminate); }); + + DeathCause cause = Run(func); + + if (IsTestSetupErrorCause(cause)) { + return DeathTestResult(Outcome::InvalidCause, cause, ToString(cause)); + } + + MatchResult match_result = matcher(GetChildStdErr()); + if (!match_result.first) { + auto failure_description = std::string("Child produced a different error message\n") + match_result.second; + return DeathTestResult(Outcome::UnexpectedErrorMessage, cause, failure_description); + } + + return DeathTestResult(Outcome::Success, cause); + } + + void PrintFailureDetails(std::string_view invocation, + std::string_view failure_description, + std::string_view stmt, + DeathCause cause) const { + std::fprintf(stderr, + "Failure: %s( %s ) failed!\n(reason: %s)\n\n", + invocation.data(), + stmt.data(), + failure_description.data()); if (cause != DeathCause::Unknown) { std::fprintf(stderr, "child exit code: %d\n", GetChildExitCode()); @@ -311,10 +375,16 @@ private: if (WIFSIGNALED(status_value)) { exit_code_ = WTERMSIG(status_value); - // `__builtin_trap` generqtes `SIGILL` on x86 and `SIGTRAP` on ARM. + // `__builtin_trap` generates `SIGILL` on x86 and `SIGTRAP` on ARM. if (exit_code_ == SIGILL || exit_code_ == SIGTRAP) { return DeathCause::Trap; } + if (exit_code_ == SIGSEGV) { + return DeathCause::Segfault; + } + if (exit_code_ == SIGFPE) { + return DeathCause::ArithmeticError; + } } return DeathCause::Unknown; @@ -357,7 +427,7 @@ bool ExpectDeath( DeathTest test_case; DeathTestResult test_result = test_case.Run(expected_causes, func, matcher); if (!test_result.success()) { - test_case.PrintFailureDetails(test_result.failure_description(), stmt, test_result.cause()); + test_case.PrintFailureDetails("EXPECT_DEATH", test_result.failure_description(), stmt, test_result.cause()); } return test_result.success(); @@ -378,6 +448,22 @@ bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func) { return ExpectDeath(std::array<DeathCause, 1>{expected_cause}, stmt, func, MakeAnyMatcher()); } +template <class Func> +bool ExpectLog(const char* stmt, Func&& func, const Matcher& matcher) { + DeathTest test_case; + DeathTestResult test_result = test_case.RunWithoutGuaranteedDeath(func, matcher); + if (!test_result.success()) { + test_case.PrintFailureDetails("EXPECT_LOG", test_result.failure_description(), stmt, test_result.cause()); + } + + return test_result.success(); +} + +template <class Func> +bool ExpectLog(const char* stmt, Func&& func) { + return ExpectLog(stmt, func, MakeAnyMatcher()); +} + // clang-format off /// Assert that the specified expression aborts with the expected cause and, optionally, error message. @@ -392,13 +478,28 @@ bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func) { #define EXPECT_STD_TERMINATE(...) \ assert( ExpectDeath(DeathCause::StdTerminate, #__VA_ARGS__, __VA_ARGS__) ) -#if defined(_LIBCPP_HARDENING_MODE) && _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG +#if defined(_LIBCPP_ASSERTION_SEMANTIC) + +#if _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE #define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \ assert(( ExpectDeath(DeathCause::VerboseAbort, #expr, [&]() { (void)(expr); }, MakeAssertionMessageMatcher(message)) )) +#elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE +#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \ + assert(( ExpectDeath(DeathCause::Trap, #expr, [&]() { (void)(expr); }) )) +#elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_OBSERVE +#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \ + assert(( ExpectLog(#expr, [&]() { (void)(expr); }, MakeAssertionMessageMatcher(message, /*use_marker=*/false)) )) +#elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_IGNORE +#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \ + assert(( ExpectLog(#expr, [&]() { (void)(expr); }) )) +#else +#error "Unknown value for _LIBCPP_ASSERTION_SEMANTIC" +#endif // _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE + #else #define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \ assert(( ExpectDeath(DeathCause::Trap, #expr, [&]() { (void)(expr); }) )) -#endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG +#endif // defined(_LIBCPP_ASSERTION_SEMANTIC) // clang-format on diff --git a/libcxx/test/support/test.support/test_check_assertion.pass.cpp b/libcxx/test/support/test.support/test_check_assertion.pass.cpp index 4dfc531..78e47b3 100644 --- a/libcxx/test/support/test.support/test_check_assertion.pass.cpp +++ b/libcxx/test/support/test.support/test_check_assertion.pass.cpp @@ -53,7 +53,7 @@ bool TestDeathTest( } if (!maybe_failure_description.empty()) { - test_case.PrintFailureDetails(maybe_failure_description, stmt, test_result.cause()); + test_case.PrintFailureDetails("EXPECT_DEATH", maybe_failure_description, stmt, test_result.cause()); return false; } @@ -76,9 +76,9 @@ DeathCause assertion_death_cause = DeathCause::Trap; #endif int main(int, char**) { - auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message"); }; - Matcher good_matcher = MakeAssertionMessageMatcher("Some message"); - Matcher bad_matcher = MakeAssertionMessageMatcher("Bad expected message"); + [[maybe_unused]] auto fail_assert = [] { _LIBCPP_ASSERT(false, "Some message"); }; + Matcher good_matcher = MakeAssertionMessageMatcher("Some message"); + Matcher bad_matcher = MakeAssertionMessageMatcher("Bad expected message"); // Test the implementation of death tests. We're bypassing the assertions added by the actual `EXPECT_DEATH` macros // which allows us to test failure cases (where the assertion would fail) as well. @@ -89,16 +89,22 @@ int main(int, char**) { // Success -- trapping. TEST_DEATH_TEST(Outcome::Success, DeathCause::Trap, __builtin_trap()); + // `_LIBCPP_ASSERT` does not terminate the program if the `observe` semantic is used, so these tests would fail with + // `DidNotDie` cause. +#if _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_OBSERVE + // Success -- assertion failure with any matcher. TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, MakeAnyMatcher(), fail_assert()); // Success -- assertion failure with a specific matcher. TEST_DEATH_TEST_MATCHES(Outcome::Success, assertion_death_cause, good_matcher, fail_assert()); -#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG +# if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG // Failure -- error message doesn't match. TEST_DEATH_TEST_MATCHES(Outcome::UnexpectedErrorMessage, assertion_death_cause, bad_matcher, fail_assert()); -#endif +# endif + +#endif // _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_OBSERVE // Invalid cause -- child did not die. TEST_DEATH_TEST(Outcome::InvalidCause, DeathCause::DidNotDie, ((void)0)); @@ -125,7 +131,9 @@ int main(int, char**) { EXPECT_DEATH_MATCHES(simple_matcher, invoke_verbose_abort()); EXPECT_STD_ABORT(invoke_abort()); EXPECT_STD_TERMINATE([] { std::terminate(); }); +#if _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_OBSERVE TEST_LIBCPP_ASSERT_FAILURE(fail_assert(), "Some message"); +#endif } return 0; diff --git a/libcxx/utils/ci/Dockerfile b/libcxx/utils/ci/Dockerfile index 63cecea..79e1156 100644 --- a/libcxx/utils/ci/Dockerfile +++ b/libcxx/utils/ci/Dockerfile @@ -38,6 +38,7 @@ # If you're only looking to run the Docker image locally for debugging a # build bot, see the `run-buildbot-container` script located in this directory. +ARG ACTIONS_BASE_IMAGE # HACK: We set the base image in the docker-compose file depending on the final target (buildkite vs github actions). # This means we have a much slower container build, but we can use the same Dockerfile for both targets. @@ -309,7 +310,20 @@ CMD /opt/android/container-setup.sh && buildkite-agent start # # IMAGE: ghcr.io/libcxx/actions-builder. # -FROM builder-base AS actions-builder - -WORKDIR /home/runner -USER runner +FROM $ACTIONS_BASE_IMAGE AS actions-builder + +ARG GITHUB_RUNNER_VERSION + +RUN useradd gha -u 1001 -m -s /bin/bash +RUN adduser gha sudo +RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers +WORKDIR /home/gha +USER gha + +ENV RUNNER_MANUALLY_TRAP_SIG=1 +ENV ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1 +RUN mkdir actions-runner && \ + cd actions-runner && \ + curl -O -L https://github.com/actions/runner/releases/download/v$GITHUB_RUNNER_VERSION/actions-runner-linux-x64-$GITHUB_RUNNER_VERSION.tar.gz && \ + tar xzf ./actions-runner-linux-x64-$GITHUB_RUNNER_VERSION.tar.gz && \ + rm ./actions-runner-linux-x64-$GITHUB_RUNNER_VERSION.tar.gz diff --git a/libcxx/utils/ci/docker-compose.yml b/libcxx/utils/ci/docker-compose.yml index 4efc6d2..36b8dd7 100644 --- a/libcxx/utils/ci/docker-compose.yml +++ b/libcxx/utils/ci/docker-compose.yml @@ -3,6 +3,16 @@ x-versions: &compiler_versions LLVM_HEAD_VERSION: 21 services: + builder-base: + image: ghcr.io/llvm/libcxx-linux-builder-base:${TAG} + build: + context: . + dockerfile: Dockerfile + target: builder-base + args: + BASE_IMAGE: ubuntu:jammy + <<: *compiler_versions + actions-builder: image: ghcr.io/llvm/libcxx-linux-builder:${TAG} build: @@ -10,7 +20,9 @@ services: dockerfile: Dockerfile target: actions-builder args: - BASE_IMAGE: ghcr.io/actions/actions-runner:2.326.0 + BASE_IMAGE: ubuntu:jammy + ACTIONS_BASE_IMAGE: builder-base + GITHUB_RUNNER_VERSION: "2.326.0" <<: *compiler_versions android-buildkite-builder: diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot index d8b23be..57ecf1e 100755 --- a/libcxx/utils/ci/run-buildbot +++ b/libcxx/utils/ci/run-buildbot @@ -442,6 +442,12 @@ generic-hardening-mode-extensive) check-runtimes check-abi-list ;; +generic-hardening-mode-extensive-observe-semantic) + clean + generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-hardening-mode-extensive-observe-semantic.cmake" + check-runtimes + check-abi-list +;; generic-hardening-mode-debug) clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-hardening-mode-debug.cmake" diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py index 93cf29b..81c6134 100644 --- a/libcxx/utils/libcxx/test/params.py +++ b/libcxx/utils/libcxx/test/params.py @@ -455,5 +455,24 @@ DEFAULT_PARAMETERS = [ help="Whether to test the main or C++03-specific headers. Only changes behaviour when std=c++03.", actions=lambda enabled: [] if not enabled else [AddFlag("-D_LIBCPP_USE_FROZEN_CXX03_HEADERS"), AddFeature("FROZEN-CXX03-HEADERS-FIXME")], ), + Parameter( + name='assertion_semantic', + choices=["ignore", "observe", "quick_enforce", "enforce", "undefined"], + type=str, + default="undefined", + help="Whether to override the assertion semantic used by hardening. This is only meaningful when running the " + "tests against libc++ with hardening enabled. By default, no assertion semantic is specified explicitly, so " + "the default one will be used (depending on the hardening mode).", + actions=lambda assertion_semantic: filter( + None, + [ + AddCompileFlag("-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE") if assertion_semantic == "ignore" else None, + AddCompileFlag("-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_OBSERVE") if assertion_semantic == "observe" else None, + AddCompileFlag("-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE") if assertion_semantic == "quick_enforce" else None, + AddCompileFlag("-D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE") if assertion_semantic == "enforce" else None, + AddFeature("libcpp-assertion-semantic={}".format(assertion_semantic)) if assertion_semantic != "undefined" else None, + ], + ), + ), ] # fmt: on diff --git a/libcxx/vendor/llvm/default_assertion_handler.in b/libcxx/vendor/llvm/default_assertion_handler.in index f115658..d352405 100644 --- a/libcxx/vendor/llvm/default_assertion_handler.in +++ b/libcxx/vendor/llvm/default_assertion_handler.in @@ -16,6 +16,7 @@ # include <__cxx03/__verbose_trap> #else # include <__config> +# include <__log_hardening_failure> # include <__verbose_abort> # include <__verbose_trap> #endif @@ -24,14 +25,40 @@ # pragma GCC system_header #endif -#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG +#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) -# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_ABORT("%s", message) +// Keep the old implementation that doesn't support assertion semantics for backward compatibility with the frozen C++03 +// mode. +# if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG +# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_ABORT("%s", message) +# else +# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_TRAP(message) +# endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG #else -# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_TRAP(message) +# if _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_IGNORE +# define _LIBCPP_ASSERTION_HANDLER(message) ((void)0) + +# elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_OBSERVE +# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_LOG_HARDENING_FAILURE(message) + +# elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE +# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_TRAP(message) + +# elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE +# define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_ABORT("%s", message) + +# else + +# error _LIBCPP_ASSERTION_SEMANTIC must be set to one of the following values: \ +_LIBCPP_ASSERTION_SEMANTIC_IGNORE, \ +_LIBCPP_ASSERTION_SEMANTIC_OBSERVE, \ +_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE, \ +_LIBCPP_ASSERTION_SEMANTIC_ENFORCE + +# endif // _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_IGNORE -#endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG +#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) #endif // _LIBCPP___ASSERTION_HANDLER |