[llvm-branch-commits] [libcxx] [libc++][docs] Convert documentation from reST to Markdown (batch 1) (PR #221513)
Reid Kleckner via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Sep 27 08:13:20 PDT 2026
https://github.com/rnk updated https://github.com/llvm/llvm-project/pull/221513
>From 155cedeb00265b0f3f7c8b4dc403daeac817fecb Mon Sep 17 00:00:00 2001
From: Reid Kleckner <rkleckner at nvidia.com>
Date: Sat, 5 Sep 2026 04:09:00 +0000
Subject: [PATCH 1/3] [libc++][docs] Convert documentation with rst2myst
---
libcxx/docs/ABIGuarantees.md | 221 ++-
libcxx/docs/AddingNewCIJobs.md | 61 +-
libcxx/docs/CodingGuidelines.md | 223 ++-
libcxx/docs/Contributing.md | 316 ++--
.../docs/Contributing/NewStandardProcedure.md | 39 +-
.../docs/Contributing/PostMeetingProcedure.md | 83 +-
libcxx/docs/Contributing/ReleaseProcedure.md | 47 +-
libcxx/docs/DesignDocs/ABIVersioning.md | 26 +-
libcxx/docs/DesignDocs/AtomicDesign.md | 1352 ++++++++---------
libcxx/docs/DesignDocs/CapturingConfigInfo.md | 65 +-
.../docs/DesignDocs/ExperimentalFeatures.md | 261 ++--
.../docs/DesignDocs/ExtendedCXX03Support.md | 51 +-
libcxx/docs/DesignDocs/FeatureTestMacros.md | 28 +-
libcxx/docs/DesignDocs/FileTimeType.md | 587 ++++---
libcxx/docs/DesignDocs/HeaderRemovalPolicy.md | 40 +-
15 files changed, 1648 insertions(+), 1752 deletions(-)
diff --git a/libcxx/docs/ABIGuarantees.md b/libcxx/docs/ABIGuarantees.md
index ee9d1296757c4..6e94a2159764e 100644
--- a/libcxx/docs/ABIGuarantees.md
+++ b/libcxx/docs/ABIGuarantees.md
@@ -1,8 +1,6 @@
-.. _ABIGuarantees:
+(abiguarantees)=
-=======================
-libc++'s ABI Guarantees
-=======================
+# libc++'s ABI Guarantees
libc++ provides multiple types of ABI guarantees. These include stability of the layout of structs, the linking of TUs
built against different versions and configurations of the library, and more. This document describes what guarantees
@@ -12,58 +10,57 @@ Note that all of the guarantees listed below come with an asterisk that there ma
worth it to break that guarantee. These breaks are communicated to vendors by CCing #libcxx-vendors on GitHub. If you
are a vendor, please ask to be added to that group to be notified about changes that potentially affect you.
-ABI flags
-=========
-All the ABI flags listed below can be added to the ``__config_site`` header by the vendor to opt in to an ABI breaking
+## ABI flags
+
+All the ABI flags listed below can be added to the `__config_site` header by the vendor to opt in to an ABI breaking
change. These flags should never be set by the user. When porting libc++ to a new platform, vendord should consider
which flags to enable, assuming that ABI stability is relevant to them. Please contact the libc++ team on Discord or
through other means to be able to make an informed decision on which flags make sense to enable, and to avoid enabling
-flags which may not be stable. Flags can be enabled via the ``LIBCXX_ABI_DEFINES`` CMake option.
-
+flags which may not be stable. Flags can be enabled via the `LIBCXX_ABI_DEFINES` CMake option.
-Stability of the Layout of Structs
-==================================
+## Stability of the Layout of Structs
The layout of any user-observable struct is kept stable across versions of the library and any user-facing options
-documented :ref:`here <libcxx-configuration-macros>`. There are a lot of structs that have internal names, but are none
+documented {ref}`here <libcxx-configuration-macros>`. There are a lot of structs that have internal names, but are none
the less observable by users; for example through public aliases to these types or because they affect the layout of
other types.
There are multiple ABI flags which affect the layout of certain structs:
-``_LIBCPP_ABI_ALTERNATE_STRING_LAYOUT``
----------------------------------------
-This changes the internal layout of ``basic_string`` to move the section that is used for the internal buffer to the
+### `_LIBCPP_ABI_ALTERNATE_STRING_LAYOUT`
+
+This changes the internal layout of `basic_string` to move the section that is used for the internal buffer to the
front, making it eight byte aligned instead of being unaligned, improving the performance of some operations
significantly.
-``_LIBCPP_ABI_NO_ITERATOR_BASES``
----------------------------------
-This removes the ``iterator`` base class from ``back_insert_iterator``, ``front_insert_iterator``, ``insert_iterator``,
-``istream_iterator``, ``ostream_iterator``, ``ostreambuf_iterator``, ``reverse_iterator``, and ``raw_storage_iterator``.
+### `_LIBCPP_ABI_NO_ITERATOR_BASES`
+
+This removes the `iterator` base class from `back_insert_iterator`, `front_insert_iterator`, `insert_iterator`,
+`istream_iterator`, `ostream_iterator`, `ostreambuf_iterator`, `reverse_iterator`, and `raw_storage_iterator`.
This doesn't directly affect the layout of these types in most cases, but may result in more padding being used when
-they are used in combination, for example ``reverse_iterator<reverse_iterator<T>>``.
+they are used in combination, for example `reverse_iterator<reverse_iterator<T>>`.
-``_LIBCPP_ABI_NO_REVERSE_ITERATOR_SECOND_MEMBER``
--------------------------------------------------
-This removes a second member in ``reverse_iterator`` that is unused after LWG2360.
+### `_LIBCPP_ABI_NO_REVERSE_ITERATOR_SECOND_MEMBER`
-``_LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION``
--------------------------------------------------
-This changes the index type used inside ``variant`` to the smallest required type to reduce the datasize of variants in
+This removes a second member in `reverse_iterator` that is unused after LWG2360.
+
+### `_LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION`
+
+This changes the index type used inside `variant` to the smallest required type to reduce the datasize of variants in
most cases.
-``_LIBCPP_ABI_OPTIMIZED_FUNCTION``
-----------------------------------
-This significantly restructures how ``function`` is written to provide better performance, but is currently not ABI
+### `_LIBCPP_ABI_OPTIMIZED_FUNCTION`
+
+This significantly restructures how `function` is written to provide better performance, but is currently not ABI
stable.
-``_LIBCPP_ABI_VECTOR_LAYOUT_SIZE_BASED``
-----------------------------------------
-Changes the layout of :cpp:type:`std::vector` from pointer-based to size-based.
+### `_LIBCPP_ABI_VECTOR_LAYOUT_SIZE_BASED`
-libc++ supports two different data layouts for :cpp:type:`std::vector`:
+Changes the layout of {cpp:type}`std::vector` from pointer-based to size-based.
+libc++ supports two different data layouts for {cpp:type}`std::vector`:
+
+```{eval-rst}
.. list-table::
:header-rows: 1
@@ -107,159 +104,155 @@ libc++ supports two different data layouts for :cpp:type:`std::vector`:
This layout is opt-in, and is incompatible with the pointer-based layout. It has the
potential for significant performance improvements, especially when combined with
:ref:`hardening`.
+```
+
+### `_LIBCPP_ABI_NO_RANDOM_DEVICE_COMPATIBILITY_LAYOUT`
-``_LIBCPP_ABI_NO_RANDOM_DEVICE_COMPATIBILITY_LAYOUT``
------------------------------------------------------
-This changes the layout of ``random_device`` to only holds state with an implementation that gets entropy from a file
-(see ``_LIBCPP_USING_DEV_RANDOM``). When switching from this implementation to another one on a platform that has
-already shipped ``random_device``, one needs to retain the same object layout to remain ABI compatible. This flag
+This changes the layout of `random_device` to only holds state with an implementation that gets entropy from a file
+(see `_LIBCPP_USING_DEV_RANDOM`). When switching from this implementation to another one on a platform that has
+already shipped `random_device`, one needs to retain the same object layout to remain ABI compatible. This flag
removes these workarounds for platforms that don't care about ABI compatibility.
-``_LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING``
-------------------------------------------
-This removes artificial padding from ``_LIBCPP_COMPRESSED_PAIR``.
+### `_LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING`
+
+This removes artificial padding from `_LIBCPP_COMPRESSED_PAIR`.
-These macros are used inside the associative and unordered containers, ``deque``, ``forward_list``, ``future``,
-``list``, ``basic_string``, ``function``, ``shared_ptr``, ``unique_ptr``, and ``vector`` to stay ABI compatible with the
-legacy ``__compressed_pair`` type. ``__compressed_pair`` had historically been used to reduce storage requirements in
-the case of empty types, but has been replaced by ``[[no_unique_address]]``. ``[[no_unique_address]]`` is significantly
+These macros are used inside the associative and unordered containers, `deque`, `forward_list`, `future`,
+`list`, `basic_string`, `function`, `shared_ptr`, `unique_ptr`, and `vector` to stay ABI compatible with the
+legacy `__compressed_pair` type. `__compressed_pair` had historically been used to reduce storage requirements in
+the case of empty types, but has been replaced by `[[no_unique_address]]`. `[[no_unique_address]]` is significantly
lighter in terms of compile time and debug information, and also improves the layout of structs further. However, to
keep ABI stability, the additional improvements in layout had to be reverted by introducing artificial padding. This
flag removes that artificial padding.
-``_LIBCPP_ABI_IOS_ALLOW_ARBITRARY_FILL_VALUE``
-----------------------------------------------
-``basic_ios`` uses ``WEOF`` to indicate that the fill value is uninitialized. However, on platforms where the size of
-``char_type`` is equal to or greater than the size of ``int_type`` and ``char_type`` is unsigned,
-``char_traits<char_type>::eq_int_type()`` cannot distinguish between ``WEOF`` and ``WCHAR_MAX``. This flag changes
-``basic_ios`` to instead track whether the fill value has been initialized using a separate boolean.
+### `_LIBCPP_ABI_IOS_ALLOW_ARBITRARY_FILL_VALUE`
+`basic_ios` uses `WEOF` to indicate that the fill value is uninitialized. However, on platforms where the size of
+`char_type` is equal to or greater than the size of `int_type` and `char_type` is unsigned,
+`char_traits<char_type>::eq_int_type()` cannot distinguish between `WEOF` and `WCHAR_MAX`. This flag changes
+`basic_ios` to instead track whether the fill value has been initialized using a separate boolean.
+
+## Linking TUs which have been compiled against different releases of libc++
-Linking TUs which have been compiled against different releases of libc++
-=========================================================================
libc++ supports linking TUs which have been compiled against different releases of libc++ by marking symbols with
hidden visibility and changing the mangling of header-only functions in every release.
+## Linking TUs which have been compiled with different flags affecting code gen
-Linking TUs which have been compiled with different flags affecting code gen
-============================================================================
There are a lot of compiler (and library) flags which change the code generated for functions. This includes flags like
-``-O1``, which are guaranteed by the compiler to not change the observable behaviour of a correct program, as well as
-flags like ``-fexceptions``, which **do** change the observable behaviour. libc++ allows linking of TUs which have been
+`-O1`, which are guaranteed by the compiler to not change the observable behaviour of a correct program, as well as
+flags like `-fexceptions`, which **do** change the observable behaviour. libc++ allows linking of TUs which have been
compiled with specific flags only and makes no guarantees for any of the flags not listed below.
The flags allowed (in any combination) are:
-- ``-f[no-]exceptions``
-- ``-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE{_FAST,_EXTENSIVE,_DEBUG,_NONE}``
+\- `-f[no-]exceptions`
+\- `-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE{_FAST,_EXTENSIVE,_DEBUG,_NONE}`
Note that this does not provide any guarantees about user-defined functions, but only that the libc++ functions linked
behave as the flags say.
+## Availability of symbols in the built library (both static and shared)
-Availability of symbols in the built library (both static and shared)
-=====================================================================
In general, libc++ does not make any guarantees about forwards-compatibility. That is, a TU compiled against new headers
may not work with an older library. Vendors who require such support can leverage availability markup. On the other
hand, backwards compatibility is generally guaranteed.
There are multiple ABI flags that change the symbols exported from the built library:
-``_LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION``
--------------------------------------------------------
-This replaces the symbols that are exported for ``basic_string`` to avoid exporting functions which are likely to be
+### `_LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION`
+
+This replaces the symbols that are exported for `basic_string` to avoid exporting functions which are likely to be
inlined as well as explicitly moving paths to the built library which are slow, improving fast-path inlining of multiple
functions. This flag is currently unstable.
+## Stability of the traits of a type
-Stability of the traits of a type
-=================================
Whether a particular trait of a type is kept stable depends heavily on the type in question and the trait. The most
important trait of a type to keep stable is the triviality for the purpose of calls, since that directly affects the
function call ABI. Which types are considered non-trivial for the purpose of calls is defined in the
-`Itanium ABI <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions>`_.
-``is_trivially_copyable`` should also be kept stable usually, since many programs depend on this trait for their own
+[Itanium ABI](https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions).
+`is_trivially_copyable` should also be kept stable usually, since many programs depend on this trait for their own
layouting. This isn't as rigid as the previous requirement though.
There are multiple ABI flags that change traits of a struct:
-``_LIBCPP_ABI_ENABLE_UNIQUE_PTR_TRIVIAL_ABI``
----------------------------------------------
-This flag adds ``[[clang::trivial_abi]]`` to ``unique_ptr``, which makes it trivial for the purpose of calls.
+### `_LIBCPP_ABI_ENABLE_UNIQUE_PTR_TRIVIAL_ABI`
+
+This flag adds `[[clang::trivial_abi]]` to `unique_ptr`, which makes it trivial for the purpose of calls.
-``_LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI``
----------------------------------------------
-This flag adds ``[[clang::trivial_abi]]`` to ``shared_ptr``, which makes it trivial for the purpose of calls.
+### `_LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI`
-``_LIBCPP_ABI_TRIVIALLY_COPYABLE_BIT_ITERATOR``
------------------------------------------------
-This flag makes ``__bit_iterator`` (a.k.a. ``vector<bool>::iterator``) trivially copyable as well as trivial for the
+This flag adds `[[clang::trivial_abi]]` to `shared_ptr`, which makes it trivial for the purpose of calls.
+
+### `_LIBCPP_ABI_TRIVIALLY_COPYABLE_BIT_ITERATOR`
+
+This flag makes `__bit_iterator` (a.k.a. `vector<bool>::iterator`) trivially copyable as well as trivial for the
purpose of calls, since the copy constructor is made trivial.
-``_LIBCPP_ABI_USE_SMALL_DEQUE_BLOCK_SIZE``
-------------------------------------------
-This flag sets the default block size of ``deque`` to 512 bytes and the minimum number of elements per block to 4.
+### `_LIBCPP_ABI_USE_SMALL_DEQUE_BLOCK_SIZE`
+
+This flag sets the default block size of `deque` to 512 bytes and the minimum number of elements per block to 4.
+
+## Types that public aliases reference
-Types that public aliases reference
-===================================
There are a lot of aliases that reference types with library internal names. For example, containers contain an
-``iterator`` alias to a type with a library internal name. These have to always reference the same type, since the
+`iterator` alias to a type with a library internal name. These have to always reference the same type, since the
mangling of user-defined function overloads would change otherwise. A notable exception to this are the alias templates
to type traits. There doesn't seem to be anybody who relies on these names staying the same, so it is OK to change what
these aliases actually reference.
There are multiple ABI flags which change which type an alias references:
-``_LIBCPP_ABI_INCOMPLETE_TYPES_IN_DEQUE``
------------------------------------------
-This changes ``deque::iterator`` to avoid requiring complete types for ``deque``.
+### `_LIBCPP_ABI_INCOMPLETE_TYPES_IN_DEQUE`
+
+This changes `deque::iterator` to avoid requiring complete types for `deque`.
+
+### `_LIBCPP_ABI_FIX_UNORDERED_CONTAINER_SIZE_TYPE`
-``_LIBCPP_ABI_FIX_UNORDERED_CONTAINER_SIZE_TYPE``
--------------------------------------------------
-This changes the unordered container's ``size_types`` aliases.
+This changes the unordered container's `size_types` aliases.
-``_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY`` and ``_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW``
------------------------------------------------------------------------------------------------
-This changes the ``iterator`` and ``const_iterator`` of ``array`` and ``string_view`` respectively to reference
-``__wrap_iter`` instead, which makes it less likely for users to depend on non-portable implementation details. This is
+### `_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY` and `_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW`
+
+This changes the `iterator` and `const_iterator` of `array` and `string_view` respectively to reference
+`__wrap_iter` instead, which makes it less likely for users to depend on non-portable implementation details. This is
especially useful because enabling bounded iterators hardening requires code not to make these assumptions.
-``_LIBCPP_ABI_BOUNDED_ITERATORS``, ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING``, ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR``, ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY`` and ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL``
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-These flags change the ``iterator`` member of various classes to reference hardened iterators instead. See the
-:ref:`hardening documentation <hardening>` for more details.
+### `_LIBCPP_ABI_BOUNDED_ITERATORS`, `_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING`, `_LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR`, `_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY` and `_LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL`
+
+These flags change the `iterator` member of various classes to reference hardened iterators instead. See the
+{ref}`hardening documentation <hardening>` for more details.
+## Meaning of values
-Meaning of values
-=================
The meaning of specific values can usually not be changed, since programs compiled against older versions of the headers
may check for these values. These specific values don't have to be hard-coded, but can also depend on user input.
There are multiple ABI flags that change the meaning of particular values:
-``_LIBCPP_ABI_REGEX_CONSTANTS_NONZERO``
----------------------------------------
-This changes the value of ``regex_constants::syntax_option-type::ECMAScript`` to be standards-conforming.
+### `_LIBCPP_ABI_REGEX_CONSTANTS_NONZERO`
+
+This changes the value of `regex_constants::syntax_option-type::ECMAScript` to be standards-conforming.
-``_LIBCPP_ABI_FIX_CITYHASH_IMPLEMENTATION``
--------------------------------------------
-This flag fixes the implementation of CityHash used for ``hash<fundamental-type>``. The incorrect implementation of
+### `_LIBCPP_ABI_FIX_CITYHASH_IMPLEMENTATION`
+
+This flag fixes the implementation of CityHash used for `hash<fundamental-type>`. The incorrect implementation of
CityHash has the problem that it drops some bits on the floor. Fixing the implementation changes the hash of values,
resulting in an ABI break.
-``_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE``
-------------------------------------------
-This flag changes the implementation of ``atomic::wait()`` and ``atomic::notify_one()/notify_all()`` to use the
+### `_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE`
+
+This flag changes the implementation of `atomic::wait()` and `atomic::notify_one()/notify_all()` to use the
native atomic wait/notify operations on platforms that support them based on the size of the atomic type, instead
-of the type itself. This means for example that a type with ``sizeof(T) == 4`` on Linux that doesn't have padding
-bytes would be able to use the underlying platform's atomic wait primitive, which is otherwise only used for ``int32_t``.
+of the type itself. This means for example that a type with `sizeof(T) == 4` on Linux that doesn't have padding
+bytes would be able to use the underlying platform's atomic wait primitive, which is otherwise only used for `int32_t`.
Since the whole program must use the same implementation for correctness, changing this is an ABI break since libc++
supports linking against TUs that were compiled against older versions of the library.
+## inline namespaces
-inline namespaces
-=================
Inline namespaces which contain types that are observable by the user need to be kept the same, since they affect
-mangling. Almost all of libc++'s symbols are inside an inline namespace. By default that namespace is ``__1``, but can
+mangling. Almost all of libc++'s symbols are inside an inline namespace. By default that namespace is `__1`, but can
be changed by the vendor by setting `LIBCXX_ABI_NAMESPACE` during CMake configuration. There is also
-``_LIBCPP_ABI_NO_FILESYSTEM_INLINE_NAMESPACE`` to remove the ``__fs`` namespace from surrounding the ``filesystem``
+`_LIBCPP_ABI_NO_FILESYSTEM_INLINE_NAMESPACE` to remove the `__fs` namespace from surrounding the `filesystem`
namespace. This shortens the mangling of the filesystem symbols a bit.
+
diff --git a/libcxx/docs/AddingNewCIJobs.md b/libcxx/docs/AddingNewCIJobs.md
index 7a12728b98919..2e059a750b782 100644
--- a/libcxx/docs/AddingNewCIJobs.md
+++ b/libcxx/docs/AddingNewCIJobs.md
@@ -1,66 +1,62 @@
-.. _AddingNewCIJobs:
+(addingnewcijobs)=
-==================
-Adding New CI Jobs
-==================
+# Adding New CI Jobs
-.. contents::
- :local:
+```{contents}
+:local: true
+```
-Adding The Job
-==============
+## Adding The Job
libc++ uses Buildkite for running its CI. Setting up new CI jobs is easy, and
these jobs can run either on our existing infrastructure, or on your own.
If you need to run the job on your own machines, please follow the
-`Buildkite guide <https://buildkite.com/docs/agent/v3>`_ to setup your
+[Buildkite guide](https://buildkite.com/docs/agent/v3) to setup your
own agents. Make sure you tag your agents in a way that you'll be able
to recognize them when defining your job below. Finally, in order for the
agent to register itself to Buildkite, it will need a BuildKite Agent token.
Please contact a maintainer to get your token.
-Then, simply add a job to the Buildkite pipeline by editing ``libcxx/utils/ci/buildkite-pipeline.yml``.
+Then, simply add a job to the Buildkite pipeline by editing `libcxx/utils/ci/buildkite-pipeline.yml`.
Take a look at how the surrounding jobs are defined and do something similar.
An example of a job definition is:
-.. code-block:: yaml
-
- - label: "C++11"
- command: "libcxx/utils/ci/run-buildbot generic-cxx11"
- env:
- CC: clang
- CXX: clang++
- artifact_paths:
- - "**/test-results.xml"
- agents:
- queue: "libcxx-builders"
- os: "linux"
- retry:
- [...]
-
-If you create your own agents, put them in the ``libcxx-builders`` queue and
+```yaml
+- label: "C++11"
+ command: "libcxx/utils/ci/run-buildbot generic-cxx11"
+ env:
+ CC: clang
+ CXX: clang++
+ artifact_paths:
+ - "**/test-results.xml"
+ agents:
+ queue: "libcxx-builders"
+ os: "linux"
+ retry:
+ [...]
+```
+
+If you create your own agents, put them in the `libcxx-builders` queue and
use agent tags to allow targeting your agents from the Buildkite pipeline
config appropriately.
We try to keep the pipeline definition file as simple as possible, and to
-keep any script used for CI inside ``libcxx/utils/ci``. This ensures that
+keep any script used for CI inside `libcxx/utils/ci`. This ensures that
it's possible to reproduce CI issues locally with ease, understanding of
course that some setups may require access to special hardware that is not
available.
-Finally, add your contact info to ``libcxx/utils/ci/BOT_OWNERS.txt``. This will
+Finally, add your contact info to `libcxx/utils/ci/BOT_OWNERS.txt`. This will
be used to contact you when there are issues with the bot.
-Testing Your New Job
-====================
+## Testing Your New Job
Testing your new job is easy -- once your agent is set up (if any), just open
a code review and the libc++ CI pipeline will run, including any changes you
might have made to the pipeline definition itself.
-Service Level Agreement
-=======================
+## Service Level Agreement
To keep the libc++ CI useful for everyone, we aim for a quick turnaround time
for all CI jobs. This allows the overall pipeline to finish in a reasonable
@@ -70,3 +66,4 @@ order to avoid flaky failures, which reduce the value of CI for everyone.
We may be reluctant to add and support CI jobs that take a long time to finish
or that are too flaky.
+
diff --git a/libcxx/docs/CodingGuidelines.md b/libcxx/docs/CodingGuidelines.md
index d91e3f22f36b6..266ed0f291d04 100644
--- a/libcxx/docs/CodingGuidelines.md
+++ b/libcxx/docs/CodingGuidelines.md
@@ -1,227 +1,212 @@
-.. _CodingGuidelines:
+(codingguidelines)=
-========================
-libc++ Coding Guidelines
-========================
+# libc++ Coding Guidelines
-.. contents::
- :local:
+```{contents}
+:local: true
+```
-Use ``__ugly_names`` for implementation details
-===============================================
+## Use `__ugly_names` for implementation details
-Libc++ uses ``__ugly_names`` or ``_UglyNames`` for implementation details. These names are reserved for implementations,
-so users may not use them in their own applications. When using a name like ``T``, a user may have defined a macro that
-changes the meaning of ``T``. By using ``__ugly_names`` we avoid that problem.
+Libc++ uses `__ugly_names` or `_UglyNames` for implementation details. These names are reserved for implementations,
+so users may not use them in their own applications. When using a name like `T`, a user may have defined a macro that
+changes the meaning of `T`. By using `__ugly_names` we avoid that problem.
-This is partially enforced by the clang-tidy check ``readability-identifier-naming`` and
-``libcxx/test/libcxx/system_reserved_names.gen.py``.
+This is partially enforced by the clang-tidy check `readability-identifier-naming` and
+`libcxx/test/libcxx/system_reserved_names.gen.py`.
-Don't use argument-dependent lookup unless required by the standard
-===================================================================
+## Don't use argument-dependent lookup unless required by the standard
Unqualified function calls are susceptible to
-`argument-dependent lookup (ADL) <https://en.cppreference.com/w/cpp/language/adl>`_. This means calling
-``move(UserType)`` might not call ``std::move``. Therefore, function calls must use qualified names to avoid ADL. Some
-functions in the standard library `require ADL usage <http://eel.is/c++draft/contents#3>`_. Names of classes, variables,
+[argument-dependent lookup (ADL)](https://en.cppreference.com/w/cpp/language/adl). This means calling
+`move(UserType)` might not call `std::move`. Therefore, function calls must use qualified names to avoid ADL. Some
+functions in the standard library [require ADL usage](http://eel.is/c++draft/contents#3). Names of classes, variables,
concepts, and type aliases are not subject to ADL. They don't need to be qualified.
-Function overloading also applies to operators. Using ``&user_object`` may call a user-defined ``operator&``. Use
-``std::addressof`` instead. Similarly, to avoid invoking a user-defined ``operator,``, make sure to cast the result to
-``void`` when using the ``,`` or avoid it in the first place. For example:
+Function overloading also applies to operators. Using `&user_object` may call a user-defined `operator&`. Use
+`std::addressof` instead. Similarly, to avoid invoking a user-defined `operator,`, make sure to cast the result to
+`void` when using the `,` or avoid it in the first place. For example:
-.. code-block:: cpp
+```cpp
+for (; __first1 != __last1; ++__first1, (void)++__first2) {
+ ...
+}
+```
- for (; __first1 != __last1; ++__first1, (void)++__first2) {
- ...
- }
+This is mostly enforced by the clang-tidy check `libcpp-robust-against-adl`.
-This is mostly enforced by the clang-tidy check ``libcpp-robust-against-adl``.
-
-Avoid including public headers
-==============================
+## Avoid including public headers
libc++ uses implementation-detail headers for most code. These are in a directory that starts with two underscores
-(e.g. ``<__type_traits/decay.h>``). These detail headers are significantly smaller than their public counterparts.
+(e.g. `<__type_traits/decay.h>`). These detail headers are significantly smaller than their public counterparts.
This reduces the amount of code that is included in a single public header, which reduces compile times.
-Add ``_LIBCPP_HIDE_FROM_ABI`` unless you know better
-====================================================
+## Add `_LIBCPP_HIDE_FROM_ABI` unless you know better
-``_LIBCPP_HIDE_FROM_ABI`` should be on every function in the library unless there is a reason not to do so. The main
-reason not to add ``_LIBCPP_HIDE_FROM_ABI`` is if a function is exported from the libc++ built library. In that case the
-function should be marked with ``_LIBCPP_EXPORTED_FROM_ABI``. Virtual functions should be marked with
-``_LIBCPP_HIDE_FROM_ABI_VIRTUAL`` instead.
+`_LIBCPP_HIDE_FROM_ABI` should be on every function in the library unless there is a reason not to do so. The main
+reason not to add `_LIBCPP_HIDE_FROM_ABI` is if a function is exported from the libc++ built library. In that case the
+function should be marked with `_LIBCPP_EXPORTED_FROM_ABI`. Virtual functions should be marked with
+`_LIBCPP_HIDE_FROM_ABI_VIRTUAL` instead.
-This is mostly enforced by the clang-tidy checks ``libcpp-hide-from-abi`` and ``libcpp-avoid-abi-tag-on-virtual``.
+This is mostly enforced by the clang-tidy checks `libcpp-hide-from-abi` and `libcpp-avoid-abi-tag-on-virtual`.
-Define configuration macros to 0 or 1
-=====================================
+## Define configuration macros to 0 or 1
Macros should usually be defined in all configurations, instead of defining them when they're enabled and leaving them
undefined otherwise. For example, use
-.. code-block:: cpp
-
- #if SOMETHING
- # define _LIBCPP_SOMETHING_ENABLED 1
- #else
- # define _LIBCPP_SOMETHING_ENABLED 0
- #endif
-
-and then check for ``#if _LIBCPP_SOMETHING_ENABLED`` instead of
+```cpp
+#if SOMETHING
+# define _LIBCPP_SOMETHING_ENABLED 1
+#else
+# define _LIBCPP_SOMETHING_ENABLED 0
+#endif
+```
-.. code-block:: cpp
+and then check for `#if _LIBCPP_SOMETHING_ENABLED` instead of
- #if SOMETHING
- # define _LIBCPP_SOMETHING_ENABLED
- #endif
+```cpp
+#if SOMETHING
+# define _LIBCPP_SOMETHING_ENABLED
+#endif
+```
-and then checking for ``#ifdef _LIBCPP_SOMETHING_ENABLED``.
+and then checking for `#ifdef _LIBCPP_SOMETHING_ENABLED`.
-This makes it significantly easier to catch missing includes: Clang and GCC with ``-Wundef`` enabled will warn
-when using an undefined macro inside an ``#if`` statement. Some macros in libc++ don't use this style yet,
+This makes it significantly easier to catch missing includes: Clang and GCC with `-Wundef` enabled will warn
+when using an undefined macro inside an `#if` statement. Some macros in libc++ don't use this style yet,
so this guideline only applies when introducing a new macro.
-This is partially enforced by the clang-tidy check ``libcpp-internal-ftms``.
+This is partially enforced by the clang-tidy check `libcpp-internal-ftms`.
-Use ``_LIBCPP_STD_VER``
-=======================
+## Use `_LIBCPP_STD_VER`
-libc++ defines the macro ``_LIBCPP_STD_VER`` for the different libc++ dialects. This should be used instead of
-``__cplusplus``.
+libc++ defines the macro `_LIBCPP_STD_VER` for the different libc++ dialects. This should be used instead of
+`__cplusplus`.
-This is mostly enforced by the clang-tidy check ``libcpp-cpp-version-check``.
+This is mostly enforced by the clang-tidy check `libcpp-cpp-version-check`.
-Use ``__ugly__`` spellings of vendor attributes
-===============================================
+## Use `__ugly__` spellings of vendor attributes
-Vendor attributes should always be ``__uglified__`` to avoid naming clashes with user-defined macros. For gnu-style
-attributes this takes the form ``__attribute__((__foo__))``. C++11-style attributes look like ``[[_Clang::__foo__]]`` or
-``[[__gnu__::__foo__]]`` for Clang or GCC attributes respectively. Clang and GCC also support standard attributes in
-earlier language dialects than they were introduced. These should be spelled as ``[[__foo__]]``. MSVC currently doesn't
+Vendor attributes should always be `__uglified__` to avoid naming clashes with user-defined macros. For gnu-style
+attributes this takes the form `__attribute__((__foo__))`. C++11-style attributes look like `[[_Clang::__foo__]]` or
+`[[__gnu__::__foo__]]` for Clang or GCC attributes respectively. Clang and GCC also support standard attributes in
+earlier language dialects than they were introduced. These should be spelled as `[[__foo__]]`. MSVC currently doesn't
provide alternative spellings for their attributes, so these should be avoided if at all possible.
-This is enforced by the clang-tidy check ``libcpp-uglify-attributes``.
+This is enforced by the clang-tidy check `libcpp-uglify-attributes`.
-Use extensions if they simplify the code
-========================================
+## Use extensions if they simplify the code
libc++ only supports recent versions Clang and GCC, which allows us to make use of extensions in the code base if both
-compilers support them. Only features backported from future language versions should be used liberally throughout the
-library. For example, some of the most useful extensions are lambdas and ``if constexpr``, since they almost always
+compilers support them. Only features backported from future language versions should be used liberally throughout the
+library. For example, some of the most useful extensions are lambdas and `if constexpr`, since they almost always
significantly improve readability when used as intended.
libc++ supports the C++98/03 mode only with the Clang compiler. Clang provides many C++11 features in C++03, making it
possible to write a lot of code in a simpler way than if we were restricted to C++03 features. Some use of extensions is
even mandatory, since libc++ supports move semantics in C++03. Details on which features have been backported can be
found
-`here <https://clang.llvm.org/docs/LanguageExtensions.html#language-extensions-back-ported-to-previous-standards>`__.
+[here](https://clang.llvm.org/docs/LanguageExtensions.html#language-extensions-back-ported-to-previous-standards).
GCC is only supported from C++11 onwards. Unfortunately, GCC doesn't document which features are backported to older
language versions, so you just have to try whether GCC accepts the features you want to use.
-Use ``using`` aliases instead of ``typedef``
-============================================
+## Use `using` aliases instead of `typedef`
-``using`` aliases are generally easier to read and support templates. Some code in libc++ uses ``typedef`` for
+`using` aliases are generally easier to read and support templates. Some code in libc++ uses `typedef` for
historical reasons.
-Write SFINAE with ``requires`` clauses in C++20-only code
-=========================================================
+## Write SFINAE with `requires` clauses in C++20-only code
-``requires`` clauses can be significantly easier to read than ``enable_if`` and friends in some cases, since concepts
+`requires` clauses can be significantly easier to read than `enable_if` and friends in some cases, since concepts
subsume other concepts. This means that overloads based on traits can be written without negating more general cases.
They also show intent better.
-Write ``enable_if`` as ``enable_if_t<condition, int> = 0``
-==========================================================
+## Write `enable_if` as `enable_if_t<condition, int> = 0`
-The form ``enable_if_t<condition, int> = 0`` is the only one that works in every language mode and for overload sets
+The form `enable_if_t<condition, int> = 0` is the only one that works in every language mode and for overload sets
using the same template arguments otherwise. If the code must work in C++11 or C++03, the libc++-internal alias
-``__enable_if_t`` can be used instead.
+`__enable_if_t` can be used instead.
-Prefer alias templates over class templates
-===========================================
+## Prefer alias templates over class templates
Alias templates are much more lightweight than class templates, since they don't require new instantiations for
different types. If the only member of a class is an alias, like in type traits, alias templates should be used if
possible. They do force more eager evaluation though, which can be a problem in some cases.
-Apply ``[[nodiscard]]`` where relevant
-======================================
+## Apply `[[nodiscard]]` where relevant
-Libc++ adds ``[[nodiscard]]`` whenever relevant to catch potential bugs. The standards committee has decided to _not_
+Libc++ adds `[[nodiscard]]` whenever relevant to catch potential bugs. The standards committee has decided to \_not\_
have a recommended practice where to put them, so libc++ applies it whenever it makes sense to catch potential bugs.
-``[[nodiscard]]`` should be applied to functions
+`[[nodiscard]]` should be applied to functions
- where discarding the return value is most likely a correctness issue. For example a locking constructor in
- ``unique_lock``.
+ `unique_lock`.
- where discarding the return value likely points to the user wanting to do something different. For example
- ``vector::empty()``, which probably should have been ``vector::clear()``.
+ `vector::empty()`, which probably should have been `vector::clear()`.
This can help spotting bugs easily which otherwise may take a very long time to find.
-- which return a constant. For example ``numeric_limits::min()``.
-- which only observe a value. For example ``string::size()``.
+- which return a constant. For example `numeric_limits::min()`.
+
+- which only observe a value. For example `string::size()`.
Code that discards values from these kinds of functions is dead code. It can either be removed, or the programmer
meant to do something different.
-- where discarding the value is most likely a misuse of the function. For example ``std::find(first, last, val)``.
+- where discarding the value is most likely a misuse of the function. For example `std::find(first, last, val)`.
This protects programmers from assuming too much about how the internals of a function work, making code more robust
in the presence of future optimizations.
-``[[nodiscard]]`` should not be applied to functions if Clang already diagnoses unused results, for example:
-- conversion functions
-- equality operators
-- relational operators
+`[[nodiscard]]` should not be applied to functions if Clang already diagnoses unused results, for example:
+\- conversion functions
+\- equality operators
+\- relational operators
-Applications of ``[[nodiscard]]`` are code like any other code, so we aim to test them on public interfaces. This can be
-done with a ``.verify.cpp`` test. Many examples are available. Just look for tests with the suffix
-``.nodiscard.verify.cpp``.
+Applications of `[[nodiscard]]` are code like any other code, so we aim to test them on public interfaces. This can be
+done with a `.verify.cpp` test. Many examples are available. Just look for tests with the suffix
+`.nodiscard.verify.cpp`.
-Don't use public API names for symbols on the ABI boundary
-==========================================================
+## Don't use public API names for symbols on the ABI boundary
-Most functions in libc++ are defined in headers either as templates or as ``inline`` functions. However, we sometimes
+Most functions in libc++ are defined in headers either as templates or as `inline` functions. However, we sometimes
need or want to define functions in the built library. Symbols that are declared in the headers and defined in the
built library become part of the ABI of libc++, which must be preserved for backwards compatibility. This means that
we can't easily remove or rename such symbols except in special cases.
When adding a symbol to the built library, make sure not to use a public name directly. Instead, define a
-``_LIBCPP_HIDE_FROM_ABI`` function in the headers with the public name and have it call a private function in the built
+`_LIBCPP_HIDE_FROM_ABI` function in the headers with the public name and have it call a private function in the built
library. This approach makes it easier to make changes to libc++ like move something from the built library to the
-headers (which is sometimes required for ``constexpr`` support).
+headers (which is sometimes required for `constexpr` support).
-When defining a function at the ABI boundary, it can also be useful to consider which attributes (like ``[[gnu::pure]]``
-and ``[[clang::noescape]]``) can be added to the function to improve the compiler's ability to optimize.
+When defining a function at the ABI boundary, it can also be useful to consider which attributes (like `[[gnu::pure]]`
+and `[[clang::noescape]]`) can be added to the function to improve the compiler's ability to optimize.
-Library-internal type aliases should be annotated with ``_LIBCPP_NODEBUG``
-==========================================================================
+## Library-internal type aliases should be annotated with `_LIBCPP_NODEBUG`
Libc++ has lots of internal type aliases. Accumulated, these can result in significant amounts of debug information that
users generally don't care about, since users don't try to debug standard library facilities in most cases. For that
-reason, all library-internal type aliases that aren't function-local should be annotated with ``_LIBCPP_NODEBUG`` to
-prevent compilers from generating said debug information. Aliases inside type traits (i.e. aliases named ``type``)
+reason, all library-internal type aliases that aren't function-local should be annotated with `_LIBCPP_NODEBUG` to
+prevent compilers from generating said debug information. Aliases inside type traits (i.e. aliases named `type`)
should be annotated for the same reason.
-This is enforced by the clang-tidy check ``libcpp-nodebug-on-aliases``.
+This is enforced by the clang-tidy check `libcpp-nodebug-on-aliases`.
-Naming benchmarks
-=================
+## Naming benchmarks
Libc++ contains several benchmarks. It is helpful to observe some consistency when naming benchmarks since it makes it
easier to search for and filter benchmark names from various other tools like LNT. In particular, we name benchmarks
after the function they are measuring, with a few transformations to help filtering:
-- Constructors are named ``ctor`` to make the name independent on the container being benchmarked.
-- Copy and move operations use ``Self`` instead of the container type, again to make their name independent from the
+- Constructors are named `ctor` to make the name independent on the container being benchmarked.
+- Copy and move operations use `Self` instead of the container type, again to make their name independent from the
container being benchmarked.
When multiple benchmarks measure the same function under different circumstances, we add context as a parenthesis
-after the function signature. For example, ``std::vector<bool>::ctor(Self&&, const allocator_type&) (equal allocators)``
-would be the allocator-aware move constructor for ``std::vector<bool>`` in the case of equal allocators.
+after the function signature. For example, `std::vector<bool>::ctor(Self&&, const allocator_type&) (equal allocators)`
+would be the allocator-aware move constructor for `std::vector<bool>` in the case of equal allocators.
+
diff --git a/libcxx/docs/Contributing.md b/libcxx/docs/Contributing.md
index 11f803b75b837..e3bb5d5bb9ba7 100644
--- a/libcxx/docs/Contributing.md
+++ b/libcxx/docs/Contributing.md
@@ -1,148 +1,133 @@
-.. _ContributingToLibcxx:
+(contributingtolibcxx)=
-======================
-Contributing to libc++
-======================
+# Contributing to libc++
This file contains information useful when contributing to libc++. If this is your first time contributing,
-please also read `this document <https://www.llvm.org/docs/Contributing.html>`__ on general rules for
+please also read [this document](https://www.llvm.org/docs/Contributing.html) on general rules for
contributing to LLVM.
-If you plan on contributing to libc++, it can be useful to join the ``#libcxx`` channel
-on `LLVM's Discord server <https://discord.gg/jzUbyP26tQ>`__.
+If you plan on contributing to libc++, it can be useful to join the `#libcxx` channel
+on [LLVM's Discord server](https://discord.gg/jzUbyP26tQ).
-Looking for pre-existing pull requests
-======================================
+## Looking for pre-existing pull requests
Before you start working on any feature, please take a look at the open libc++ pull
requests to avoid duplicating someone else's work. You can do that on GitHub by
-filtering pull requests `tagged with libc++ <https://github.com/llvm/llvm-project/pulls?q=is%3Apr+is%3Aopen+label%3Alibc%2B%2B>`__.
+filtering pull requests [tagged with libc++](https://github.com/llvm/llvm-project/pulls?q=is%3Apr+is%3Aopen+label%3Alibc%2B%2B).
If you see that your feature is already being worked on, please consider chiming in
and helping review the code instead of duplicating work!
-RFCs for significant user-affecting changes
-===========================================
+## RFCs for significant user-affecting changes
Before you start working on a change that can have significant impact on users of the library,
-please consider creating a RFC on the `libc++ forum <https://discourse.llvm.org/c/runtimes/libcxx>`_.
+please consider creating a RFC on the [libc++ forum](https://discourse.llvm.org/c/runtimes/libcxx).
This will ensure that you work in a direction that the project endorses and will ease reviewing your
contribution as directional questions can be raised early. Including a WIP patch is not mandatory,
but it can be useful to ground the discussion in something concrete.
-Writing tests and running the test suite
-========================================
+## Writing tests and running the test suite
Every change in libc++ must come with appropriate tests. Libc++ has an extensive test suite that
should be run locally by developers before submitting patches and is also run as part of our CI
-infrastructure. The documentation about writing tests and running them is :ref:`here <testing>`.
+infrastructure. The documentation about writing tests and running them is {ref}`here <testing>`.
-Coding Guidelines
-=================
+## Coding Guidelines
-libc++'s coding guidelines are documented :ref:`here <CodingGuidelines>`.
+libc++'s coding guidelines are documented {ref}`here <CodingGuidelines>`.
-Procedures for recurring tasks
-==============================
+## Procedures for recurring tasks
-* :ref:`After a WG21 meeting <PostMeetingProcedure>`
-* :ref:`Around a LLVM release <ReleaseProcedure>`
-* :ref:`When a new Standard is introduced <NewStandardProcedure>`
+- {ref}`After a WG21 meeting <PostMeetingProcedure>`
+- {ref}`Around a LLVM release <ReleaseProcedure>`
+- {ref}`When a new Standard is introduced <NewStandardProcedure>`
-Resources
-=========
+## Resources
-Libc++ specific
----------------
+### Libc++ specific
-- ``libcxx/include/__config`` -- this file contains the commonly used
+- `libcxx/include/__config` -- this file contains the commonly used
macros in libc++. Libc++ supports all C++ language versions. Newer versions
- of the Standard add new features. For example, making functions ``constexpr``
- in C++20 is done by using ``_LIBCPP_CONSTEXPR_SINCE_CXX20``. This means the
- function is ``constexpr`` in C++20 and later. The Standard does not allow
+ of the Standard add new features. For example, making functions `constexpr`
+ in C++20 is done by using `_LIBCPP_CONSTEXPR_SINCE_CXX20`. This means the
+ function is `constexpr` in C++20 and later. The Standard does not allow
making this available in C++17 or earlier, so we use a macro to implement
this requirement.
-- ``libcxx/test/support/test_macros.h`` -- similar to the above, but for the
+- `libcxx/test/support/test_macros.h` -- similar to the above, but for the
test suite.
-
-ISO C++ Standard
-----------------
+### ISO C++ Standard
Libc++ implements the library part of the ISO C++ standard. The official
publication must be bought from ISO or your national body. This is not
needed to work on libc++, there are other free resources available.
-- The `LaTeX sources <https://github.com/cplusplus/draft>`_ used to
+- The [LaTeX sources](https://github.com/cplusplus/draft) used to
create the official C++ standard. This can be used to create your own
unofficial build of the standard.
-
-- An `HTML rendered version of the draft <https://eel.is/c++draft/>`_ is
+- An [HTML rendered version of the draft](https://eel.is/c++draft/) is
available. This is the most commonly used place to look for the
wording of the standard.
-
-- An `alternative <https://github.com/timsong-cpp/cppwp>`_ is available.
+- An [alternative](https://github.com/timsong-cpp/cppwp) is available.
This link has both recent and historic versions of the standard.
-
- When implementing features, there are
- `general requirements <https://eel.is/c++draft/#library>`_.
+ [general requirements](https://eel.is/c++draft/#library).
Most papers use this
- `jargon <http://eel.is/c++draft/structure#specifications>`_
+ [jargon](http://eel.is/c++draft/structure#specifications)
to describe how library functions work.
-
-- The `WG21 redirect service <https://wg21.link/>`_ is a tool to quickly locate
+- The [WG21 redirect service](https://wg21.link/) is a tool to quickly locate
papers, issues, and wording in the standard.
-
-- The `paper trail <https://github.com/cplusplus/papers/issues>`_ of
+- The [paper trail](https://github.com/cplusplus/papers/issues) of
papers is publicly available, including the polls taken. It
contains links to the minutes of paper's discussion. Per ISO rules,
these minutes are only accessible by members of the C++ committee.
-
-- `Feature-Test Macros and Policies
- <https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations>`_
+- [Feature-Test Macros and Policies](https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations)
contains information about feature-test macros in C++.
It contains a list with all feature-test macros, their versions, and the paper
that introduced them.
-
-- `cppreference <https://en.cppreference.com/w/>`_ is a good resource
+- [cppreference](https://en.cppreference.com/w/) is a good resource
for the usage of C++ library and language features. It's easier to
read than the C++ Standard, but it lacks details needed to properly implement
library features.
-
-Pre-commit check list
-=====================
+## Pre-commit check list
Before committing or creating a review, please go through this check-list to make
sure you don't forget anything:
-- Do you have :ref:`tests <testing>` for every public class and/or function you're adding or modifying?
+- Do you have {ref}`tests <testing>` for every public class and/or function you're adding or modifying?
+
- Did you update the synopsis of the relevant headers?
-- Did you update the relevant files to track implementation status (in ``docs/Status/``)?
-- Did you mark all functions and type declarations with the :ref:`proper visibility macro <visibility-macros>`?
-- Did you add all new named declarations to the ``std`` module?
+
+- Did you update the relevant files to track implementation status (in `docs/Status/`)?
+
+- Did you mark all functions and type declarations with the {ref}`proper visibility macro <visibility-macros>`?
+
+- Did you add all new named declarations to the `std` module?
+
- If you added a header:
- - Did you add it to ``include/module.modulemap.in``?
- - Did you add it to ``include/CMakeLists.txt``?
- - If it's a public header, did you update ``utils/libcxx/header_information.py``?
+ - Did you add it to `include/module.modulemap.in`?
+ - Did you add it to `include/CMakeLists.txt`?
+ - If it's a public header, did you update `utils/libcxx/header_information.py`?
+
+- Did you add the relevant feature test macro(s) for your feature? Did you update the `generate_feature_test_macro_components.py` script with it?
+
+- Did you run the `libcxx-generate-files` target and verify its output?
-- Did you add the relevant feature test macro(s) for your feature? Did you update the ``generate_feature_test_macro_components.py`` script with it?
-- Did you run the ``libcxx-generate-files`` target and verify its output?
-- If needed, did you add ``_LIBCPP_PUSH_MACROS`` and ``_LIBCPP_POP_MACROS`` to the relevant headers?
+- If needed, did you add `_LIBCPP_PUSH_MACROS` and `_LIBCPP_POP_MACROS` to the relevant headers?
-The review process
-==================
+## The review process
After uploading your patch, you should see that the "libc++" review group is automatically
added as a reviewer for your patch. Once the group is marked as having approved your patch,
you can commit it. However, if you get an approval very quickly for a significant patch,
please try to wait a couple of business days before committing to give the opportunity for
other reviewers to chime in. If you need someone else to commit the patch for you, please
-mention it and provide your ``Name <email at domain>`` for us to attribute the commit properly.
+mention it and provide your `Name <email at domain>` for us to attribute the commit properly.
Note that the rule for accepting as the "libc++" review group is to wait for two members
of the group to have approved the patch, excluding the patch author. This is not a hard
-rule -- for very simple patches, use your judgement. The `"libc++" review group <https://reviews.llvm.org/project/members/64/>`__
+rule -- for very simple patches, use your judgement. The ["libc++" review group](https://reviews.llvm.org/project/members/64/)
consists of frequent libc++ contributors with a good understanding of the project's
guidelines -- if you would like to be added to it, please reach out on Discord.
@@ -157,178 +142,183 @@ Some tips:
patches to implement one feature if the feature can be split into
self-contained sub-tasks.
-Exporting new symbols from the library
-======================================
+## Exporting new symbols from the library
-When exporting new symbols from libc++, you must update the ABI lists located in ``lib/abi``.
-To test whether the lists are up-to-date, please run the target ``check-cxx-abilist``.
-To regenerate the lists, use the target ``generate-cxx-abilist``.
+When exporting new symbols from libc++, you must update the ABI lists located in `lib/abi`.
+To test whether the lists are up-to-date, please run the target `check-cxx-abilist`.
+To regenerate the lists, use the target `generate-cxx-abilist`.
The ABI lists must be updated for all supported platforms; currently Linux and
-Apple. If you don't have access to one of these platforms, you can download an
+Apple. If you don't have access to one of these platforms, you can download an
updated list from the failed build at
-`Buildkite <https://buildkite.com/llvm-project/libcxx-ci>`__.
-Look for the failed build and select the ``artifacts`` tab. There, download the
+[Buildkite](https://buildkite.com/llvm-project/libcxx-ci).
+Look for the failed build and select the `artifacts` tab. There, download the
abilist for the platform, e.g.:
-* C++<version>.
-* macOS X86_64 and macOS arm64 for the Apple platform.
+- C++\<version>.
+- macOS X86_64 and macOS arm64 for the Apple platform.
+## Pre-commit CI
-Pre-commit CI
-=============
+### Introduction
-Introduction
-------------
-
-Unlike most parts of the LLVM project, libc++ uses a pre-commit CI [#]_. Some of
-this CI is hosted on `Buildkite <https://buildkite.com/llvm-project/libcxx-ci>`__,
+Unlike most parts of the LLVM project, libc++ uses a pre-commit CI [^footnote-1]. Some of
+this CI is hosted on [Buildkite](https://buildkite.com/llvm-project/libcxx-ci),
but some has migrated to the LLVM CI infrastructure. The build results are
visible in the review on GitHub. Please make sure the CI is green before
committing a patch.
-The CI tests libc++ for all :ref:`supported platforms <SupportedPlatforms>`.
+The CI tests libc++ for all {ref}`supported platforms <SupportedPlatforms>`.
The build is started for every commit added to a Pull Request. A complete CI
run takes approximately one hour. To reduce the load:
-* The build is cancelled when a new commit is pushed to a PR that is already running CI.
-* The build is done in several stages and cancelled when a stage fails.
+- The build is cancelled when a new commit is pushed to a PR that is already running CI.
+- The build is done in several stages and cancelled when a stage fails.
Typically, the libc++ jobs use a Ubuntu Docker image. This image contains
-recent `nightly builds <https://apt.llvm.org>`__ of all supported versions of
-Clang and the current version of the ``main`` branch. These versions of Clang
+recent [nightly builds](https://apt.llvm.org) of all supported versions of
+Clang and the current version of the `main` branch. These versions of Clang
are used to build libc++ and execute its tests.
Unless specified otherwise, the configurations:
-* use a nightly build of the ``main`` branch of Clang,
-* execute the tests using the language C++<latest>. This is the version
+- use a nightly build of the `main` branch of Clang,
+- execute the tests using the language C++\<latest>. This is the version
"developed" by the C++ committee.
-.. note:: Updating the Clang nightly builds in the Docker image is a manual
- process and is done at an irregular interval on purpose. When you need to
- have the latest nightly build to test recent Clang changes, ask in the
- ``#libcxx`` channel on `LLVM's Discord server
- <https://discord.gg/jzUbyP26tQ>`__.
+:::{note}
+Updating the Clang nightly builds in the Docker image is a manual
+process and is done at an irregular interval on purpose. When you need to
+have the latest nightly build to test recent Clang changes, ask in the
+`#libcxx` channel on [LLVM's Discord server](https://discord.gg/jzUbyP26tQ).
+:::
-.. [#] There's `LLVM Dev Meeting talk <https://www.youtube.com/watch?v=B7gB6van7Bw>`__
- explaining the benefits of libc++'s pre-commit CI.
+[^footnote-1]: There's [LLVM Dev Meeting talk](https://www.youtube.com/watch?v=B7gB6van7Bw)
+ explaining the benefits of libc++'s pre-commit CI.
-Builds
-------
+### Builds
-Below is a short description of the most interesting CI builds [#]_:
+Below is a short description of the most interesting CI builds [^footnote-2]:
-* ``Format`` runs ``clang-format`` and uploads its output as an artifact. At the
+- `Format` runs `clang-format` and uploads its output as an artifact. At the
moment this build is a soft error and doesn't fail the build.
-* ``Generated output`` runs the ``libcxx-generate-files`` build target and
+
+- `Generated output` runs the `libcxx-generate-files` build target and
tests for non-ASCII characters in libcxx. Some files are excluded since they
use Unicode, mainly tests. The output of these commands are uploaded as
artifact.
-* ``Documentation`` builds the documentation. (This is done early in the build
+
+- `Documentation` builds the documentation. (This is done early in the build
process since it is cheap to run.)
-* ``C++<version>`` these build steps test the various C++ versions, making sure all
+
+- `C++<version>` these build steps test the various C++ versions, making sure all
C++ language versions work with the changes made.
-* ``Clang <version>`` these build steps test whether the changes work with all
+
+- `Clang <version>` these build steps test whether the changes work with all
supported Clang versions.
-* ``Booststrapping build`` builds Clang using the revision of the patch and
+
+- `Booststrapping build` builds Clang using the revision of the patch and
uses that Clang version to build and test libc++. This validates the current
Clang and lib++ are compatible.
When a crash occurs in this build, the crash reproducer is available as an
artifact.
-* ``Modular build`` tests libc++ using Clang modules [#]_.
-* ``GCC <version>`` tests libc++ with the latest stable GCC version. Only C++11
+- `Modular build` tests libc++ using Clang modules [^footnote-3].
+
+- `GCC <version>` tests libc++ with the latest stable GCC version. Only C++11
and the latest C++ version are tested.
-* ``Santitizers`` tests libc++ using the Clang sanitizers.
-* ``Parts disabled`` tests libc++ with certain libc++ features disabled.
-* ``Windows`` tests libc++ using MinGW and clang-cl.
-* ``Apple`` tests libc++ on macOS.
-* ``ARM`` tests libc++ on various Linux ARM platforms.
-* ``AIX`` tests libc++ on AIX.
-.. [#] Not all steps are listed: steps are added and removed when the need arises.
-.. [#] Clang modules are not the same as C++20's modules.
+- `Santitizers` tests libc++ using the Clang sanitizers.
+
+- `Parts disabled` tests libc++ with certain libc++ features disabled.
-Infrastructure
---------------
+- `Windows` tests libc++ using MinGW and clang-cl.
+
+- `Apple` tests libc++ on macOS.
+
+- `ARM` tests libc++ on various Linux ARM platforms.
+
+- `AIX` tests libc++ on AIX.
+
+[^footnote-2]: Not all steps are listed: steps are added and removed when the need arises.
+
+[^footnote-3]: Clang modules are not the same as C++20's modules.
+
+### Infrastructure
The files for the CI infrastructure are split between the llvm-project
and the llvm-zorg repositories. All files of the CI infrastructure in
-the llvm-project are in the directory ``libcxx/utils/ci``. Note that
+the llvm-project are in the directory `libcxx/utils/ci`. Note that
quite a bit of this infrastructure is heavily Linux focused. This is
the platform used by most of libc++'s Buildkite runners and
developers.
-Dockerfile/Container Images
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#### Dockerfile/Container Images
Contains the Docker image for the Ubuntu CI. Because the same Docker image is
-used for the ``main`` and ``release`` branch, it should contain no hard-coded
+used for the `main` and `release` branch, it should contain no hard-coded
versions. It contains the used versions of Clang, various clang-tools,
GCC, and CMake.
-.. note:: This image is pulled from Docker hub and not rebuild when changing
- the Dockerfile.
+:::{note}
+This image is pulled from Docker hub and not rebuild when changing
+the Dockerfile.
+:::
-Updating the CI testing container images
-----------------------------------------
+### Updating the CI testing container images
The libcxx linux premerge testing can run on one of three sets of runner
-groups. The three runner group names are ``llvm-premerge-libcxx-runners``,
-``llvm-premerge-libcxx-release-runners`` and ``llvm-premerge-libcxx-next-runners``.
+groups. The three runner group names are `llvm-premerge-libcxx-runners`,
+`llvm-premerge-libcxx-release-runners` and `llvm-premerge-libcxx-next-runners`.
The runner set currently in use is controlled by the contents of
-https://github.com/llvm/llvm-project/blob/main/.github/workflows/libcxx-pr-conformance-tests.yaml.
-By default, it uses ``llvm-premerge-libcxx-runners``. To switch to one of the
-other runner sets, just replace all uses of ``llvm-premerge-libcxx-runners`` in
+<https://github.com/llvm/llvm-project/blob/main/.github/workflows/libcxx-pr-conformance-tests.yaml>.
+By default, it uses `llvm-premerge-libcxx-runners`. To switch to one of the
+other runner sets, just replace all uses of `llvm-premerge-libcxx-runners` in
the yaml file with the desired runner set.
The container image used by these three runner sets is controlled by the contents
-of the corresponding text files in ``libcxx/utils/ci/images``. The content of these
-files is read by the `Terraform configuration in llvm-zorg
-<https://github.com/llvm/llvm-zorg/blob/main/premerge/premerge_resources/main.tf>`__.
+of the corresponding text files in `libcxx/utils/ci/images`. The content of these
+files is read by the [Terraform configuration in llvm-zorg](https://github.com/llvm/llvm-zorg/blob/main/premerge/premerge_resources/main.tf).
When updating the container image, you can either update just the runner binary (the part
that connects to Github), or you can update everything (tools, etc.). To update the runner
-binary, bump the value of ``GITHUB_RUNNER_VERSION`` in ``libcxx/utils/ci/docker/docker-compose.yml``.
-To update all of the tools, bump ``BASE_IMAGE_VERSION`` to a newer version of the ``libcxx-linux-builder-base``
-image. You can see all versions of that image at https://github.com/llvm/llvm-project/pkgs/container/libcxx-linux-builder-base.
+binary, bump the value of `GITHUB_RUNNER_VERSION` in `libcxx/utils/ci/docker/docker-compose.yml`.
+To update all of the tools, bump `BASE_IMAGE_VERSION` to a newer version of the `libcxx-linux-builder-base`
+image. You can see all versions of that image at <https://github.com/llvm/llvm-project/pkgs/container/libcxx-linux-builder-base>.
-On push to ``main``, a new version of both the ``libcxx-linux-builder`` and the ``libcxx-android-builder``
-images will be built and pushed to https://github.com/llvm/llvm-project/packages.
+On push to `main`, a new version of both the `libcxx-linux-builder` and the `libcxx-android-builder`
+images will be built and pushed to <https://github.com/llvm/llvm-project/packages>.
You can then update the image used by the actual runners by changing the image encoded in
-``libcxx/utils/ci/images`` and asking an LLVM premerge maintainer (a Google employee) to
+`libcxx/utils/ci/images` and asking an LLVM premerge maintainer (a Google employee) to
actually deploy the changes to the GKE cluster via Terraform.
-Monitoring premerge testing performance
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#### Monitoring premerge testing performance
The llvm-premerge-libcxx runners mentioned above collect metrics regarding the
time the tests spend queued up before they start running and also the time it
takes the tests to actually complete running. These metrics are collected and
aggregated (based on stage and PR), and the results can be seen at the
-`Libc++ Premerge Testing dashboard
-<https://llvm.grafana.net/public-dashboards/0bd453e8b3034733a1b0ff8c7728086d>`__
+[Libc++ Premerge Testing dashboard](https://llvm.grafana.net/public-dashboards/0bd453e8b3034733a1b0ff8c7728086d)
.
-run-buildbot-container
-~~~~~~~~~~~~~~~~~~~~~~
+#### run-buildbot-container
Helper script that pulls and runs the Docker image. This image mounts the LLVM
-monorepo at ``/llvm``. This can be used to test with compilers not available on
+monorepo at `/llvm`. This can be used to test with compilers not available on
your system.
-run-buildbot
-~~~~~~~~~~~~
+#### run-buildbot
This is the script executed by the CI runners. This script can be executed
-locally or inside ``run-buildbot-container``. The script must be called with
-the target to test. For example, ``run-buildbot generic-cxx20`` will build
+locally or inside `run-buildbot-container`. The script must be called with
+the target to test. For example, `run-buildbot generic-cxx20` will build
libc++ and test it using C++20.
-.. warning:: This script will overwrite the directory ``<llvm-root>/build/XX``
- where ``XX`` is the target of ``run-buildbot``.
+:::{warning}
+This script will overwrite the directory `<llvm-root>/build/XX`
+where `XX` is the target of `run-buildbot`.
+:::
This script contains as little version information as possible. This makes it
easy to use the script with a different compiler. This allows testing a
@@ -336,14 +326,14 @@ combination not in the libc++ CI. It can be used to add a new (temporary)
job to the CI. For example, testing the C++17 build with Clang-14 can be done
like:
-.. code-block:: bash
+```bash
+CC=clang-14 CXX=clang++-14 run-buildbot generic-cxx17
+```
- CC=clang-14 CXX=clang++-14 run-buildbot generic-cxx17
-
-buildkite-pipeline.yml
-~~~~~~~~~~~~~~~~~~~~~~
+#### buildkite-pipeline.yml
Contains the jobs executed in the CI. This file contains the version
information of the jobs being executed. Since this script differs between the
-``main`` and ``release`` branch, both branches can use different compiler
+`main` and `release` branch, both branches can use different compiler
versions.
+
diff --git a/libcxx/docs/Contributing/NewStandardProcedure.md b/libcxx/docs/Contributing/NewStandardProcedure.md
index 3ba170d50842f..16f8c5432fbfa 100644
--- a/libcxx/docs/Contributing/NewStandardProcedure.md
+++ b/libcxx/docs/Contributing/NewStandardProcedure.md
@@ -1,8 +1,6 @@
-.. _NewStandardProcedure:
+(newstandardprocedure)=
-==========================
-New standard procedure
-==========================
+# New standard procedure
Roughly every three years, WG21 finishes a version of the C++ standard and starts
working on the next one. This page describes the procedure that libc++ developers
@@ -11,23 +9,28 @@ Since introducing a new Standard does not happen often, this document may not be
fully exhaustive and is meant as a starting point. Keep it up-to-date when drift
is noticed.
-* Create status pages for tracking conformance of C++ZZ (``CxxZZIssues.csv``, ``CxxZZPapers.csv`` and related).
-* Create the associated views in the `libc++ Conformance project <https://github.com/orgs/llvm/projects/31>`__.
-* CI updates
+- Create status pages for tracking conformance of C++ZZ (`CxxZZIssues.csv`, `CxxZZPapers.csv` and related).
- * Add a new job testing C++ZZ
- * Move jobs that specify the previous standard over to C++ZZ (except jobs which intend to test older
+- Create the associated views in the [libc++ Conformance project](https://github.com/orgs/llvm/projects/31).
+
+- CI updates
+
+ - Add a new job testing C++ZZ
+ - Move jobs that specify the previous standard over to C++ZZ (except jobs which intend to test older
standard specifically)
-* Teach the test suite about C++ZZ (for example ``--param std=c++zz`` in the ``Lit`` configuration)
-* Add files to track the transitive includes for C++ZZ
-* Add a new version for ``_LIBCPP_STD_VER`` and ``TEST_STD_VER`` for the test suite
+- Teach the test suite about C++ZZ (for example `--param std=c++zz` in the `Lit` configuration)
+
+- Add files to track the transitive includes for C++ZZ
+
+- Add a new version for `_LIBCPP_STD_VER` and `TEST_STD_VER` for the test suite
+
+ - Note that we don't add various versioned macros until we need them (e.g. `_LIBCPP_CONSTEXPR_SINCE_CXXZZ`)
- * Note that we don't add various versioned macros until we need them (e.g. ``_LIBCPP_CONSTEXPR_SINCE_CXXZZ``)
+- Feature-test macros:
-* Feature-test macros:
+ - Update the FTM generation script to account for C++ZZ
+ - Add any missing FTMs for the new standard version in the FTM generation script
+ - Regenerate the FTM files
+ - Update the tests for the FTM generation script itself
- * Update the FTM generation script to account for C++ZZ
- * Add any missing FTMs for the new standard version in the FTM generation script
- * Regenerate the FTM files
- * Update the tests for the FTM generation script itself
diff --git a/libcxx/docs/Contributing/PostMeetingProcedure.md b/libcxx/docs/Contributing/PostMeetingProcedure.md
index a7acaa1c6a4c0..d3b1fba0d026e 100644
--- a/libcxx/docs/Contributing/PostMeetingProcedure.md
+++ b/libcxx/docs/Contributing/PostMeetingProcedure.md
@@ -1,8 +1,6 @@
-.. _PostMeetingProcedure:
+(postmeetingprocedure)=
-===========================
-Post-meeting procedure
-===========================
+# Post-meeting procedure
The C++ standards committee (WG21) meets several times a year. Each plenary
session adopts new papers and Library Working Group (LWG) issues that libc++
@@ -10,26 +8,23 @@ needs to track. This page describes the procedure that libc++ developers must
follow after each WG21 plenary meeting to keep the conformance trackers in
sync with what the committee voted in.
-The tracker files
-=================
+## The tracker files
For each version of the C++ standard, libc++ maintains some CSV files under
-``libcxx/docs/Status/``:
+`libcxx/docs/Status/`:
-* ``Cxx<NN>Papers.csv`` — every WG21 paper with library impact that targets
+- `Cxx<NN>Papers.csv` — every WG21 paper with library impact that targets
this standard version.
-* ``Cxx<NN>Issues.csv`` — every LWG issue that targets this standard version.
+- `Cxx<NN>Issues.csv` — every LWG issue that targets this standard version.
-Each row in the CSVs corresponds to one Github tracking issue on ``llvm/llvm-project``.
-Those tracking issues are also linked to the `libc++ Standards Conformance
-<https://github.com/orgs/llvm/projects/31>`__ project. Together, the CSVs, the tracking
-issues and the project board are kept in sync by the ``libcxx/utils/conformance`` script.
+Each row in the CSVs corresponds to one Github tracking issue on `llvm/llvm-project`.
+Those tracking issues are also linked to the [libc++ Standards Conformance](https://github.com/orgs/llvm/projects/31) project. Together, the CSVs, the tracking
+issues and the project board are kept in sync by the `libcxx/utils/conformance` script.
When tracking new items after a plenary vote, the CSV files should be updated first, and
then the Github issues should be created from the CSV files using the script.
-Deciding what plenary motions to track
-======================================
+## Deciding what plenary motions to track
After each meeting, look at the meeting's straw polls page (requires being a member
of WG21) and decide what needs to be added to the trackers. Generally speaking, we
@@ -41,60 +36,66 @@ Also note that LWG and CWG issues are respectively bundled as a single motion/pa
on the straw polls page. The papers in these motions contain the actual issues that
we should be tracking.
-To confirm that an issue or paper was approved in plenary, ``https://wg21.link/<PAPER>/status``
+To confirm that an issue or paper was approved in plenary, `https://wg21.link/<PAPER>/status`
can be used. That will link to the Github issue tracking the paper in WG21's system,
-where papers approved in plenary have the ``plenary-approved`` label.
+where papers approved in plenary have the `plenary-approved` label.
-Updating the CSV files
-======================
+## Updating the CSV files
For each new paper or issue to track, add a row following the convention used in existing
files. If a paper was voted as a Defect Report, mention it in the notes. The syntax of the
-file can be validated with::
+file can be validated with:
- libcxx/utils/conformance csv validate libcxx/docs/Status/Cxx<NN>Papers.csv \
- libcxx/docs/Status/Cxx<NN>Issues.csv
+```
+libcxx/utils/conformance csv validate libcxx/docs/Status/Cxx<NN>Papers.csv \
+ libcxx/docs/Status/Cxx<NN>Issues.csv
+```
Commit the CSV changes and related updates as a first PR. The Github tracking issues are
created in a separate step.
-Link stray Github issues
-========================
+## Link stray Github issues
People sometimes create Github issues to track standard papers outside of the workflow
described here. While that should be discouraged as only plenary-voted papers should be
tracked and this workflow should be used, issues created outside of this workflow should
-still be linked to prevent duplicates and confusion. This can be done with::
+still be linked to prevent duplicates and confusion. This can be done with:
- libcxx/utils/conformance github find-unlinked --labels wg21-paper --labels lwg-issue
+```
+libcxx/utils/conformance github find-unlinked --labels wg21-paper --labels lwg-issue
+```
This will find existing issues with the given labels that are not linked to the Github project
tracking conformance. They can then be linked manually.
-Create the Github tracking issues
-==================================
+## Create the Github tracking issues
Once the CSV files are committed and any stray issues have been linked, the remaining missing
-Github issues can be created using ``libcxx/utils/conformance``. The script lists every issue
+Github issues can be created using `libcxx/utils/conformance`. The script lists every issue
it would create from the CSV (skipping rows that are already tracked) and asks for a confirmation
before creating them. The issue title, body and labels are all populated automatically, and they
-are appropriately linked to the libc++ conformance project. Run it once per CSV::
+are appropriately linked to the libc++ conformance project. Run it once per CSV:
- libcxx/utils/conformance github create libcxx/docs/Status/Cxx<NN>Papers.csv \
- --labels=wg21-paper --labels=c++<NN>
+```
+libcxx/utils/conformance github create libcxx/docs/Status/Cxx<NN>Papers.csv \
+ --labels=wg21-paper --labels=c++<NN>
- libcxx/utils/conformance github create libcxx/docs/Status/Cxx<NN>Issues.csv \
- --labels=lwg-issue --labels=c++<NN>
+libcxx/utils/conformance github create libcxx/docs/Status/Cxx<NN>Issues.csv \
+ --labels=lwg-issue --labels=c++<NN>
+```
-The CSV ``Notes`` column is written to the issue body between ``BEGIN-RST-NOTES``/``END-RST-NOTES``
-markers so that ``csv synchronize`` can round-trip it back into the CSV.
+The CSV `Notes` column is written to the issue body between `BEGIN-RST-NOTES`/`END-RST-NOTES`
+markers so that `csv synchronize` can round-trip it back into the CSV.
-Once the issues have been created, populate the ``GitHub issue`` column of each CSV row::
+Once the issues have been created, populate the `GitHub issue` column of each CSV row:
- libcxx/utils/conformance csv synchronize libcxx/docs/Status/Cxx<NN>Papers.csv \
- -o libcxx/docs/Status/Cxx<NN>Papers.csv
+```
+libcxx/utils/conformance csv synchronize libcxx/docs/Status/Cxx<NN>Papers.csv \
+ -o libcxx/docs/Status/Cxx<NN>Papers.csv
- libcxx/utils/conformance csv synchronize libcxx/docs/Status/Cxx<NN>Issues.csv \
- -o libcxx/docs/Status/Cxx<NN>Issues.csv
+libcxx/utils/conformance csv synchronize libcxx/docs/Status/Cxx<NN>Issues.csv \
+ -o libcxx/docs/Status/Cxx<NN>Issues.csv
+```
This can then be committed as a follow-up PR.
+
diff --git a/libcxx/docs/Contributing/ReleaseProcedure.md b/libcxx/docs/Contributing/ReleaseProcedure.md
index 69cc0c340ecc2..50dd2fe308eb3 100644
--- a/libcxx/docs/Contributing/ReleaseProcedure.md
+++ b/libcxx/docs/Contributing/ReleaseProcedure.md
@@ -1,65 +1,60 @@
-.. _ReleaseProcedure:
+(releaseprocedure)=
-=================
-Release procedure
-=================
+# Release procedure
The LLVM project creates a new release twice a year following a fixed
-`schedule <https://llvm.org/docs/HowToReleaseLLVM.html#annual-release-schedule>`__.
+[schedule](https://llvm.org/docs/HowToReleaseLLVM.html#annual-release-schedule).
This page describes the libc++ procedure for that release.
-Prepare the release
-===================
+## Prepare the release
It should be finished before the Release managers start branching the new
release:
-* Make sure ``libcxx/docs/ReleaseNotes/<VERSION>.rst`` is up to date. Typically
+- Make sure `libcxx/docs/ReleaseNotes/<VERSION>.rst` is up to date. Typically
this file is updated when contributing patches. Still there might be some
information added regarding the general improvements of larger projects.
-* Make sure the deprecated features on this page are up to date. Typically a
+- Make sure the deprecated features on this page are up to date. Typically a
new deprecated feature should be added to the release notes and this page.
However this should be verified so removals won't get forgotten.
-* Make sure the latest Unicode version is used. The C++ Standard
- `refers to the Unicode Standard <https://wg21.link/intro.refs#1.10>`__
+- Make sure the latest Unicode version is used. The C++ Standard
+ [refers to the Unicode Standard](https://wg21.link/intro.refs#1.10)
- ``The Unicode Consortium. The Unicode Standard. Available from: https://www.unicode.org/versions/latest/``
+ `The Unicode Consortium. The Unicode Standard. Available from: https://www.unicode.org/versions/latest/`
Typically the Unicode Consortium has one release per year. The libc++
format library uses the Unicode Standard. Libc++ should be updated to the
latest Unicode version. Updating means using the latest data files and, if
needed, adapting the code to changes in the Unicode Standard.
-* Make sure all libc++ supported compilers in the CI are updated to their
+- Make sure all libc++ supported compilers in the CI are updated to their
latest release.
-After the branch is created
-===========================
+## After the branch is created
After branching for an LLVM release:
-1. Update ``_LIBCPP_VERSION`` in ``libcxx/include/__config``
-2. Update the version number in ``libcxx/docs/conf.py``
-3. Update ``_LIBCPPABI_VERSION`` in ``libcxxabi/include/cxxabi.h``
-4. Update ``_LIBUNWIND_VERSION`` in ``libunwind/include/__libunwind_config.h``
+1. Update `_LIBCPP_VERSION` in `libcxx/include/__config`
+2. Update the version number in `libcxx/docs/conf.py`
+3. Update `_LIBCPPABI_VERSION` in `libcxxabi/include/cxxabi.h`
+4. Update `_LIBUNWIND_VERSION` in `libunwind/include/__libunwind_config.h`
5. Create a release notes file for the next release from the previous ones and point to it from
- ``libcxx/docs/ReleaseNotes.rst``. Remove entries that do not apply anymore, but keep in mind
+ `libcxx/docs/ReleaseNotes.rst`. Remove entries that do not apply anymore, but keep in mind
that some entries (such as upcoming deprecations) may still apply, may need rewording and may
also require follow up PRs to implement.
-6. Update the set of runners targeted by the CI on the release branch to ``llvm-premerge-libcxx-release-runners``, and
+6. Update the set of runners targeted by the CI on the release branch to `llvm-premerge-libcxx-release-runners`, and
make sure that runner set is using the appropriate image. This ensures that the release branch CI keeps working even
if the main branch starts using newer images.
7. Update the pre-commit CI to use the new ToT version of Clang available from Compiler Explorer. In order
to make sure patches can be backported to the release branch, we don't remove the oldest compiler yet.
-Post release
-============
+## Post release
Once the release is done and cherry-picks are not expected, we remove support for the ToT - 3 version Clang.
We also perform associated cleanups:
-- Search for ``LLVM RELEASE`` and address their comments
-- Search for test that have ``UNSUPPORTED`` or ``XFAIL`` for the no longer supported version
-- Search for ``TODO(LLVM-<ToT>)`` and address their comments
+- Search for `LLVM RELEASE` and address their comments
+- Search for test that have `UNSUPPORTED` or `XFAIL` for the no longer supported version
+- Search for `TODO(LLVM-<ToT>)` and address their comments
diff --git a/libcxx/docs/DesignDocs/ABIVersioning.md b/libcxx/docs/DesignDocs/ABIVersioning.md
index ad7218687d55f..40c85d71f56eb 100644
--- a/libcxx/docs/DesignDocs/ABIVersioning.md
+++ b/libcxx/docs/DesignDocs/ABIVersioning.md
@@ -1,32 +1,28 @@
-
-====================
-Libc++ ABI stability
-====================
+# Libc++ ABI stability
Libc++ aims to preserve a stable ABI to avoid subtle bugs when code built under the old ABI
is linked with code built under the new ABI. At the same time, libc++ wants to make
ABI-breaking improvements and bugfixes in scenarios where the user doesn't mind ABI breaks.
To support both cases, libc++ allows specifying an ABI version at
-build time. The version is defined with CMake option ``LIBCXX_ABI_VERSION``.
-Currently supported values are ``1`` (the stable default)
-and ``2`` (the unstable "next" version). At some point "ABI version 2" will be
-frozen and new ABI-breaking changes will start being applied to version ``3``;
+build time. The version is defined with CMake option `LIBCXX_ABI_VERSION`.
+Currently supported values are `1` (the stable default)
+and `2` (the unstable "next" version). At some point "ABI version 2" will be
+frozen and new ABI-breaking changes will start being applied to version `3`;
but this has not happened yet.
-To always use the most cutting-edge, most unstable ABI (which is currently ``2``
-but at some point will become ``3``), set the CMake option ``LIBCXX_ABI_UNSTABLE``.
+To always use the most cutting-edge, most unstable ABI (which is currently `2`
+but at some point will become `3`), set the CMake option `LIBCXX_ABI_UNSTABLE`.
Internally, each ABI-changing feature is placed under its own C++ macro,
-``_LIBCPP_ABI_XXX``. These macros' definitions are controlled by the C++ macro
-``_LIBCPP_ABI_VERSION``, which is controlled by the ``LIBCXX_ABI_VERSION`` set
+`_LIBCPP_ABI_XXX`. These macros' definitions are controlled by the C++ macro
+`_LIBCPP_ABI_VERSION`, which is controlled by the `LIBCXX_ABI_VERSION` set
at build time. Libc++ does not intend users to interact with these C++ macros
directly.
------------------
-MSVC environments
------------------
+## MSVC environments
The exception to this is MSVC environments. Libc++ does not currently have users
that require a stable ABI in MSVC environments, so MSVC-only changes may be
applied unconditionally.
+
diff --git a/libcxx/docs/DesignDocs/AtomicDesign.md b/libcxx/docs/DesignDocs/AtomicDesign.md
index 4b28ab2a8218a..9a6ba94e5196d 100644
--- a/libcxx/docs/DesignDocs/AtomicDesign.md
+++ b/libcxx/docs/DesignDocs/AtomicDesign.md
@@ -1,463 +1,458 @@
-
-====================
-``<atomic>`` Design
-====================
+# `<atomic>` Design
There were originally 3 designs under consideration. They differ in where most
of the implementation work is done. The functionality exposed to the customer
should be identical (and conforming) for all three designs.
+## Design A: Minimal work for the library
-Design A: Minimal work for the library
-======================================
The compiler supplies all of the intrinsics as described below. This list of
intrinsics roughly parallels the requirements of the C and C++ atomics proposals.
The C and C++ library implementations simply drop through to these intrinsics.
Anything the platform does not support in hardware, the compiler
arranges for a (compiler-rt) library call to be made which will do the job with
a mutex, and in this case ignoring the memory ordering parameter (effectively
-implementing ``memory_order_seq_cst``).
+implementing `memory_order_seq_cst`).
Ultimate efficiency is preferred over run time error checking. Undefined
behavior is acceptable when the inputs do not conform as defined below.
-.. code-block:: cpp
-
- // In every intrinsic signature below, type* atomic_obj may be a pointer to a
- // volatile-qualified type. Memory ordering values map to the following meanings:
- // memory_order_relaxed == 0
- // memory_order_consume == 1
- // memory_order_acquire == 2
- // memory_order_release == 3
- // memory_order_acq_rel == 4
- // memory_order_seq_cst == 5
-
- // type must be trivially copyable
- // type represents a "type argument"
- bool __atomic_is_lock_free(type);
-
- // type must be trivially copyable
- // Behavior is defined for mem_ord = 0, 1, 2, 5
- type __atomic_load(const type* atomic_obj, int mem_ord);
-
- // type must be trivially copyable
- // Behavior is defined for mem_ord = 0, 3, 5
- void __atomic_store(type* atomic_obj, type desired, int mem_ord);
-
- // type must be trivially copyable
- // Behavior is defined for mem_ord = [0 ... 5]
- type __atomic_exchange(type* atomic_obj, type desired, int mem_ord);
-
- // type must be trivially copyable
- // Behavior is defined for mem_success = [0 ... 5],
- // mem_failure <= mem_success
- // mem_failure != 3
- // mem_failure != 4
- bool __atomic_compare_exchange_strong(type* atomic_obj,
- type* expected, type desired,
- int mem_success, int mem_failure);
-
- // type must be trivially copyable
- // Behavior is defined for mem_success = [0 ... 5],
- // mem_failure <= mem_success
- // mem_failure != 3
- // mem_failure != 4
- bool __atomic_compare_exchange_weak(type* atomic_obj,
- type* expected, type desired,
- int mem_success, int mem_failure);
-
- // type is one of: char, signed char, unsigned char, short, unsigned short, int,
- // unsigned int, long, unsigned long, long long, unsigned long long,
- // char16_t, char32_t, wchar_t
- // Behavior is defined for mem_ord = [0 ... 5]
- type __atomic_fetch_add(type* atomic_obj, type operand, int mem_ord);
-
- // type is one of: char, signed char, unsigned char, short, unsigned short, int,
- // unsigned int, long, unsigned long, long long, unsigned long long,
- // char16_t, char32_t, wchar_t
- // Behavior is defined for mem_ord = [0 ... 5]
- type __atomic_fetch_sub(type* atomic_obj, type operand, int mem_ord);
-
- // type is one of: char, signed char, unsigned char, short, unsigned short, int,
- // unsigned int, long, unsigned long, long long, unsigned long long,
- // char16_t, char32_t, wchar_t
- // Behavior is defined for mem_ord = [0 ... 5]
- type __atomic_fetch_and(type* atomic_obj, type operand, int mem_ord);
-
- // type is one of: char, signed char, unsigned char, short, unsigned short, int,
- // unsigned int, long, unsigned long, long long, unsigned long long,
- // char16_t, char32_t, wchar_t
- // Behavior is defined for mem_ord = [0 ... 5]
- type __atomic_fetch_or(type* atomic_obj, type operand, int mem_ord);
-
- // type is one of: char, signed char, unsigned char, short, unsigned short, int,
- // unsigned int, long, unsigned long, long long, unsigned long long,
- // char16_t, char32_t, wchar_t
- // Behavior is defined for mem_ord = [0 ... 5]
- type __atomic_fetch_xor(type* atomic_obj, type operand, int mem_ord);
-
- // Behavior is defined for mem_ord = [0 ... 5]
- void* __atomic_fetch_add(void** atomic_obj, ptrdiff_t operand, int mem_ord);
- void* __atomic_fetch_sub(void** atomic_obj, ptrdiff_t operand, int mem_ord);
-
- // Behavior is defined for mem_ord = [0 ... 5]
- void __atomic_thread_fence(int mem_ord);
- void __atomic_signal_fence(int mem_ord);
-
-If desired the intrinsics taking a single ``mem_ord`` parameter can default
+```cpp
+// In every intrinsic signature below, type* atomic_obj may be a pointer to a
+// volatile-qualified type. Memory ordering values map to the following meanings:
+// memory_order_relaxed == 0
+// memory_order_consume == 1
+// memory_order_acquire == 2
+// memory_order_release == 3
+// memory_order_acq_rel == 4
+// memory_order_seq_cst == 5
+
+// type must be trivially copyable
+// type represents a "type argument"
+bool __atomic_is_lock_free(type);
+
+// type must be trivially copyable
+// Behavior is defined for mem_ord = 0, 1, 2, 5
+type __atomic_load(const type* atomic_obj, int mem_ord);
+
+// type must be trivially copyable
+// Behavior is defined for mem_ord = 0, 3, 5
+void __atomic_store(type* atomic_obj, type desired, int mem_ord);
+
+// type must be trivially copyable
+// Behavior is defined for mem_ord = [0 ... 5]
+type __atomic_exchange(type* atomic_obj, type desired, int mem_ord);
+
+// type must be trivially copyable
+// Behavior is defined for mem_success = [0 ... 5],
+// mem_failure <= mem_success
+// mem_failure != 3
+// mem_failure != 4
+bool __atomic_compare_exchange_strong(type* atomic_obj,
+ type* expected, type desired,
+ int mem_success, int mem_failure);
+
+// type must be trivially copyable
+// Behavior is defined for mem_success = [0 ... 5],
+// mem_failure <= mem_success
+// mem_failure != 3
+// mem_failure != 4
+bool __atomic_compare_exchange_weak(type* atomic_obj,
+ type* expected, type desired,
+ int mem_success, int mem_failure);
+
+// type is one of: char, signed char, unsigned char, short, unsigned short, int,
+// unsigned int, long, unsigned long, long long, unsigned long long,
+// char16_t, char32_t, wchar_t
+// Behavior is defined for mem_ord = [0 ... 5]
+type __atomic_fetch_add(type* atomic_obj, type operand, int mem_ord);
+
+// type is one of: char, signed char, unsigned char, short, unsigned short, int,
+// unsigned int, long, unsigned long, long long, unsigned long long,
+// char16_t, char32_t, wchar_t
+// Behavior is defined for mem_ord = [0 ... 5]
+type __atomic_fetch_sub(type* atomic_obj, type operand, int mem_ord);
+
+// type is one of: char, signed char, unsigned char, short, unsigned short, int,
+// unsigned int, long, unsigned long, long long, unsigned long long,
+// char16_t, char32_t, wchar_t
+// Behavior is defined for mem_ord = [0 ... 5]
+type __atomic_fetch_and(type* atomic_obj, type operand, int mem_ord);
+
+// type is one of: char, signed char, unsigned char, short, unsigned short, int,
+// unsigned int, long, unsigned long, long long, unsigned long long,
+// char16_t, char32_t, wchar_t
+// Behavior is defined for mem_ord = [0 ... 5]
+type __atomic_fetch_or(type* atomic_obj, type operand, int mem_ord);
+
+// type is one of: char, signed char, unsigned char, short, unsigned short, int,
+// unsigned int, long, unsigned long, long long, unsigned long long,
+// char16_t, char32_t, wchar_t
+// Behavior is defined for mem_ord = [0 ... 5]
+type __atomic_fetch_xor(type* atomic_obj, type operand, int mem_ord);
+
+// Behavior is defined for mem_ord = [0 ... 5]
+void* __atomic_fetch_add(void** atomic_obj, ptrdiff_t operand, int mem_ord);
+void* __atomic_fetch_sub(void** atomic_obj, ptrdiff_t operand, int mem_ord);
+
+// Behavior is defined for mem_ord = [0 ... 5]
+void __atomic_thread_fence(int mem_ord);
+void __atomic_signal_fence(int mem_ord);
+```
+
+If desired the intrinsics taking a single `mem_ord` parameter can default
this argument to 5.
-If desired the intrinsics taking two ordering parameters can default ``mem_success``
-to 5, and ``mem_failure`` to ``translate_memory_order(mem_success)`` where
-``translate_memory_order(mem_success)`` is defined as:
-
-.. code-block:: cpp
+If desired the intrinsics taking two ordering parameters can default `mem_success`
+to 5, and `mem_failure` to `translate_memory_order(mem_success)` where
+`translate_memory_order(mem_success)` is defined as:
- int translate_memory_order(int o) {
- switch (o) {
- case 4:
- return 2;
- case 3:
- return 0;
- }
- return o;
+```cpp
+int translate_memory_order(int o) {
+ switch (o) {
+ case 4:
+ return 2;
+ case 3:
+ return 0;
}
+ return o;
+}
+```
Below are representative C++ implementations of all of the operations. Their
purpose is to document the desired semantics of each operation, assuming
-``memory_order_seq_cst``. This is essentially the code that will be called
+`memory_order_seq_cst`. This is essentially the code that will be called
if the front end calls out to compiler-rt.
-.. code-block:: cpp
-
- template <class T>
- T __atomic_load(T const volatile* obj) {
- unique_lock<mutex> _(some_mutex);
- return *obj;
- }
-
- template <class T>
- void __atomic_store(T volatile* obj, T desr) {
- unique_lock<mutex> _(some_mutex);
- *obj = desr;
- }
-
- template <class T>
- T __atomic_exchange(T volatile* obj, T desr) {
- unique_lock<mutex> _(some_mutex);
- T r = *obj;
- *obj = desr;
- return r;
- }
-
- template <class T>
- bool __atomic_compare_exchange_strong(T volatile* obj, T* exp, T desr) {
- unique_lock<mutex> _(some_mutex);
- if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) // if (*obj == *exp)
- {
- std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); // *obj = desr;
- return true;
- }
- std::memcpy(exp, const_cast<T*>(obj), sizeof(T)); // *exp = *obj;
- return false;
- }
-
- // May spuriously return false (even if *obj == *exp)
- template <class T>
- bool __atomic_compare_exchange_weak(T volatile* obj, T* exp, T desr) {
- unique_lock<mutex> _(some_mutex);
- if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) // if (*obj == *exp)
- {
- std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); // *obj = desr;
- return true;
- }
- std::memcpy(exp, const_cast<T*>(obj), sizeof(T)); // *exp = *obj;
- return false;
- }
-
- template <class T>
- T __atomic_fetch_add(T volatile* obj, T operand) {
- unique_lock<mutex> _(some_mutex);
- T r = *obj;
- *obj += operand;
- return r;
- }
-
- template <class T>
- T __atomic_fetch_sub(T volatile* obj, T operand) {
- unique_lock<mutex> _(some_mutex);
- T r = *obj;
- *obj -= operand;
- return r;
- }
-
- template <class T>
- T __atomic_fetch_and(T volatile* obj, T operand) {
- unique_lock<mutex> _(some_mutex);
- T r = *obj;
- *obj &= operand;
- return r;
- }
-
- template <class T>
- T __atomic_fetch_or(T volatile* obj, T operand) {
- unique_lock<mutex> _(some_mutex);
- T r = *obj;
- *obj |= operand;
- return r;
- }
-
- template <class T>
- T __atomic_fetch_xor(T volatile* obj, T operand) {
- unique_lock<mutex> _(some_mutex);
- T r = *obj;
- *obj ^= operand;
- return r;
- }
-
- void* __atomic_fetch_add(void* volatile* obj, ptrdiff_t operand) {
- unique_lock<mutex> _(some_mutex);
- void* r = *obj;
- (char*&)(*obj) += operand;
- return r;
- }
-
- void* __atomic_fetch_sub(void* volatile* obj, ptrdiff_t operand) {
- unique_lock<mutex> _(some_mutex);
- void* r = *obj;
- (char*&)(*obj) -= operand;
- return r;
- }
-
- void __atomic_thread_fence() {
- unique_lock<mutex> _(some_mutex);
- }
-
- void __atomic_signal_fence() {
- unique_lock<mutex> _(some_mutex);
- }
-
+```cpp
+template <class T>
+T __atomic_load(T const volatile* obj) {
+ unique_lock<mutex> _(some_mutex);
+ return *obj;
+}
+
+template <class T>
+void __atomic_store(T volatile* obj, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ *obj = desr;
+}
+
+template <class T>
+T __atomic_exchange(T volatile* obj, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj = desr;
+ return r;
+}
+
+template <class T>
+bool __atomic_compare_exchange_strong(T volatile* obj, T* exp, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) // if (*obj == *exp)
+ {
+ std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); // *obj = desr;
+ return true;
+ }
+ std::memcpy(exp, const_cast<T*>(obj), sizeof(T)); // *exp = *obj;
+ return false;
+}
+
+// May spuriously return false (even if *obj == *exp)
+template <class T>
+bool __atomic_compare_exchange_weak(T volatile* obj, T* exp, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) // if (*obj == *exp)
+ {
+ std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); // *obj = desr;
+ return true;
+ }
+ std::memcpy(exp, const_cast<T*>(obj), sizeof(T)); // *exp = *obj;
+ return false;
+}
+
+template <class T>
+T __atomic_fetch_add(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj += operand;
+ return r;
+}
+
+template <class T>
+T __atomic_fetch_sub(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj -= operand;
+ return r;
+}
+
+template <class T>
+T __atomic_fetch_and(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj &= operand;
+ return r;
+}
+
+template <class T>
+T __atomic_fetch_or(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj |= operand;
+ return r;
+}
+
+template <class T>
+T __atomic_fetch_xor(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj ^= operand;
+ return r;
+}
+
+void* __atomic_fetch_add(void* volatile* obj, ptrdiff_t operand) {
+ unique_lock<mutex> _(some_mutex);
+ void* r = *obj;
+ (char*&)(*obj) += operand;
+ return r;
+}
+
+void* __atomic_fetch_sub(void* volatile* obj, ptrdiff_t operand) {
+ unique_lock<mutex> _(some_mutex);
+ void* r = *obj;
+ (char*&)(*obj) -= operand;
+ return r;
+}
+
+void __atomic_thread_fence() {
+ unique_lock<mutex> _(some_mutex);
+}
+
+void __atomic_signal_fence() {
+ unique_lock<mutex> _(some_mutex);
+}
+```
+
+## Design B: Something in between
-Design B: Something in between
-==============================
This is a variation of design A which puts the burden on the library to arrange
for the correct manipulation of the run time memory ordering arguments, and only
calls the compiler for well-defined memory orderings. I think of this design as
the worst of A and C, instead of the best of A and C. But I offer it as an
option in the spirit of completeness.
-.. code-block:: cpp
-
- // type must be trivially copyable
- bool __atomic_is_lock_free(const type* atomic_obj);
-
- // type must be trivially copyable
- type __atomic_load_relaxed(const volatile type* atomic_obj);
- type __atomic_load_consume(const volatile type* atomic_obj);
- type __atomic_load_acquire(const volatile type* atomic_obj);
- type __atomic_load_seq_cst(const volatile type* atomic_obj);
-
- // type must be trivially copyable
- type __atomic_store_relaxed(volatile type* atomic_obj, type desired);
- type __atomic_store_release(volatile type* atomic_obj, type desired);
- type __atomic_store_seq_cst(volatile type* atomic_obj, type desired);
-
- // type must be trivially copyable
- type __atomic_exchange_relaxed(volatile type* atomic_obj, type desired);
- type __atomic_exchange_consume(volatile type* atomic_obj, type desired);
- type __atomic_exchange_acquire(volatile type* atomic_obj, type desired);
- type __atomic_exchange_release(volatile type* atomic_obj, type desired);
- type __atomic_exchange_acq_rel(volatile type* atomic_obj, type desired);
- type __atomic_exchange_seq_cst(volatile type* atomic_obj, type desired);
-
- // type must be trivially copyable
- bool __atomic_compare_exchange_strong_relaxed_relaxed(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_consume_relaxed(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_consume_consume(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_acquire_relaxed(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_acquire_consume(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_acquire_acquire(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_release_relaxed(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_release_consume(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_release_acquire(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_acq_rel_relaxed(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_acq_rel_consume(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_acq_rel_acquire(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_seq_cst_relaxed(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_seq_cst_consume(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_seq_cst_acquire(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_strong_seq_cst_seq_cst(volatile type* atomic_obj,
- type* expected,
- type desired);
-
- // type must be trivially copyable
- bool __atomic_compare_exchange_weak_relaxed_relaxed(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_consume_relaxed(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_consume_consume(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_acquire_relaxed(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_acquire_consume(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_acquire_acquire(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_release_relaxed(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_release_consume(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_release_acquire(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_acq_rel_relaxed(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_acq_rel_consume(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_acq_rel_acquire(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_seq_cst_relaxed(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_seq_cst_consume(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_seq_cst_acquire(volatile type* atomic_obj,
- type* expected,
- type desired);
- bool __atomic_compare_exchange_weak_seq_cst_seq_cst(volatile type* atomic_obj,
- type* expected,
- type desired);
-
- // type is one of: char, signed char, unsigned char, short, unsigned short, int,
- // unsigned int, long, unsigned long, long long, unsigned long long,
- // char16_t, char32_t, wchar_t
- type __atomic_fetch_add_relaxed(volatile type* atomic_obj, type operand);
- type __atomic_fetch_add_consume(volatile type* atomic_obj, type operand);
- type __atomic_fetch_add_acquire(volatile type* atomic_obj, type operand);
- type __atomic_fetch_add_release(volatile type* atomic_obj, type operand);
- type __atomic_fetch_add_acq_rel(volatile type* atomic_obj, type operand);
- type __atomic_fetch_add_seq_cst(volatile type* atomic_obj, type operand);
-
- // type is one of: char, signed char, unsigned char, short, unsigned short, int,
- // unsigned int, long, unsigned long, long long, unsigned long long,
- // char16_t, char32_t, wchar_t
- type __atomic_fetch_sub_relaxed(volatile type* atomic_obj, type operand);
- type __atomic_fetch_sub_consume(volatile type* atomic_obj, type operand);
- type __atomic_fetch_sub_acquire(volatile type* atomic_obj, type operand);
- type __atomic_fetch_sub_release(volatile type* atomic_obj, type operand);
- type __atomic_fetch_sub_acq_rel(volatile type* atomic_obj, type operand);
- type __atomic_fetch_sub_seq_cst(volatile type* atomic_obj, type operand);
-
- // type is one of: char, signed char, unsigned char, short, unsigned short, int,
- // unsigned int, long, unsigned long, long long, unsigned long long,
- // char16_t, char32_t, wchar_t
- type __atomic_fetch_and_relaxed(volatile type* atomic_obj, type operand);
- type __atomic_fetch_and_consume(volatile type* atomic_obj, type operand);
- type __atomic_fetch_and_acquire(volatile type* atomic_obj, type operand);
- type __atomic_fetch_and_release(volatile type* atomic_obj, type operand);
- type __atomic_fetch_and_acq_rel(volatile type* atomic_obj, type operand);
- type __atomic_fetch_and_seq_cst(volatile type* atomic_obj, type operand);
-
- // type is one of: char, signed char, unsigned char, short, unsigned short, int,
- // unsigned int, long, unsigned long, long long, unsigned long long,
- // char16_t, char32_t, wchar_t
- type __atomic_fetch_or_relaxed(volatile type* atomic_obj, type operand);
- type __atomic_fetch_or_consume(volatile type* atomic_obj, type operand);
- type __atomic_fetch_or_acquire(volatile type* atomic_obj, type operand);
- type __atomic_fetch_or_release(volatile type* atomic_obj, type operand);
- type __atomic_fetch_or_acq_rel(volatile type* atomic_obj, type operand);
- type __atomic_fetch_or_seq_cst(volatile type* atomic_obj, type operand);
-
- // type is one of: char, signed char, unsigned char, short, unsigned short, int,
- // unsigned int, long, unsigned long, long long, unsigned long long,
- // char16_t, char32_t, wchar_t
- type __atomic_fetch_xor_relaxed(volatile type* atomic_obj, type operand);
- type __atomic_fetch_xor_consume(volatile type* atomic_obj, type operand);
- type __atomic_fetch_xor_acquire(volatile type* atomic_obj, type operand);
- type __atomic_fetch_xor_release(volatile type* atomic_obj, type operand);
- type __atomic_fetch_xor_acq_rel(volatile type* atomic_obj, type operand);
- type __atomic_fetch_xor_seq_cst(volatile type* atomic_obj, type operand);
-
- void* __atomic_fetch_add_relaxed(void* volatile* atomic_obj, ptrdiff_t operand);
- void* __atomic_fetch_add_consume(void* volatile* atomic_obj, ptrdiff_t operand);
- void* __atomic_fetch_add_acquire(void* volatile* atomic_obj, ptrdiff_t operand);
- void* __atomic_fetch_add_release(void* volatile* atomic_obj, ptrdiff_t operand);
- void* __atomic_fetch_add_acq_rel(void* volatile* atomic_obj, ptrdiff_t operand);
- void* __atomic_fetch_add_seq_cst(void* volatile* atomic_obj, ptrdiff_t operand);
-
- void* __atomic_fetch_sub_relaxed(void* volatile* atomic_obj, ptrdiff_t operand);
- void* __atomic_fetch_sub_consume(void* volatile* atomic_obj, ptrdiff_t operand);
- void* __atomic_fetch_sub_acquire(void* volatile* atomic_obj, ptrdiff_t operand);
- void* __atomic_fetch_sub_release(void* volatile* atomic_obj, ptrdiff_t operand);
- void* __atomic_fetch_sub_acq_rel(void* volatile* atomic_obj, ptrdiff_t operand);
- void* __atomic_fetch_sub_seq_cst(void* volatile* atomic_obj, ptrdiff_t operand);
-
- void __atomic_thread_fence_relaxed();
- void __atomic_thread_fence_consume();
- void __atomic_thread_fence_acquire();
- void __atomic_thread_fence_release();
- void __atomic_thread_fence_acq_rel();
- void __atomic_thread_fence_seq_cst();
-
- void __atomic_signal_fence_relaxed();
- void __atomic_signal_fence_consume();
- void __atomic_signal_fence_acquire();
- void __atomic_signal_fence_release();
- void __atomic_signal_fence_acq_rel();
- void __atomic_signal_fence_seq_cst();
-
-Design C: Minimal work for the front end
-========================================
-The ``<atomic>`` header is one of the most closely coupled headers to the compiler.
-Ideally when you invoke any function from ``<atomic>``, it should result in highly
+```cpp
+// type must be trivially copyable
+bool __atomic_is_lock_free(const type* atomic_obj);
+
+// type must be trivially copyable
+type __atomic_load_relaxed(const volatile type* atomic_obj);
+type __atomic_load_consume(const volatile type* atomic_obj);
+type __atomic_load_acquire(const volatile type* atomic_obj);
+type __atomic_load_seq_cst(const volatile type* atomic_obj);
+
+// type must be trivially copyable
+type __atomic_store_relaxed(volatile type* atomic_obj, type desired);
+type __atomic_store_release(volatile type* atomic_obj, type desired);
+type __atomic_store_seq_cst(volatile type* atomic_obj, type desired);
+
+// type must be trivially copyable
+type __atomic_exchange_relaxed(volatile type* atomic_obj, type desired);
+type __atomic_exchange_consume(volatile type* atomic_obj, type desired);
+type __atomic_exchange_acquire(volatile type* atomic_obj, type desired);
+type __atomic_exchange_release(volatile type* atomic_obj, type desired);
+type __atomic_exchange_acq_rel(volatile type* atomic_obj, type desired);
+type __atomic_exchange_seq_cst(volatile type* atomic_obj, type desired);
+
+// type must be trivially copyable
+bool __atomic_compare_exchange_strong_relaxed_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_consume_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_consume_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_acquire_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_acquire_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_acquire_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_release_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_release_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_release_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_acq_rel_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_acq_rel_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_acq_rel_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_seq_cst_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_seq_cst_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_seq_cst_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_strong_seq_cst_seq_cst(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+
+// type must be trivially copyable
+bool __atomic_compare_exchange_weak_relaxed_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_consume_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_consume_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_acquire_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_acquire_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_acquire_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_release_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_release_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_release_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_acq_rel_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_acq_rel_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_acq_rel_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_seq_cst_relaxed(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_seq_cst_consume(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_seq_cst_acquire(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+bool __atomic_compare_exchange_weak_seq_cst_seq_cst(volatile type* atomic_obj,
+ type* expected,
+ type desired);
+
+// type is one of: char, signed char, unsigned char, short, unsigned short, int,
+// unsigned int, long, unsigned long, long long, unsigned long long,
+// char16_t, char32_t, wchar_t
+type __atomic_fetch_add_relaxed(volatile type* atomic_obj, type operand);
+type __atomic_fetch_add_consume(volatile type* atomic_obj, type operand);
+type __atomic_fetch_add_acquire(volatile type* atomic_obj, type operand);
+type __atomic_fetch_add_release(volatile type* atomic_obj, type operand);
+type __atomic_fetch_add_acq_rel(volatile type* atomic_obj, type operand);
+type __atomic_fetch_add_seq_cst(volatile type* atomic_obj, type operand);
+
+// type is one of: char, signed char, unsigned char, short, unsigned short, int,
+// unsigned int, long, unsigned long, long long, unsigned long long,
+// char16_t, char32_t, wchar_t
+type __atomic_fetch_sub_relaxed(volatile type* atomic_obj, type operand);
+type __atomic_fetch_sub_consume(volatile type* atomic_obj, type operand);
+type __atomic_fetch_sub_acquire(volatile type* atomic_obj, type operand);
+type __atomic_fetch_sub_release(volatile type* atomic_obj, type operand);
+type __atomic_fetch_sub_acq_rel(volatile type* atomic_obj, type operand);
+type __atomic_fetch_sub_seq_cst(volatile type* atomic_obj, type operand);
+
+// type is one of: char, signed char, unsigned char, short, unsigned short, int,
+// unsigned int, long, unsigned long, long long, unsigned long long,
+// char16_t, char32_t, wchar_t
+type __atomic_fetch_and_relaxed(volatile type* atomic_obj, type operand);
+type __atomic_fetch_and_consume(volatile type* atomic_obj, type operand);
+type __atomic_fetch_and_acquire(volatile type* atomic_obj, type operand);
+type __atomic_fetch_and_release(volatile type* atomic_obj, type operand);
+type __atomic_fetch_and_acq_rel(volatile type* atomic_obj, type operand);
+type __atomic_fetch_and_seq_cst(volatile type* atomic_obj, type operand);
+
+// type is one of: char, signed char, unsigned char, short, unsigned short, int,
+// unsigned int, long, unsigned long, long long, unsigned long long,
+// char16_t, char32_t, wchar_t
+type __atomic_fetch_or_relaxed(volatile type* atomic_obj, type operand);
+type __atomic_fetch_or_consume(volatile type* atomic_obj, type operand);
+type __atomic_fetch_or_acquire(volatile type* atomic_obj, type operand);
+type __atomic_fetch_or_release(volatile type* atomic_obj, type operand);
+type __atomic_fetch_or_acq_rel(volatile type* atomic_obj, type operand);
+type __atomic_fetch_or_seq_cst(volatile type* atomic_obj, type operand);
+
+// type is one of: char, signed char, unsigned char, short, unsigned short, int,
+// unsigned int, long, unsigned long, long long, unsigned long long,
+// char16_t, char32_t, wchar_t
+type __atomic_fetch_xor_relaxed(volatile type* atomic_obj, type operand);
+type __atomic_fetch_xor_consume(volatile type* atomic_obj, type operand);
+type __atomic_fetch_xor_acquire(volatile type* atomic_obj, type operand);
+type __atomic_fetch_xor_release(volatile type* atomic_obj, type operand);
+type __atomic_fetch_xor_acq_rel(volatile type* atomic_obj, type operand);
+type __atomic_fetch_xor_seq_cst(volatile type* atomic_obj, type operand);
+
+void* __atomic_fetch_add_relaxed(void* volatile* atomic_obj, ptrdiff_t operand);
+void* __atomic_fetch_add_consume(void* volatile* atomic_obj, ptrdiff_t operand);
+void* __atomic_fetch_add_acquire(void* volatile* atomic_obj, ptrdiff_t operand);
+void* __atomic_fetch_add_release(void* volatile* atomic_obj, ptrdiff_t operand);
+void* __atomic_fetch_add_acq_rel(void* volatile* atomic_obj, ptrdiff_t operand);
+void* __atomic_fetch_add_seq_cst(void* volatile* atomic_obj, ptrdiff_t operand);
+
+void* __atomic_fetch_sub_relaxed(void* volatile* atomic_obj, ptrdiff_t operand);
+void* __atomic_fetch_sub_consume(void* volatile* atomic_obj, ptrdiff_t operand);
+void* __atomic_fetch_sub_acquire(void* volatile* atomic_obj, ptrdiff_t operand);
+void* __atomic_fetch_sub_release(void* volatile* atomic_obj, ptrdiff_t operand);
+void* __atomic_fetch_sub_acq_rel(void* volatile* atomic_obj, ptrdiff_t operand);
+void* __atomic_fetch_sub_seq_cst(void* volatile* atomic_obj, ptrdiff_t operand);
+
+void __atomic_thread_fence_relaxed();
+void __atomic_thread_fence_consume();
+void __atomic_thread_fence_acquire();
+void __atomic_thread_fence_release();
+void __atomic_thread_fence_acq_rel();
+void __atomic_thread_fence_seq_cst();
+
+void __atomic_signal_fence_relaxed();
+void __atomic_signal_fence_consume();
+void __atomic_signal_fence_acquire();
+void __atomic_signal_fence_release();
+void __atomic_signal_fence_acq_rel();
+void __atomic_signal_fence_seq_cst();
+```
+
+## Design C: Minimal work for the front end
+
+The `<atomic>` header is one of the most closely coupled headers to the compiler.
+Ideally when you invoke any function from `<atomic>`, it should result in highly
optimized assembly being inserted directly into your application -- assembly that
is not otherwise representable by higher level C or C++ expressions. The design of
-the libc++ ``<atomic>`` header started with this goal in mind. A secondary, but
+the libc++ `<atomic>` header started with this goal in mind. A secondary, but
still very important goal is that the compiler should have to do minimal work to
-facilitate the implementation of ``<atomic>``. Without this second goal, then
-practically speaking, the libc++ ``<atomic>`` header would be doomed to be a
+facilitate the implementation of `<atomic>`. Without this second goal, then
+practically speaking, the libc++ `<atomic>` header would be doomed to be a
barely supported, second class citizen on almost every platform.
Goals:
@@ -467,309 +462,308 @@ Goals:
- Conformance to the C++0X draft standard
The purpose of this document is to inform compiler writers what they need to do
-to enable a high performance libc++ ``<atomic>`` with minimal effort.
-
-The minimal work that must be done for a conforming ``<atomic>``
-----------------------------------------------------------------
-The only "atomic" operations that must actually be lock free in
-``<atomic>`` are represented by the following compiler intrinsics:
+to enable a high performance libc++ `<atomic>` with minimal effort.
-.. code-block:: cpp
-
- __atomic_flag__ __atomic_exchange_seq_cst(__atomic_flag__ volatile* obj, __atomic_flag__ desr) {
- unique_lock<mutex> _(some_mutex);
- __atomic_flag__ result = *obj;
- *obj = desr;
- return result;
- }
+### The minimal work that must be done for a conforming `<atomic>`
- void __atomic_store_seq_cst(__atomic_flag__ volatile* obj, __atomic_flag__ desr) {
- unique_lock<mutex> _(some_mutex);
- *obj = desr;
- }
+The only "atomic" operations that must actually be lock free in
+`<atomic>` are represented by the following compiler intrinsics:
+
+```cpp
+__atomic_flag__ __atomic_exchange_seq_cst(__atomic_flag__ volatile* obj, __atomic_flag__ desr) {
+ unique_lock<mutex> _(some_mutex);
+ __atomic_flag__ result = *obj;
+ *obj = desr;
+ return result;
+}
+
+void __atomic_store_seq_cst(__atomic_flag__ volatile* obj, __atomic_flag__ desr) {
+ unique_lock<mutex> _(some_mutex);
+ *obj = desr;
+}
+```
Where:
-- If ``__has_feature(__atomic_flag)`` evaluates to 1 in the preprocessor then
- the compiler must define ``__atomic_flag__`` (e.g. as a typedef to ``int``).
-- If ``__has_feature(__atomic_flag)`` evaluates to 0 in the preprocessor then
- the library defines ``__atomic_flag__`` as a typedef to ``bool``.
+- If `__has_feature(__atomic_flag)` evaluates to 1 in the preprocessor then
+ the compiler must define `__atomic_flag__` (e.g. as a typedef to `int`).
+- If `__has_feature(__atomic_flag)` evaluates to 0 in the preprocessor then
+ the library defines `__atomic_flag__` as a typedef to `bool`.
- To communicate that the above intrinsics are available, the compiler must
- arrange for ``__has_feature`` to return 1 when fed the intrinsic name
- appended with an '_' and the mangled type name of ``__atomic_flag__``.
+ arrange for `__has_feature` to return 1 when fed the intrinsic name
+ appended with an '\_' and the mangled type name of `__atomic_flag__`.
-For example if ``__atomic_flag__`` is ``unsigned int``:
+For example if `__atomic_flag__` is `unsigned int`:
-.. code-block:: cpp
+```cpp
+// __has_feature(__atomic_flag) == 1
+// __has_feature(__atomic_exchange_seq_cst_j) == 1
+// __has_feature(__atomic_store_seq_cst_j) == 1
- // __has_feature(__atomic_flag) == 1
- // __has_feature(__atomic_exchange_seq_cst_j) == 1
- // __has_feature(__atomic_store_seq_cst_j) == 1
+typedef unsigned int __atomic_flag__;
- typedef unsigned int __atomic_flag__;
+unsigned int __atomic_exchange_seq_cst(unsigned int volatile*, unsigned int) {
+ // ...
+}
- unsigned int __atomic_exchange_seq_cst(unsigned int volatile*, unsigned int) {
- // ...
- }
-
- void __atomic_store_seq_cst(unsigned int volatile*, unsigned int) {
- // ...
- }
+void __atomic_store_seq_cst(unsigned int volatile*, unsigned int) {
+ // ...
+}
+```
That's it! Compiler writers do the above and you've got a fully conforming
-(though sub-par performance) ``<atomic>`` header!
+(though sub-par performance) `<atomic>` header!
+### Recommended work for a higher performance `<atomic>`
-Recommended work for a higher performance ``<atomic>``
-------------------------------------------------------
It would be good if the above intrinsics worked with all integral types plus
-``void*``. Because this may not be possible to do in a lock-free manner for
+`void*`. Because this may not be possible to do in a lock-free manner for
all integral types on all platforms, a compiler must communicate each type that
-an intrinsic works with. For example, if ``__atomic_exchange_seq_cst`` works
-for all types except for ``long long`` and ``unsigned long long`` then:
-
-.. code-block:: cpp
-
- __has_feature(__atomic_exchange_seq_cst_b) == 1 // bool
- __has_feature(__atomic_exchange_seq_cst_c) == 1 // char
- __has_feature(__atomic_exchange_seq_cst_a) == 1 // signed char
- __has_feature(__atomic_exchange_seq_cst_h) == 1 // unsigned char
- __has_feature(__atomic_exchange_seq_cst_Ds) == 1 // char16_t
- __has_feature(__atomic_exchange_seq_cst_Di) == 1 // char32_t
- __has_feature(__atomic_exchange_seq_cst_w) == 1 // wchar_t
- __has_feature(__atomic_exchange_seq_cst_s) == 1 // short
- __has_feature(__atomic_exchange_seq_cst_t) == 1 // unsigned short
- __has_feature(__atomic_exchange_seq_cst_i) == 1 // int
- __has_feature(__atomic_exchange_seq_cst_j) == 1 // unsigned int
- __has_feature(__atomic_exchange_seq_cst_l) == 1 // long
- __has_feature(__atomic_exchange_seq_cst_m) == 1 // unsigned long
- __has_feature(__atomic_exchange_seq_cst_Pv) == 1 // void*
-
-Note that only the ``__has_feature`` flag is decorated with the argument
+an intrinsic works with. For example, if `__atomic_exchange_seq_cst` works
+for all types except for `long long` and `unsigned long long` then:
+
+```cpp
+__has_feature(__atomic_exchange_seq_cst_b) == 1 // bool
+__has_feature(__atomic_exchange_seq_cst_c) == 1 // char
+__has_feature(__atomic_exchange_seq_cst_a) == 1 // signed char
+__has_feature(__atomic_exchange_seq_cst_h) == 1 // unsigned char
+__has_feature(__atomic_exchange_seq_cst_Ds) == 1 // char16_t
+__has_feature(__atomic_exchange_seq_cst_Di) == 1 // char32_t
+__has_feature(__atomic_exchange_seq_cst_w) == 1 // wchar_t
+__has_feature(__atomic_exchange_seq_cst_s) == 1 // short
+__has_feature(__atomic_exchange_seq_cst_t) == 1 // unsigned short
+__has_feature(__atomic_exchange_seq_cst_i) == 1 // int
+__has_feature(__atomic_exchange_seq_cst_j) == 1 // unsigned int
+__has_feature(__atomic_exchange_seq_cst_l) == 1 // long
+__has_feature(__atomic_exchange_seq_cst_m) == 1 // unsigned long
+__has_feature(__atomic_exchange_seq_cst_Pv) == 1 // void*
+```
+
+Note that only the `__has_feature` flag is decorated with the argument
type. The name of the compiler intrinsic is not decorated, but instead works
like a C++ overloaded function.
-Additionally, there are other intrinsics besides ``__atomic_exchange_seq_cst``
-and ``__atomic_store_seq_cst``. They are optional. But if the compiler can
+Additionally, there are other intrinsics besides `__atomic_exchange_seq_cst`
+and `__atomic_store_seq_cst`. They are optional. But if the compiler can
generate faster code than provided by the library, then clients will benefit
from the compiler writer's expertise and knowledge of the targeted platform.
Below is the complete list of *sequentially consistent* intrinsics, and
their library implementations. Template syntax is used to indicate the desired
-overloading for integral and ``void*`` types. The template does not represent a
+overloading for integral and `void*` types. The template does not represent a
requirement that the intrinsic operate on **any** type!
-.. code-block:: cpp
-
- // T is one of:
- // bool, char, signed char, unsigned char, short, unsigned short,
- // int, unsigned int, long, unsigned long,
- // long long, unsigned long long, char16_t, char32_t, wchar_t, void*
-
- template <class T>
- T __atomic_load_seq_cst(T const volatile* obj) {
- unique_lock<mutex> _(some_mutex);
- return *obj;
- }
-
- template <class T>
- void __atomic_store_seq_cst(T volatile* obj, T desr) {
- unique_lock<mutex> _(some_mutex);
- *obj = desr;
- }
-
- template <class T>
- T __atomic_exchange_seq_cst(T volatile* obj, T desr) {
- unique_lock<mutex> _(some_mutex);
- T r = *obj;
- *obj = desr;
- return r;
- }
-
- template <class T>
- bool __atomic_compare_exchange_strong_seq_cst_seq_cst(T volatile* obj, T* exp, T desr) {
- unique_lock<mutex> _(some_mutex);
- if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) {
- std::memcpy(const_cast<T*>(obj), &desr, sizeof(T));
- return true;
- }
- std::memcpy(exp, const_cast<T*>(obj), sizeof(T));
- return false;
- }
-
- template <class T>
- bool __atomic_compare_exchange_weak_seq_cst_seq_cst(T volatile* obj, T* exp, T desr) {
- unique_lock<mutex> _(some_mutex);
- if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0)
- {
- std::memcpy(const_cast<T*>(obj), &desr, sizeof(T));
- return true;
- }
- std::memcpy(exp, const_cast<T*>(obj), sizeof(T));
- return false;
- }
-
- // T is one of:
- // char, signed char, unsigned char, short, unsigned short,
- // int, unsigned int, long, unsigned long,
- // long long, unsigned long long, char16_t, char32_t, wchar_t
-
- template <class T>
- T __atomic_fetch_add_seq_cst(T volatile* obj, T operand) {
- unique_lock<mutex> _(some_mutex);
- T r = *obj;
- *obj += operand;
- return r;
- }
-
- template <class T>
- T __atomic_fetch_sub_seq_cst(T volatile* obj, T operand) {
- unique_lock<mutex> _(some_mutex);
- T r = *obj;
- *obj -= operand;
- return r;
- }
-
- template <class T>
- T __atomic_fetch_and_seq_cst(T volatile* obj, T operand) {
- unique_lock<mutex> _(some_mutex);
- T r = *obj;
- *obj &= operand;
- return r;
- }
-
- template <class T>
- T __atomic_fetch_or_seq_cst(T volatile* obj, T operand) {
- unique_lock<mutex> _(some_mutex);
- T r = *obj;
- *obj |= operand;
- return r;
- }
-
- template <class T>
- T __atomic_fetch_xor_seq_cst(T volatile* obj, T operand) {
- unique_lock<mutex> _(some_mutex);
- T r = *obj;
- *obj ^= operand;
- return r;
- }
-
- void* __atomic_fetch_add_seq_cst(void* volatile* obj, ptrdiff_t operand) {
- unique_lock<mutex> _(some_mutex);
- void* r = *obj;
- (char*&)(*obj) += operand;
- return r;
- }
-
- void* __atomic_fetch_sub_seq_cst(void* volatile* obj, ptrdiff_t operand) {
- unique_lock<mutex> _(some_mutex);
- void* r = *obj;
- (char*&)(*obj) -= operand;
- return r;
- }
-
- void __atomic_thread_fence_seq_cst() {
- unique_lock<mutex> _(some_mutex);
- }
-
- void __atomic_signal_fence_seq_cst() {
- unique_lock<mutex> _(some_mutex);
- }
-
-One should consult the (currently draft) `C++ Standard <https://wg21.link/n3126>`_
+```cpp
+// T is one of:
+// bool, char, signed char, unsigned char, short, unsigned short,
+// int, unsigned int, long, unsigned long,
+// long long, unsigned long long, char16_t, char32_t, wchar_t, void*
+
+template <class T>
+T __atomic_load_seq_cst(T const volatile* obj) {
+ unique_lock<mutex> _(some_mutex);
+ return *obj;
+}
+
+template <class T>
+void __atomic_store_seq_cst(T volatile* obj, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ *obj = desr;
+}
+
+template <class T>
+T __atomic_exchange_seq_cst(T volatile* obj, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj = desr;
+ return r;
+}
+
+template <class T>
+bool __atomic_compare_exchange_strong_seq_cst_seq_cst(T volatile* obj, T* exp, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) {
+ std::memcpy(const_cast<T*>(obj), &desr, sizeof(T));
+ return true;
+ }
+ std::memcpy(exp, const_cast<T*>(obj), sizeof(T));
+ return false;
+}
+
+template <class T>
+bool __atomic_compare_exchange_weak_seq_cst_seq_cst(T volatile* obj, T* exp, T desr) {
+ unique_lock<mutex> _(some_mutex);
+ if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0)
+ {
+ std::memcpy(const_cast<T*>(obj), &desr, sizeof(T));
+ return true;
+ }
+ std::memcpy(exp, const_cast<T*>(obj), sizeof(T));
+ return false;
+}
+
+// T is one of:
+// char, signed char, unsigned char, short, unsigned short,
+// int, unsigned int, long, unsigned long,
+// long long, unsigned long long, char16_t, char32_t, wchar_t
+
+template <class T>
+T __atomic_fetch_add_seq_cst(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj += operand;
+ return r;
+}
+
+template <class T>
+T __atomic_fetch_sub_seq_cst(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj -= operand;
+ return r;
+}
+
+template <class T>
+T __atomic_fetch_and_seq_cst(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj &= operand;
+ return r;
+}
+
+template <class T>
+T __atomic_fetch_or_seq_cst(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj |= operand;
+ return r;
+}
+
+template <class T>
+T __atomic_fetch_xor_seq_cst(T volatile* obj, T operand) {
+ unique_lock<mutex> _(some_mutex);
+ T r = *obj;
+ *obj ^= operand;
+ return r;
+}
+
+void* __atomic_fetch_add_seq_cst(void* volatile* obj, ptrdiff_t operand) {
+ unique_lock<mutex> _(some_mutex);
+ void* r = *obj;
+ (char*&)(*obj) += operand;
+ return r;
+}
+
+void* __atomic_fetch_sub_seq_cst(void* volatile* obj, ptrdiff_t operand) {
+ unique_lock<mutex> _(some_mutex);
+ void* r = *obj;
+ (char*&)(*obj) -= operand;
+ return r;
+}
+
+void __atomic_thread_fence_seq_cst() {
+ unique_lock<mutex> _(some_mutex);
+}
+
+void __atomic_signal_fence_seq_cst() {
+ unique_lock<mutex> _(some_mutex);
+}
+```
+
+One should consult the (currently draft) [C++ Standard](https://wg21.link/n3126)
for the details of the definitions for these operations. For example,
-``__atomic_compare_exchange_weak_seq_cst_seq_cst`` is allowed to fail
-spuriously while ``__atomic_compare_exchange_strong_seq_cst_seq_cst`` is not.
-
-If on your platform the lock-free definition of ``__atomic_compare_exchange_weak_seq_cst_seq_cst``
-would be the same as ``__atomic_compare_exchange_strong_seq_cst_seq_cst``, you may omit the
-``__atomic_compare_exchange_weak_seq_cst_seq_cst`` intrinsic without a performance cost. The
-library will prefer your implementation of ``__atomic_compare_exchange_strong_seq_cst_seq_cst``
-over its own definition for implementing ``__atomic_compare_exchange_weak_seq_cst_seq_cst``.
-That is, the library will arrange for ``__atomic_compare_exchange_weak_seq_cst_seq_cst`` to call
-``__atomic_compare_exchange_strong_seq_cst_seq_cst`` if you supply an intrinsic for the strong
+`__atomic_compare_exchange_weak_seq_cst_seq_cst` is allowed to fail
+spuriously while `__atomic_compare_exchange_strong_seq_cst_seq_cst` is not.
+
+If on your platform the lock-free definition of `__atomic_compare_exchange_weak_seq_cst_seq_cst`
+would be the same as `__atomic_compare_exchange_strong_seq_cst_seq_cst`, you may omit the
+`__atomic_compare_exchange_weak_seq_cst_seq_cst` intrinsic without a performance cost. The
+library will prefer your implementation of `__atomic_compare_exchange_strong_seq_cst_seq_cst`
+over its own definition for implementing `__atomic_compare_exchange_weak_seq_cst_seq_cst`.
+That is, the library will arrange for `__atomic_compare_exchange_weak_seq_cst_seq_cst` to call
+`__atomic_compare_exchange_strong_seq_cst_seq_cst` if you supply an intrinsic for the strong
version but not the weak.
-Taking advantage of weaker memory synchronization
--------------------------------------------------
+### Taking advantage of weaker memory synchronization
+
So far, all of the intrinsics presented require a **sequentially consistent** memory ordering.
That is, no loads or stores can move across the operation (just as if the library had locked
-that internal mutex). But ``<atomic>`` supports weaker memory ordering operations. In all,
+that internal mutex). But `<atomic>` supports weaker memory ordering operations. In all,
there are six memory orderings (listed here from strongest to weakest):
-.. code-block:: cpp
-
- memory_order_seq_cst
- memory_order_acq_rel
- memory_order_release
- memory_order_acquire
- memory_order_consume
- memory_order_relaxed
+```cpp
+memory_order_seq_cst
+memory_order_acq_rel
+memory_order_release
+memory_order_acquire
+memory_order_consume
+memory_order_relaxed
+```
-(See the `C++ Standard <https://wg21.link/n3126>`_ for the detailed definitions of each of these orderings).
+(See the [C++ Standard](https://wg21.link/n3126) for the detailed definitions of each of these orderings).
On some platforms, the compiler vendor can offer some or even all of the above
intrinsics at one or more weaker levels of memory synchronization. This might
-lead for example to not issuing an ``mfence`` instruction on the x86.
+lead for example to not issuing an `mfence` instruction on the x86.
If the compiler does not offer any given operation, at any given memory ordering
level, the library will automatically attempt to call the next highest memory
-ordering operation. This continues up to ``seq_cst``, and if that doesn't
-exist, then the library takes over and does the job with a ``mutex``. This
+ordering operation. This continues up to `seq_cst`, and if that doesn't
+exist, then the library takes over and does the job with a `mutex`. This
is a compile-time search and selection operation. At run time, the application
will only see the few inlined assembly instructions for the selected intrinsic.
Each intrinsic is appended with the 7-letter name of the memory ordering it
-addresses. For example a ``load`` with ``relaxed`` ordering is defined by:
-
-.. code-block:: cpp
+addresses. For example a `load` with `relaxed` ordering is defined by:
- T __atomic_load_relaxed(const volatile T* obj);
+```cpp
+T __atomic_load_relaxed(const volatile T* obj);
+```
And announced with:
-.. code-block:: cpp
+```cpp
+__has_feature(__atomic_load_relaxed_b) == 1 // bool
+__has_feature(__atomic_load_relaxed_c) == 1 // char
+__has_feature(__atomic_load_relaxed_a) == 1 // signed char
+...
+```
- __has_feature(__atomic_load_relaxed_b) == 1 // bool
- __has_feature(__atomic_load_relaxed_c) == 1 // char
- __has_feature(__atomic_load_relaxed_a) == 1 // signed char
- ...
-
-The ``__atomic_compare_exchange_strong(weak)`` intrinsics are parameterized
+The `__atomic_compare_exchange_strong(weak)` intrinsics are parameterized
on two memory orderings. The first ordering applies when the operation returns
-``true`` and the second ordering applies when the operation returns ``false``.
+`true` and the second ordering applies when the operation returns `false`.
-Not every memory ordering is appropriate for every operation. ``exchange``
-and the ``fetch_XXX`` operations support all 6. But ``load`` only supports
-``relaxed``, ``consume``, ``acquire`` and ``seq_cst``. ``store`` only supports
-``relaxed``, ``release``, and ``seq_cst``. The ``compare_exchange`` operations
+Not every memory ordering is appropriate for every operation. `exchange`
+and the `fetch_XXX` operations support all 6. But `load` only supports
+`relaxed`, `consume`, `acquire` and `seq_cst`. `store` only supports
+`relaxed`, `release`, and `seq_cst`. The `compare_exchange` operations
support the following 16 combinations out of the possible 36:
-.. code-block:: cpp
-
- relaxed_relaxed
- consume_relaxed
- consume_consume
- acquire_relaxed
- acquire_consume
- acquire_acquire
- release_relaxed
- release_consume
- release_acquire
- acq_rel_relaxed
- acq_rel_consume
- acq_rel_acquire
- seq_cst_relaxed
- seq_cst_consume
- seq_cst_acquire
- seq_cst_seq_cst
+```cpp
+relaxed_relaxed
+consume_relaxed
+consume_consume
+acquire_relaxed
+acquire_consume
+acquire_acquire
+release_relaxed
+release_consume
+release_acquire
+acq_rel_relaxed
+acq_rel_consume
+acq_rel_acquire
+seq_cst_relaxed
+seq_cst_consume
+seq_cst_acquire
+seq_cst_seq_cst
+```
Again, the compiler supplies intrinsics only for the strongest orderings where
it can make a difference. The library takes care of calling the weakest
supplied intrinsic that is as strong or stronger than the customer asked for.
-Note about ABI
-==============
+## Note about ABI
+
With any design, the (back end) compiler writer should note that the decision to
implement lock-free operations on any given type (or not) is an ABI-binding decision.
One can not change from treating a type as not lock free, to lock free (or vice-versa)
@@ -779,19 +773,19 @@ For example:
**TU1.cpp**:
-.. code-block:: cpp
-
- extern atomic<long long> A;
- int foo() { return A.compare_exchange_strong(w, x); }
-
+```cpp
+extern atomic<long long> A;
+int foo() { return A.compare_exchange_strong(w, x); }
+```
**TU2.cpp**:
-.. code-block:: cpp
+```cpp
+extern atomic<long long> A;
+void bar() { return A.compare_exchange_strong(y, z); }
+```
- extern atomic<long long> A;
- void bar() { return A.compare_exchange_strong(y, z); }
-
-If only **one** of these calls to ``compare_exchange_strong`` is implemented with
+If only **one** of these calls to `compare_exchange_strong` is implemented with
mutex-locked code, then that mutex-locked code will not be executed mutually
exclusively of the one implemented in a lock-free manner.
+
diff --git a/libcxx/docs/DesignDocs/CapturingConfigInfo.md b/libcxx/docs/DesignDocs/CapturingConfigInfo.md
index 402f4c7197c2f..b9083ed794f63 100644
--- a/libcxx/docs/DesignDocs/CapturingConfigInfo.md
+++ b/libcxx/docs/DesignDocs/CapturingConfigInfo.md
@@ -1,41 +1,33 @@
-==================================================
-Capturing configuration information in the headers
-==================================================
+# Capturing configuration information in the headers
-.. contents::
- :local:
+```{contents}
+:local: true
+```
-The Problem
-===========
+## The Problem
libc++ supports building the library with a number of different configuration options.
In order to support persistent configurations and reduce arbitrary preprocessor logic
in the headers, libc++ has a mechanism to capture configuration options in the
installed headers so they can be used in the rest of the code.
+## Design Goals
-Design Goals
-============
-
-* The solution should be simple, consistent and robust to avoid subtle bugs.
-
-* Developers should test the code the same way it will be deployed -- in other words,
+- The solution should be simple, consistent and robust to avoid subtle bugs.
+- Developers should test the code the same way it will be deployed -- in other words,
the headers used to run tests should be the same that we install in order
to avoid bugs creeping up.
-
-* It should allow different targets or flavors of the library to use a different
+- It should allow different targets or flavors of the library to use a different
configuration without having to duplicate all the libc++ headers.
+## The Solution
-The Solution
-============
-
-When you first configure libc++ using CMake, a ``__config_site`` file is generated
-to capture the various configuration options you selected. The ``__config`` header
-used by all other headers includes this ``__config_site`` header first in order to
+When you first configure libc++ using CMake, a `__config_site` file is generated
+to capture the various configuration options you selected. The `__config` header
+used by all other headers includes this `__config_site` header first in order to
get the correct configuration.
-The ``__config_site`` header is hence the only place where persistent configuration
+The `__config_site` header is hence the only place where persistent configuration
is stored in the library. That header essentially reflects how the vendor configured
the library. As we evolve the library, we can lift configuration options into that
header in order to reduce arbitrary hardcoded choices elsewhere in the code. For
@@ -45,24 +37,25 @@ configuring the library on that platform. This makes the "carve off" reusable in
other circumstances instead of tying it tightly to a single platform.
Furthermore, the Clang driver now looks for headers in a target-specific directory
-for libc++. By installing the ``__config_site`` header (and only that header) to
+for libc++. By installing the `__config_site` header (and only that header) to
this target-specific directory, it is possible to share the libc++ headers for
multiple targets, and only duplicate the persistent information located in the
-``__config_site`` header. For example:
+`__config_site` header. For example:
-.. code-block:: bash
+```bash
+include/c++/v1/
+ vector
+ map
+ etc...
- include/c++/v1/
- vector
- map
- etc...
+include/<targetA>/c++/v1/
+ __config_site
- include/<targetA>/c++/v1/
- __config_site
+include/<targetB>/c++/v1/
+ __config_site
+```
- include/<targetB>/c++/v1/
- __config_site
+When compiling for `targetA`, Clang will use the `__config_site` inside
+`include/<targetA>/c++/v1/`, and the corresponding `__config_site` for
+`targetB`.
-When compiling for ``targetA``, Clang will use the ``__config_site`` inside
-``include/<targetA>/c++/v1/``, and the corresponding ``__config_site`` for
-``targetB``.
diff --git a/libcxx/docs/DesignDocs/ExperimentalFeatures.md b/libcxx/docs/DesignDocs/ExperimentalFeatures.md
index f9b23493b2356..8522383c8bc3d 100644
--- a/libcxx/docs/DesignDocs/ExperimentalFeatures.md
+++ b/libcxx/docs/DesignDocs/ExperimentalFeatures.md
@@ -1,14 +1,12 @@
-=====================
-Experimental Features
-=====================
+# Experimental Features
-.. contents::
- :local:
+```{contents}
+:local: true
+```
-.. _experimental features:
+(experimental-features-1)=
-Overview
-========
+## Overview
Libc++ implements technical specifications (TSes) and ships them as experimental
features that users are free to try out. The goal is to allow getting feedback
@@ -20,8 +18,7 @@ is guaranteed, and experimental features are deprecated once the non-experimenta
equivalent has shipped in the library. This document outlines the details of
that process.
-Background
-==========
+## Background
The "end game" of a Technical Specification (TS) is to have the features in
there added to a future version of the C++ Standard. When this happens, the TS
@@ -29,182 +26,166 @@ can be retired. Sometimes, only part of at TS is added to the standard, and
the rest of the features may be incorporated into the next version of the TS.
Adoption leaves library implementors with two implementations of a feature,
-one in namespace ``std``, and the other in namespace ``std::experimental``.
+one in namespace `std`, and the other in namespace `std::experimental`.
The first one will continue to evolve (via issues and papers), while the other
will not. Gradually they will diverge. It's not good for users to have two
(subtly) different implementations of the same functionality in the same library.
-Design
-======
+## Design
When a feature is adopted into the main standard, we implement it in namespace
-``std``. Once that implementation is complete, we then create a deprecation
+`std`. Once that implementation is complete, we then create a deprecation
warning for the corresponding experimental feature warning users to move off
of it and to the now-standardized feature.
These deprecation warnings are guarded by a macro of the form
-``_LIBCPP_NO_EXPERIMENTAL_DEPRECATION_WARNING_<FEATURE>``, which
+`_LIBCPP_NO_EXPERIMENTAL_DEPRECATION_WARNING_<FEATURE>`, which
can be defined by users to disable the deprecation warning. Whenever
possible, deprecation warnings are put on a per-declaration basis
-using the ``[[deprecated]]`` attribute, which also allows disabling
-the warnings using ``-Wno-deprecated-declarations``.
+using the `[[deprecated]]` attribute, which also allows disabling
+the warnings using `-Wno-deprecated-declarations`.
After **2 releases** of LLVM, the experimental feature is removed completely
(and the deprecation notice too). Using the experimental feature simply becomes
an error. Furthermore, when an experimental header becomes empty due to the
removal of the corresponding experimental feature, the header is removed.
Keeping the header around creates incorrect assumptions from users and breaks
-``__has_include``.
+`__has_include`.
+## Status of TSes
-Status of TSes
-==============
-
-Library Fundamentals TS `V1 <https://wg21.link/N4480>`__ and `V2 <https://wg21.link/N4617>`__
----------------------------------------------------------------------------------------------
+### Library Fundamentals TS [V1](https://wg21.link/N4480) and [V2](https://wg21.link/N4617)
Most (but not all) of the features of the LFTS were accepted into C++17.
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| Section | Feature | Shipped in ``std`` | To be removed from ``std::experimental`` | Notes |
-+=========+=======================================================+====================+==========================================+=========================+
-| 2.1 | ``uses_allocator construction`` | 5.0 | 7.0 | |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 3.1.2 | ``erased_type`` | | n/a | Not part of C++17 |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 3.2.1 | ``tuple_size_v`` | 5.0 | 7.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 3.2.2 | ``apply`` | 5.0 | 7.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 3.3.1 | All of the ``_v`` traits in ``<type_traits>`` | 5.0 | 7.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 3.3.2 | ``invocation_type`` and ``raw_invocation_type`` | | n/a | Not part of C++17 |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 3.3.3 | Logical operator traits | 5.0 | 7.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 3.3.3 | Detection Idiom | 5.0 | | Only partially in C++17 |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 3.4.1 | All of the ``_v`` traits in ``<ratio>`` | 5.0 | 7.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 3.5.1 | All of the ``_v`` traits in ``<chrono>`` | 5.0 | 7.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 3.6.1 | All of the ``_v`` traits in ``<system_error>`` | 5.0 | 7.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 3.7 | ``propagate_const`` | | n/a | Not part of C++17 |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 4.2 | Enhancements to ``function`` | Not yet | | |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 4.3 | searchers | 7.0 | 9.0 | |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 5 | optional | 5.0 | 7.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 6 | ``any`` | 5.0 | 7.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 7 | ``string_view`` | 5.0 | 7.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 8.2.1 | ``shared_ptr`` enhancements | Not yet | Never added | |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 8.2.2 | ``weak_ptr`` enhancements | Not yet | Never added | |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 8.5 | ``memory_resource`` | 16.0 | 18.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 8.6 | ``polymorphic_allocator`` | 16.0 | 18.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 8.7 | ``resource_adaptor`` | | n/a | Not part of C++17 |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 8.8 | Access to program-wide ``memory_resource`` objects | 16.0 | 18.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 8.9 | Pool resource classes | 16.0 | 18.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 8.10 | ``monotonic_buffer_resource`` | 16.0 | 18.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 8.11 | Alias templates using polymorphic memory resources | 16.0 | 18.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 8.12 | Non-owning pointers | | n/a | Not part of C++17 |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 11.2 | ``promise`` | | n/a | Not part of C++17 |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 11.3 | ``packaged_task`` | | n/a | Not part of C++17 |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 12.2 | ``search`` | 7.0 | 9.0 | |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 12.3 | ``sample`` | 5.0 | 7.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 12.4 | ``shuffle`` | | | Not part of C++17 |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 13.1 | ``gcd`` and ``lcm`` | 5.0 | 7.0 | Removed |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 13.2 | Random number generation | | | Not part of C++17 |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-| 14 | Reflection Library | | | Not part of C++17 |
-+---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-
-
-`FileSystem TS <https://wg21.link/N4100>`__
--------------------------------------------
+| Section | Feature | Shipped in `std` | To be removed from `std::experimental` | Notes |
+| ------- | -------------------------------------------------- | ---------------- | -------------------------------------- | ----------------------- |
+| 2.1 | `uses_allocator construction` | 5.0 | 7.0 | |
+| 3.1.2 | `erased_type` | | n/a | Not part of C++17 |
+| 3.2.1 | `tuple_size_v` | 5.0 | 7.0 | Removed |
+| 3.2.2 | `apply` | 5.0 | 7.0 | Removed |
+| 3.3.1 | All of the `_v` traits in `<type_traits>` | 5.0 | 7.0 | Removed |
+| 3.3.2 | `invocation_type` and `raw_invocation_type` | | n/a | Not part of C++17 |
+| 3.3.3 | Logical operator traits | 5.0 | 7.0 | Removed |
+| 3.3.3 | Detection Idiom | 5.0 | | Only partially in C++17 |
+| 3.4.1 | All of the `_v` traits in `<ratio>` | 5.0 | 7.0 | Removed |
+| 3.5.1 | All of the `_v` traits in `<chrono>` | 5.0 | 7.0 | Removed |
+| 3.6.1 | All of the `_v` traits in `<system_error>` | 5.0 | 7.0 | Removed |
+| 3.7 | `propagate_const` | | n/a | Not part of C++17 |
+| 4.2 | Enhancements to `function` | Not yet | | |
+| 4.3 | searchers | 7.0 | 9.0 | |
+| 5 | optional | 5.0 | 7.0 | Removed |
+| 6 | `any` | 5.0 | 7.0 | Removed |
+| 7 | `string_view` | 5.0 | 7.0 | Removed |
+| 8.2.1 | `shared_ptr` enhancements | Not yet | Never added | |
+| 8.2.2 | `weak_ptr` enhancements | Not yet | Never added | |
+| 8.5 | `memory_resource` | 16.0 | 18.0 | Removed |
+| 8.6 | `polymorphic_allocator` | 16.0 | 18.0 | Removed |
+| 8.7 | `resource_adaptor` | | n/a | Not part of C++17 |
+| 8.8 | Access to program-wide `memory_resource` objects | 16.0 | 18.0 | Removed |
+| 8.9 | Pool resource classes | 16.0 | 18.0 | Removed |
+| 8.10 | `monotonic_buffer_resource` | 16.0 | 18.0 | Removed |
+| 8.11 | Alias templates using polymorphic memory resources | 16.0 | 18.0 | Removed |
+| 8.12 | Non-owning pointers | | n/a | Not part of C++17 |
+| 11.2 | `promise` | | n/a | Not part of C++17 |
+| 11.3 | `packaged_task` | | n/a | Not part of C++17 |
+| 12.2 | `search` | 7.0 | 9.0 | |
+| 12.3 | `sample` | 5.0 | 7.0 | Removed |
+| 12.4 | `shuffle` | | | Not part of C++17 |
+| 13.1 | `gcd` and `lcm` | 5.0 | 7.0 | Removed |
+| 13.2 | Random number generation | | | Not part of C++17 |
+| 14 | Reflection Library | | | Not part of C++17 |
+
+### [FileSystem TS](https://wg21.link/N4100)
+
The FileSystem TS was accepted (in totality) for C++17.
-The FileSystem TS implementation was shipped in namespace ``std`` in LLVM 7.0, and was
+The FileSystem TS implementation was shipped in namespace `std` in LLVM 7.0, and was
removed in LLVM 11.0 (due to the lack of deprecation warnings before LLVM 9.0).
-Parallelism TS `V1 <https://wg21.link/N4507>`__ and `V2 <https://wg21.link/N4706>`__
-------------------------------------------------------------------------------------
+### Parallelism TS [V1](https://wg21.link/N4507) and [V2](https://wg21.link/N4706)
+
Some (most) of the Parallelism TS was accepted for C++17.
We have not yet shipped an implementation of the Parallelism TS.
-`Coroutines TS <https://wg21.link/N4680>`__
--------------------------------------------
+### [Coroutines TS](https://wg21.link/N4680)
+
The Coroutines TS was accepted for C++20.
-An implementation of the Coroutines TS was shipped in LLVM 5.0 in namespace ``std::experimental``,
-and C++20 Coroutines shipped in LLVM 14.0. The implementation of the Coroutines TS in ``std::experimental``
+An implementation of the Coroutines TS was shipped in LLVM 5.0 in namespace `std::experimental`,
+and C++20 Coroutines shipped in LLVM 14.0. The implementation of the Coroutines TS in `std::experimental`
has been removed in LLVM 17.0.
-`Networking TS <https://wg21.link/N4656>`__
--------------------------------------------
+### [Networking TS](https://wg21.link/N4656)
+
The Networking TS is not yet part of a shipping standard, and there is discussion around removing it.
Libc++ never shipped an implementation of the Networking TS and does not plan to do so in the future,
unless the C++ Standards Committee expresses a desire to merge the Networking TS into the IS (which is
unlikely at this point).
-`Ranges TS <https://wg21.link/N4685>`__
----------------------------------------
+### [Ranges TS](https://wg21.link/N4685)
+
The Ranges TS was accepted for C++20.
We will not ship an implementation of the Ranges TS, however we are actively working on
the implementation of C++20 Ranges.
-`Concepts TS <https://wg21.link/N4641>`__
------------------------------------------
+### [Concepts TS](https://wg21.link/N4641)
+
The Concepts TS was accepted for C++20.
We will not ship an implementation of the Concepts TS, however we are shipping an
implementation of C++20 Concepts.
-`Concurrency TS <https://wg21.link/P0159>`__
---------------------------------------------
+### [Concurrency TS](https://wg21.link/P0159)
+
The Concurrency TS was adopted in Kona (2015).
None of the Concurrency TS was accepted for C++17.
We have not yet shipped an implementation of the Concurrency TS.
-.. +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-.. | Section | Feature | Shipped in ``std`` | To be removed from ``std::experimental`` | Notes |
-.. +=========+=======================================================+====================+==========================================+=========================+
-.. | 2.3 | class template ``future`` | | | |
-.. +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-.. | 2.4 | class template ``shared_future`` | | | |
-.. +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-.. | 2.5 | class template ``promise`` | | | Only using ``future`` |
-.. +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-.. | 2.6 | class template ``packaged_task`` | | | Only using ``future`` |
-.. +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-.. | 2.7 | function template ``when_all`` | | | Not part of C++17 |
-.. +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-.. | 2.8 | class template ``when_any_result`` | | | Not part of C++17 |
-.. +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-.. | 2.9 | function template ``when_any`` | | | Not part of C++17 |
-.. +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-.. | 2.10 | function template ``make_ready_future`` | | | Not part of C++17 |
-.. +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-.. | 2.11 | function template ``make_exeptional_future`` | | | Not part of C++17 |
-.. +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-.. | 3 | ``latches`` and ``barriers`` | | | Not part of C++17 |
-.. +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-.. | 4 | Atomic Smart Pointers | | | Adopted for C++20 |
-.. +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
+% +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
+
+% | Section | Feature | Shipped in ``std`` | To be removed from ``std::experimental`` | Notes |
+
+% +=========+=======================================================+====================+==========================================+=========================+
+
+% | 2.3 | class template ``future`` | | | |
+
+% +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
+
+% | 2.4 | class template ``shared_future`` | | | |
+
+% +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
+
+% | 2.5 | class template ``promise`` | | | Only using ``future`` |
+
+% +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
+
+% | 2.6 | class template ``packaged_task`` | | | Only using ``future`` |
+
+% +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
+
+% | 2.7 | function template ``when_all`` | | | Not part of C++17 |
+
+% +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
+
+% | 2.8 | class template ``when_any_result`` | | | Not part of C++17 |
+
+% +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
+
+% | 2.9 | function template ``when_any`` | | | Not part of C++17 |
+
+% +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
+
+% | 2.10 | function template ``make_ready_future`` | | | Not part of C++17 |
+
+% +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
+
+% | 2.11 | function template ``make_exeptional_future`` | | | Not part of C++17 |
+
+% +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
+
+% | 3 | ``latches`` and ``barriers`` | | | Not part of C++17 |
+
+% +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
+
+% | 4 | Atomic Smart Pointers | | | Adopted for C++20 |
+
+% +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
+
diff --git a/libcxx/docs/DesignDocs/ExtendedCXX03Support.md b/libcxx/docs/DesignDocs/ExtendedCXX03Support.md
index 42d59db2bb7a4..40911fd6a2a3c 100644
--- a/libcxx/docs/DesignDocs/ExtendedCXX03Support.md
+++ b/libcxx/docs/DesignDocs/ExtendedCXX03Support.md
@@ -1,12 +1,10 @@
-=======================
-Extended C++03 Support
-=======================
+# Extended C++03 Support
-.. contents::
- :local:
+```{contents}
+:local: true
+```
-Overview
-========
+## Overview
libc++ is an implementation of the C++ standard library targeting C++11 or later.
@@ -16,34 +14,33 @@ by Clang.
This document tracks the C++11 extensions libc++ requires, the C++11 extensions it provides,
and how to write minimal C++11 inside libc++.
-Required C++11 Compiler Extensions
-==================================
+## Required C++11 Compiler Extensions
Clang provides a large subset of C++11 in C++03 as an extension. The features
-libc++ expects Clang to provide are:
+libc++ expects Clang to provide are:
-* Variadic templates.
-* RValue references and perfect forwarding.
-* Alias templates
-* defaulted and deleted Functions.
-* reference qualified Functions
-* ``auto``
+- Variadic templates.
+- RValue references and perfect forwarding.
+- Alias templates
+- defaulted and deleted Functions.
+- reference qualified Functions
+- `auto`
There are also features that Clang *does not* provide as an extension in C++03
mode. These include:
-* ``constexpr`` and ``noexcept``
-* Trailing return types.
-* ``>>`` without a space.
+- `constexpr` and `noexcept`
+- Trailing return types.
+- `>>` without a space.
+## Provided C++11 Library Extensions
-Provided C++11 Library Extensions
-=================================
+:::{warning}
+The C++11 extensions libc++ provides in C++03 are currently undergoing change. Existing extensions
+may be removed in the future. New users are strongly discouraged depending on these extension
+in new code.
-.. warning::
- The C++11 extensions libc++ provides in C++03 are currently undergoing change. Existing extensions
- may be removed in the future. New users are strongly discouraged depending on these extension
- in new code.
+This section will be updated once the libc++ developer community has further discussed the
+future of C++03 with libc++.
+:::
- This section will be updated once the libc++ developer community has further discussed the
- future of C++03 with libc++.
diff --git a/libcxx/docs/DesignDocs/FeatureTestMacros.md b/libcxx/docs/DesignDocs/FeatureTestMacros.md
index fc3a4e355d6a0..8799442319028 100644
--- a/libcxx/docs/DesignDocs/FeatureTestMacros.md
+++ b/libcxx/docs/DesignDocs/FeatureTestMacros.md
@@ -1,20 +1,16 @@
-===================
-Feature Test Macros
-===================
+# Feature Test Macros
-.. contents::
- :local:
+```{contents}
+:local: true
+```
-Overview
-========
+## Overview
Libc++ implements the C++ feature test macros as specified in the C++20 standard,
and before that in non-normative guiding documents
-(`See cppreference <https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros>`_)
+([See cppreference](https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros))
-
-Design
-======
+## Design
Feature test macros are tricky to track, implement, test, and document correctly.
They must be available from a list of headers, they may have different values in
@@ -28,12 +24,11 @@ the tests, and the documentation.
Therefore we maintain a SSoA in `libcxx/utils/generate_feature_test_macro_components.py`
which doubles as a script to generate the following components:
-* The `<version>` header.
-* The version tests under `support.limits.general`.
-* Documentation of libc++'s implementation of each macro.
+- The `<version>` header.
+- The version tests under `support.limits.general`.
+- Documentation of libc++'s implementation of each macro.
-Usage
-=====
+## Usage
The `generate_feature_test_macro_components.py` script is used to track and
update feature test macros in libc++.
@@ -41,3 +36,4 @@ update feature test macros in libc++.
Whenever a feature test macro is added or changed, the table should be updated
and the script should be re-ran. The script will clobber the existing test files,
the documentation and the `<version>` header.
+
diff --git a/libcxx/docs/DesignDocs/FileTimeType.md b/libcxx/docs/DesignDocs/FileTimeType.md
index 946c9e515fb9b..c625c8260e692 100644
--- a/libcxx/docs/DesignDocs/FileTimeType.md
+++ b/libcxx/docs/DesignDocs/FileTimeType.md
@@ -1,81 +1,74 @@
-==============
-File Time Type
-==============
+# File Time Type
-.. contents::
- :local:
+```{contents}
+:local: true
+```
-.. _file-time-type-motivation:
+(file-time-type-motivation)=
-Motivation
-==========
+## Motivation
The filesystem library provides interfaces for getting and setting the last
-write time of a file or directory. The interfaces use the ``file_time_type``
-type, which is a specialization of ``chrono::time_point`` for the
+write time of a file or directory. The interfaces use the `file_time_type`
+type, which is a specialization of `chrono::time_point` for the
"filesystem clock". According to [fs.filesystem.syn]
- trivial-clock is an implementation-defined type that satisfies the
- Cpp17TrivialClock requirements ([time.clock.req]) and that is capable of
- representing and measuring file time values. Implementations should ensure
- that the resolution and range of file_time_type reflect the operating
- system dependent resolution and range of file time values.
+> trivial-clock is an implementation-defined type that satisfies the
+> Cpp17TrivialClock requirements ([time.clock.req]) and that is capable of
+> representing and measuring file time values. Implementations should ensure
+> that the resolution and range of file_time_type reflect the operating
+> system dependent resolution and range of file time values.
-
-On POSIX systems, file times are represented using the ``timespec`` struct,
+On POSIX systems, file times are represented using the `timespec` struct,
which is defined as follows:
-.. code-block:: cpp
-
- struct timespec {
- time_t tv_sec;
- long tv_nsec;
- };
+```cpp
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+```
-To represent the range and resolution of ``timespec``, we need to (A) have
-nanosecond resolution, and (B) use more than 64 bits (assuming a 64-bit ``time_t``).
+To represent the range and resolution of `timespec`, we need to (A) have
+nanosecond resolution, and (B) use more than 64 bits (assuming a 64-bit `time_t`).
-As the standard requires us to use the ``chrono`` interface, we have to define
+As the standard requires us to use the `chrono` interface, we have to define
our own filesystem clock which specifies the period and representation of
the time points and duration it provides. It will look like this:
-.. code-block:: cpp
-
- struct _FilesystemClock {
- using period = nano;
- using rep = TBD; // What is this?
+```cpp
+struct _FilesystemClock {
+ using period = nano;
+ using rep = TBD; // What is this?
- using duration = chrono::duration<rep, period>;
- using time_point = chrono::time_point<_FilesystemClock>;
+ using duration = chrono::duration<rep, period>;
+ using time_point = chrono::time_point<_FilesystemClock>;
- // ... //
- };
+ // ... //
+};
- using file_time_type = _FilesystemClock::time_point;
+using file_time_type = _FilesystemClock::time_point;
+```
-
-To get nanosecond resolution, we simply define ``period`` to be ``std::nano``.
+To get nanosecond resolution, we simply define `period` to be `std::nano`.
But what type can we use as the arithmetic representation that is capable
-of representing the range of the ``timespec`` struct?
+of representing the range of the `timespec` struct?
-Problems To Consider
-====================
+## Problems To Consider
Before considering solutions, let's consider the problems they should solve,
and how important solving those problems are:
-
-Having a Smaller Range than ``timespec``
-----------------------------------------
+### Having a Smaller Range than `timespec`
One solution to the range problem is to simply reduce the resolution of
-``file_time_type`` to be less than that of nanoseconds. This is what libc++'s
-initial implementation of ``file_time_type`` did; it's also what
-``std::system_clock`` does. As a result, it can represent time points about
+`file_time_type` to be less than that of nanoseconds. This is what libc++'s
+initial implementation of `file_time_type` did; it's also what
+`std::system_clock` does. As a result, it can represent time points about
292 thousand years on either side of the epoch, as opposed to only 292 years
at nanosecond resolution.
-``timespec`` can represent time points +/- 292 billion years from the epoch
+`timespec` can represent time points +/- 292 billion years from the epoch
(just in case you needed a time point 200 billion years before the big bang,
and with nanosecond resolution).
@@ -91,52 +84,49 @@ a value, then we should too. Our wrappers should not place artificial restrictio
on users that are not present in the underlying filesystem.
Having a smaller range that the underlying filesystem forces the
-implementation to report ``value_too_large`` errors when it encounters a time
-point that it can't represent. This can cause the call to ``last_write_time``
+implementation to report `value_too_large` errors when it encounters a time
+point that it can't represent. This can cause the call to `last_write_time`
to throw in cases where the user was confident the call should succeed. (See below)
-
-.. code-block:: cpp
-
- #include <filesystem>
- using namespace std::filesystem;
-
- // Set the times using the system interface.
- void set_file_times(const char* path, struct timespec ts) {
- timespec both_times[2];
- both_times[0] = ts;
- both_times[1] = ts;
- int result = ::utimensat(AT_FDCWD, path, both_times, 0);
- assert(result != -1);
- }
-
- // Called elsewhere to set the file time to something insane, and way
- // out of the 300 year range we might expect.
- void some_bad_persons_code() {
- struct timespec new_times;
- new_times.tv_sec = numeric_limits<time_t>::max();
- new_times.tv_nsec = 0;
- set_file_times("/tmp/foo", new_times); // OK, supported by most FSes
- }
-
- int main(int, char**) {
- path p = "/tmp/foo";
- file_status st = status(p);
- if (!exists(st) || !is_regular_file(st))
- return 1;
- if ((st.permissions() & perms::others_read) == perms::none)
- return 1;
- // It seems reasonable to assume this call should succeed.
- file_time_type tp = last_write_time(p); // BAD! Throws value_too_large.
- return 0;
- }
-
-
-Having a Smaller Resolution than ``timespec``
----------------------------------------------
+```cpp
+#include <filesystem>
+using namespace std::filesystem;
+
+// Set the times using the system interface.
+void set_file_times(const char* path, struct timespec ts) {
+ timespec both_times[2];
+ both_times[0] = ts;
+ both_times[1] = ts;
+ int result = ::utimensat(AT_FDCWD, path, both_times, 0);
+ assert(result != -1);
+}
+
+// Called elsewhere to set the file time to something insane, and way
+// out of the 300 year range we might expect.
+void some_bad_persons_code() {
+ struct timespec new_times;
+ new_times.tv_sec = numeric_limits<time_t>::max();
+ new_times.tv_nsec = 0;
+ set_file_times("/tmp/foo", new_times); // OK, supported by most FSes
+}
+
+int main(int, char**) {
+ path p = "/tmp/foo";
+ file_status st = status(p);
+ if (!exists(st) || !is_regular_file(st))
+ return 1;
+ if ((st.permissions() & perms::others_read) == perms::none)
+ return 1;
+ // It seems reasonable to assume this call should succeed.
+ file_time_type tp = last_write_time(p); // BAD! Throws value_too_large.
+ return 0;
+}
+```
+
+### Having a Smaller Resolution than `timespec`
As mentioned in the previous section, one way to solve the range problem
-is by reducing the resolution. But matching the range of ``timespec`` using a
+is by reducing the resolution. But matching the range of `timespec` using a
64 bit representation requires limiting the resolution to seconds.
So we might ask: Do users "need" nanosecond precision? Is seconds not good enough?
@@ -145,29 +135,27 @@ the underlying system interfaces? If it wasn't good enough for them, then it
isn't good enough for us. Our job is to match the filesystems range and
representation, not design it.
+### Having a Larger Range than `timespec`
-Having a Larger Range than ``timespec``
-----------------------------------------
-
-We should also consider the opposite problem of having a ``file_time_type``
-that is able to represent a larger range than ``timespec``. At least in
-this case ``last_write_time`` can be used to get and set all possible values
-supported by the underlying filesystem; meaning ``last_write_time(p)`` will
+We should also consider the opposite problem of having a `file_time_type`
+that is able to represent a larger range than `timespec`. At least in
+this case `last_write_time` can be used to get and set all possible values
+supported by the underlying filesystem; meaning `last_write_time(p)` will
never throw an overflow error when retrieving a value.
However, this introduces a new problem, where users are allowed to attempt to
create a time point beyond what the filesystem can represent. Two particular
-values which cause this are ``file_time_type::min()`` and
-``file_time_type::max()``. As a result, the following code would throw:
-
-.. code-block:: cpp
+values which cause this are `file_time_type::min()` and
+`file_time_type::max()`. As a result, the following code would throw:
- void test() {
- last_write_time("/tmp/foo", file_time_type::max()); // Throws
- last_write_time("/tmp/foo", file_time_type::min()); // Throws.
- }
+```cpp
+void test() {
+ last_write_time("/tmp/foo", file_time_type::max()); // Throws
+ last_write_time("/tmp/foo", file_time_type::min()); // Throws.
+}
+```
-Apart from cases explicitly using ``min`` and ``max``, I don't see users taking
+Apart from cases explicitly using `min` and `max`, I don't see users taking
a valid time point, adding a couple hundred billions of years in error,
and then trying to update a file's write time to that value very often.
@@ -179,15 +167,13 @@ I posit that we should only consider this concern *after* we have something
with at least the same range and resolution of the underlying filesystem. The
latter two problems are much more important to solve.
-Potential Solutions And Their Complications
-===========================================
+## Potential Solutions And Their Complications
-Source Code Portability Across Implementations
------------------------------------------------
+### Source Code Portability Across Implementations
-As we've discussed, ``file_time_type`` needs a representation that uses more
-than 64 bits. The possible solutions include using ``__int128_t``, emulating a
-128 bit integer using a class, or potentially defining a ``timespec`` like
+As we've discussed, `file_time_type` needs a representation that uses more
+than 64 bits. The possible solutions include using `__int128_t`, emulating a
+128 bit integer using a class, or potentially defining a `timespec` like
arithmetic type. All three will allow us to, at minimum, match the range
and resolution, and the last one might even allow us to match them exactly.
@@ -196,43 +182,42 @@ just the values they can represent. We need to consider the effects they will
have on users and their code. For example, each of them breaks the following
code in some way:
-.. code-block:: cpp
-
- // Bug caused by an unexpected 'rep' type returned by count.
- void print_time(path p) {
- // __int128_t doesn't have streaming operators, and neither would our
- // custom arithmetic types.
- cout << last_write_time(p).time_since_epoch().count() << endl;
- }
-
- // Overflow during creation bug.
- file_time_type timespec_to_file_time_type(struct timespec ts) {
- // woops! chrono::seconds and chrono::nanoseconds use a 64-bit representation
- // this may overflow before it's converted to a file_time_type.
- auto dur = seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec);
- return file_time_type(dur);
- }
-
- file_time_type correct_timespec_to_file_time_type(struct timespec ts) {
- // This is the correct version of the above example, where we
- // avoid using the chrono typedefs as they're not sufficient.
- // Can we expect users to avoid this bug?
- using fs_seconds = chrono::duration<file_time_type::rep>;
- using fs_nanoseconds = chrono::duration<file_time_type::rep, nano>;
- auto dur = fs_seconds(ts.tv_sec) + fs_nanoseconds(tv.tv_nsec);
- return file_time_type(dur);
- }
-
- // Implicit truncation during conversion bug.
- intmax_t get_time_in_seconds(path p) {
- using fs_seconds = duration<file_time_type::rep, ratio<1, 1> >;
- auto tp = last_write_time(p);
-
- // This works with truncation for __int128_t, but what does it do for
- // our custom arithmetic types.
- return duration_cast<fs_seconds>().count();
- }
-
+```cpp
+// Bug caused by an unexpected 'rep' type returned by count.
+void print_time(path p) {
+ // __int128_t doesn't have streaming operators, and neither would our
+ // custom arithmetic types.
+ cout << last_write_time(p).time_since_epoch().count() << endl;
+}
+
+// Overflow during creation bug.
+file_time_type timespec_to_file_time_type(struct timespec ts) {
+ // woops! chrono::seconds and chrono::nanoseconds use a 64-bit representation
+ // this may overflow before it's converted to a file_time_type.
+ auto dur = seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec);
+ return file_time_type(dur);
+}
+
+file_time_type correct_timespec_to_file_time_type(struct timespec ts) {
+ // This is the correct version of the above example, where we
+ // avoid using the chrono typedefs as they're not sufficient.
+ // Can we expect users to avoid this bug?
+ using fs_seconds = chrono::duration<file_time_type::rep>;
+ using fs_nanoseconds = chrono::duration<file_time_type::rep, nano>;
+ auto dur = fs_seconds(ts.tv_sec) + fs_nanoseconds(tv.tv_nsec);
+ return file_time_type(dur);
+}
+
+// Implicit truncation during conversion bug.
+intmax_t get_time_in_seconds(path p) {
+ using fs_seconds = duration<file_time_type::rep, ratio<1, 1> >;
+ auto tp = last_write_time(p);
+
+ // This works with truncation for __int128_t, but what does it do for
+ // our custom arithmetic types.
+ return duration_cast<fs_seconds>().count();
+}
+```
Each of the above examples would require a user to adjust their filesystem code
to the particular eccentricities of the representation, hopefully only in such
@@ -240,249 +225,242 @@ a way that the code is still portable across implementations.
At least some of the above issues are unavoidable, no matter what
representation we choose. But some representations may be quirkier than others,
-and, as I'll argue later, using an actual arithmetic type (``__int128_t``)
+and, as I'll argue later, using an actual arithmetic type (`__int128_t`)
provides the least aberrant behavior.
+### Chrono and `timespec` Emulation.
-Chrono and ``timespec`` Emulation.
-----------------------------------
-
-One of the options we've considered is using something akin to ``timespec``
-to represent the ``file_time_type``. It only seems natural seeing as that's
+One of the options we've considered is using something akin to `timespec`
+to represent the `file_time_type`. It only seems natural seeing as that's
what the underlying system uses, and because it might allow us to match
the range and resolution exactly. But would it work with chrono? And could
-it still act at all like a ``timespec`` struct?
+it still act at all like a `timespec` struct?
For ease of consideration, let's consider what the implementation might
look like.
-.. code-block:: cpp
-
- struct fs_timespec_rep {
- fs_timespec_rep(long long v)
- : tv_sec(v / nano::den), tv_nsec(v % nano::den)
- { }
- private:
- time_t tv_sec;
- long tv_nsec;
- };
- bool operator==(fs_timespec_rep, fs_timespec_rep);
- fs_int128_rep operator+(fs_timespec_rep, fs_timespec_rep);
- // ... arithmetic operators ... //
-
-The first thing to notice is that we can't construct ``fs_timespec_rep`` like
-a ``timespec`` by passing ``{secs, nsecs}``. Instead we're limited to
+```cpp
+struct fs_timespec_rep {
+ fs_timespec_rep(long long v)
+ : tv_sec(v / nano::den), tv_nsec(v % nano::den)
+ { }
+private:
+ time_t tv_sec;
+ long tv_nsec;
+};
+bool operator==(fs_timespec_rep, fs_timespec_rep);
+fs_int128_rep operator+(fs_timespec_rep, fs_timespec_rep);
+// ... arithmetic operators ... //
+```
+
+The first thing to notice is that we can't construct `fs_timespec_rep` like
+a `timespec` by passing `{secs, nsecs}`. Instead we're limited to
constructing it from a single 64-bit integer.
-We also can't allow the user to inspect the ``tv_sec`` or ``tv_nsec`` values
-directly. A ``chrono::duration`` represents its value as a tick period and a
-number of ticks stored using ``rep``. The representation is unaware of the
-tick period it is being used to represent, but ``timespec`` is setup to assume
-a nanosecond tick period; which is the only case where the names ``tv_sec``
-and ``tv_nsec`` match the values they store.
+We also can't allow the user to inspect the `tv_sec` or `tv_nsec` values
+directly. A `chrono::duration` represents its value as a tick period and a
+number of ticks stored using `rep`. The representation is unaware of the
+tick period it is being used to represent, but `timespec` is setup to assume
+a nanosecond tick period; which is the only case where the names `tv_sec`
+and `tv_nsec` match the values they store.
-When we convert a nanosecond duration to seconds, ``fs_timespec_rep`` will
-use ``tv_sec`` to represent the number of giga seconds, and ``tv_nsec`` the
+When we convert a nanosecond duration to seconds, `fs_timespec_rep` will
+use `tv_sec` to represent the number of giga seconds, and `tv_nsec` the
remaining seconds. Let's consider how this might cause a bug were users allowed
to manipulate the fields directly.
-.. code-block:: cpp
-
- template <class Period>
- timespec convert_to_timespec(duration<fs_time_rep, Period> dur) {
- fs_timespec_rep rep = dur.count();
- return {rep.tv_sec, rep.tv_nsec}; // Oops! Period may not be nanoseconds.
- }
-
- template <class Duration>
- Duration convert_to_duration(timespec ts) {
- Duration dur({ts.tv_sec, ts.tv_nsec}); // Oops! Period may not be nanoseconds.
- return file_time_type(dur);
- file_time_type tp = last_write_time(p);
- auto dur =
- }
-
- time_t extract_seconds(file_time_type tp) {
- // Converting to seconds is a silly bug, but I could see it happening.
- using SecsT = chrono::duration<file_time_type::rep, ratio<1, 1>>;
- auto secs = duration_cast<Secs>(tp.time_since_epoch());
- // tv_sec is now representing gigaseconds.
- return secs.count().tv_sec; // Oops!
- }
-
-Despite ``fs_timespec_rep`` not being usable in any manner resembling
-``timespec``, it still might buy us our goal of matching its range exactly,
+```cpp
+template <class Period>
+timespec convert_to_timespec(duration<fs_time_rep, Period> dur) {
+ fs_timespec_rep rep = dur.count();
+ return {rep.tv_sec, rep.tv_nsec}; // Oops! Period may not be nanoseconds.
+}
+
+template <class Duration>
+Duration convert_to_duration(timespec ts) {
+ Duration dur({ts.tv_sec, ts.tv_nsec}); // Oops! Period may not be nanoseconds.
+ return file_time_type(dur);
+ file_time_type tp = last_write_time(p);
+ auto dur =
+}
+
+time_t extract_seconds(file_time_type tp) {
+ // Converting to seconds is a silly bug, but I could see it happening.
+ using SecsT = chrono::duration<file_time_type::rep, ratio<1, 1>>;
+ auto secs = duration_cast<Secs>(tp.time_since_epoch());
+ // tv_sec is now representing gigaseconds.
+ return secs.count().tv_sec; // Oops!
+}
+```
+
+Despite `fs_timespec_rep` not being usable in any manner resembling
+`timespec`, it still might buy us our goal of matching its range exactly,
right?
Sort of. Chrono provides a specialization point which specifies the minimum
and maximum values for a custom representation. It looks like this:
-.. code-block:: cpp
-
- template <>
- struct duration_values<fs_timespec_rep> {
- static fs_timespec_rep zero();
- static fs_timespec_rep min();
- static fs_timespec_rep max() { // assume friendship.
- fs_timespec_rep val;
- val.tv_sec = numeric_limits<time_t>::max();
- val.tv_nsec = nano::den - 1;
- return val;
- }
- };
+```cpp
+template <>
+struct duration_values<fs_timespec_rep> {
+ static fs_timespec_rep zero();
+ static fs_timespec_rep min();
+ static fs_timespec_rep max() { // assume friendship.
+ fs_timespec_rep val;
+ val.tv_sec = numeric_limits<time_t>::max();
+ val.tv_nsec = nano::den - 1;
+ return val;
+ }
+};
+```
-Notice that ``duration_values`` doesn't tell the representation what tick
+Notice that `duration_values` doesn't tell the representation what tick
period it's actually representing. This would indeed correctly limit the range
-of ``duration<fs_timespec_rep, nano>`` to exactly that of ``timespec``. But
+of `duration<fs_timespec_rep, nano>` to exactly that of `timespec`. But
nanoseconds isn't the only tick period it will be used to represent. For
example:
-.. code-block:: cpp
-
- void test() {
- using rep = file_time_type::rep;
- using fs_nsec = duration<rep, nano>;
- using fs_sec = duration<rep>;
- fs_nsec nsecs(fs_seconds::max()); // Truncates
- }
+```cpp
+void test() {
+ using rep = file_time_type::rep;
+ using fs_nsec = duration<rep, nano>;
+ using fs_sec = duration<rep>;
+ fs_nsec nsecs(fs_seconds::max()); // Truncates
+}
+```
Though the above example may appear silly, I think it follows from the incorrect
-notion that using a ``timespec`` rep in chrono actually makes it act as if it
-were an actual ``timespec``.
+notion that using a `timespec` rep in chrono actually makes it act as if it
+were an actual `timespec`.
-Interactions with 32-bit ``time_t``
------------------------------------
+### Interactions with 32-bit `time_t`
-Up until now we've only be considering cases where ``time_t`` is 64 bits, but what
-about 32-bit systems/builds where ``time_t`` is 32 bits? (this is the common case
+Up until now we've only be considering cases where `time_t` is 64 bits, but what
+about 32-bit systems/builds where `time_t` is 32 bits? (this is the common case
for 32-bit builds).
-When ``time_t`` is 32 bits, we can implement ``file_time_type`` simply using 64-bit
-``long long``. There is no need to get either ``__int128_t`` or ``timespec`` emulation
+When `time_t` is 32 bits, we can implement `file_time_type` simply using 64-bit
+`long long`. There is no need to get either `__int128_t` or `timespec` emulation
involved. And nor should we, as it would suffer from the numerous complications
described by this paper.
Obviously our implementation for 32-bit builds should act as similarly to the
64-bit build as possible. Code which compiles in one, should compile in the other.
-This consideration is important when choosing between ``__int128_t`` and
-emulating ``timespec``. The solution which provides the most uniformity with
+This consideration is important when choosing between `__int128_t` and
+emulating `timespec`. The solution which provides the most uniformity with
the least eccentricity is the preferable one.
-Summary
-=======
+## Summary
-The ``file_time_type`` time point is used to represent the write times for files.
+The `file_time_type` time point is used to represent the write times for files.
Its job is to act as part of a C++ wrapper for less ideal system interfaces. The
-underlying filesystem uses the ``timespec`` struct for the same purpose.
+underlying filesystem uses the `timespec` struct for the same purpose.
-However, the initial implementation of ``file_time_type`` could not represent
-either the range or resolution of ``timespec``, making it unsuitable. Fixing
+However, the initial implementation of `file_time_type` could not represent
+either the range or resolution of `timespec`, making it unsuitable. Fixing
this requires an implementation which uses more than 64 bits to store the
time point.
-We primarily considered two solutions: Using ``__int128_t`` and using a
-arithmetic emulation of ``timespec``. Each has its pros and cons, and both
+We primarily considered two solutions: Using `__int128_t` and using a
+arithmetic emulation of `timespec`. Each has its pros and cons, and both
come with more than one complication.
-The Potential Solutions
------------------------
+### The Potential Solutions
-``long long`` - The Status Quo
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#### `long long` - The Status Quo
Pros:
-* As a type ``long long`` plays the nicest with others:
+- As a type `long long` plays the nicest with others:
- * It works with streaming operators and other library entities which support
- builtin integer types, but don't support ``__int128_t``.
- * Its the representation used by chrono's ``nanosecond`` and ``second`` typedefs.
+ - It works with streaming operators and other library entities which support
+ builtin integer types, but don't support `__int128_t`.
+ - Its the representation used by chrono's `nanosecond` and `second` typedefs.
Cons:
-* It cannot provide the same resolution as ``timespec`` unless we limit it
+- It cannot provide the same resolution as `timespec` unless we limit it
to a range of +/- 300 years from the epoch.
-* It cannot provide the same range as ``timespec`` unless we limit its resolution
+- It cannot provide the same range as `timespec` unless we limit its resolution
to seconds.
-* ``last_write_time`` has to report an error when the time reported by the filesystem
+- `last_write_time` has to report an error when the time reported by the filesystem
is unrepresentable.
-__int128_t
-~~~~~~~~~~~
+#### \_\_int128_t
Pros:
-* It is an integer type.
-* It makes the implementation simple and efficient.
-* Acts exactly like other arithmetic types.
-* Can be implicitly converted to a builtin integer type by the user.
+- It is an integer type.
- * This is important for doing things like:
+- It makes the implementation simple and efficient.
- .. code-block:: cpp
+- Acts exactly like other arithmetic types.
- void c_interface_using_time_t(const char* p, time_t);
+- Can be implicitly converted to a builtin integer type by the user.
- void foo(path p) {
- file_time_type tp = last_write_time(p);
- time_t secs = duration_cast<seconds>(tp.time_since_epoch()).count();
- c_interface_using_time_t(p.c_str(), secs);
- }
+ - This is important for doing things like:
+
+ ```cpp
+ void c_interface_using_time_t(const char* p, time_t);
+
+ void foo(path p) {
+ file_time_type tp = last_write_time(p);
+ time_t secs = duration_cast<seconds>(tp.time_since_epoch()).count();
+ c_interface_using_time_t(p.c_str(), secs);
+ }
+ ```
Cons:
-* It isn't always available (but on 64-bit machines, it normally is).
-* It causes ``file_time_type`` to have a larger range than ``timespec``.
-* It doesn't always act the same as other builtin integer types. For example
- with ``cout`` or ``to_string``.
-* Allows implicit truncation to 64-bit integers.
-* It can be implicitly converted to a builtin integer type by the user,
+- It isn't always available (but on 64-bit machines, it normally is).
+- It causes `file_time_type` to have a larger range than `timespec`.
+- It doesn't always act the same as other builtin integer types. For example
+ with `cout` or `to_string`.
+- Allows implicit truncation to 64-bit integers.
+- It can be implicitly converted to a builtin integer type by the user,
truncating its value.
-Arithmetic ``timespec`` Emulation
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#### Arithmetic `timespec` Emulation
Pros:
-* It has the exact same range and resolution of ``timespec`` when representing
+- It has the exact same range and resolution of `timespec` when representing
a nanosecond tick period.
-* It's always available, unlike ``__int128_t``.
+- It's always available, unlike `__int128_t`.
Cons:
-* It has a larger range when representing any period longer than a nanosecond.
-* Doesn't actually allow users to use it like a ``timespec``.
-* The required representation of using ``tv_sec`` to store the giga tick count
- and ``tv_nsec`` to store the remainder adds nothing over a 128 bit integer,
+- It has a larger range when representing any period longer than a nanosecond.
+- Doesn't actually allow users to use it like a `timespec`.
+- The required representation of using `tv_sec` to store the giga tick count
+ and `tv_nsec` to store the remainder adds nothing over a 128 bit integer,
but complicates a lot.
-* It isn't a builtin integer type, and can't be used anything like one.
-* Chrono can be made to work with it, but not nicely.
-* Emulating arithmetic classes come with their own host of problems regarding
+- It isn't a builtin integer type, and can't be used anything like one.
+- Chrono can be made to work with it, but not nicely.
+- Emulating arithmetic classes come with their own host of problems regarding
overload resolution (Each operator needs three SFINAE constrained versions of
it in order to act like builtin integer types).
-* It offers little over simply using ``__int128_t``.
-* It acts the most differently than implementations using an actual integer type,
+- It offers little over simply using `__int128_t`.
+- It acts the most differently than implementations using an actual integer type,
which has a high chance of breaking source compatibility.
+## Selected Solution - Using `__int128_t`
-Selected Solution - Using ``__int128_t``
-=========================================
+The solution I selected for libc++ is using `__int128_t` when available,
+and otherwise falling back to using `long long` with nanosecond precision.
-The solution I selected for libc++ is using ``__int128_t`` when available,
-and otherwise falling back to using ``long long`` with nanosecond precision.
-
-When ``__int128_t`` is available, or when ``time_t`` is 32-bits, the implementation
-provides same resolution and a greater range than ``timespec``. Otherwise
+When `__int128_t` is available, or when `time_t` is 32-bits, the implementation
+provides same resolution and a greater range than `timespec`. Otherwise
it still provides the same resolution, but is limited to a range of +/- 300
-years. This final case should be rather rare, as ``__int128_t``
-is normally available in 64-bit builds, and ``time_t`` is normally 32-bits
+years. This final case should be rather rare, as `__int128_t`
+is normally available in 64-bit builds, and `time_t` is normally 32-bits
during 32-bit builds.
-Although falling back to ``long long`` and nanosecond precision is less than
+Although falling back to `long long` and nanosecond precision is less than
ideal, it also happens to be the implementation provided by both libstdc++
and MSVC. (So that makes it better, right?)
-Although the ``timespec`` emulation solution is feasible and would largely
+Although the `timespec` emulation solution is feasible and would largely
do what we want, it comes with too many complications, potential problems
and discrepancies when compared to "normal" chrono time points and durations.
@@ -492,4 +470,5 @@ to expect them to tolerate and work around these differences. And once
we commit to an ABI it will be too late to change. Committing to this seems
risky.
-Therefore, ``__int128_t`` seems like the better solution.
+Therefore, `__int128_t` seems like the better solution.
+
diff --git a/libcxx/docs/DesignDocs/HeaderRemovalPolicy.md b/libcxx/docs/DesignDocs/HeaderRemovalPolicy.md
index e52b625fae8bc..5b6b62576d86b 100644
--- a/libcxx/docs/DesignDocs/HeaderRemovalPolicy.md
+++ b/libcxx/docs/DesignDocs/HeaderRemovalPolicy.md
@@ -1,19 +1,16 @@
-=====================
-Header Removal Policy
-=====================
+# Header Removal Policy
-Policy
-------
+## Policy
Libc++ is in the process of splitting larger headers into smaller modular
headers. This makes it possible to remove these large headers from other
-headers. For example, instead of including ``<algorithm>`` entirely it is
+headers. For example, instead of including `<algorithm>` entirely it is
possible to only include the headers for the algorithms used. When the
Standard indirectly adds additional header includes, using the smaller headers
-aids reducing the growth of top-level headers. For example ``<atomic>`` uses
-``std::chrono::nanoseconds`` and included ``<chrono>``. In C++20 ``<chrono>``
-requires ``<format>`` which adds several other headers (like ``<string>``,
-``<optional>``, ``<tuple>``) which are not needed in ``<atomic>``.
+aids reducing the growth of top-level headers. For example `<atomic>` uses
+`std::chrono::nanoseconds` and included `<chrono>`. In C++20 `<chrono>`
+requires `<format>` which adds several other headers (like `<string>`,
+`<optional>`, `<tuple>`) which are not needed in `<atomic>`.
The benefit of using minimal headers is that the size of libc++'s top-level
headers becomes smaller. This improves the compilation time when users include
@@ -23,7 +20,7 @@ to port headers to platforms with reduced functionality.
A disadvantage is that users unknowingly depend on these transitive includes.
Thus removing an include might break their build after upgrading a newer
version of libc++ by reducing the set of declarations provided by a header.
-For example, ``<algorithm>`` is often forgotten but using algorithms will
+For example, `<algorithm>` is often forgotten but using algorithms will
still work through those transitive includes. This problem is solved by modules,
however in practice most people do not use modules (yet).
@@ -42,13 +39,13 @@ do it in a user-friendly way, again within reason. For libc++ developers, this
means that any transitive include removal of a public header must be guarded by
something of the form:
-.. code-block:: cpp
-
- #if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 23
- # include <algorithm>
- # include <iterator>
- # include <utility>
- #endif
+```cpp
+#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 23
+# include <algorithm>
+# include <iterator>
+# include <utility>
+#endif
+```
Occasionally, private headers may also be included transitively for backwards
compatibility in the same manner. We currently strive to provide backwards
@@ -56,16 +53,14 @@ compatibility on the set of declarations provided by a header in all Standard
modes starting with **C++23**. Note that this is very difficult to actually
enforce, so this is done only on a best effort basis.
-When users define ``_LIBCPP_REMOVE_TRANSITIVE_INCLUDES``, libc++ will not include
+When users define `_LIBCPP_REMOVE_TRANSITIVE_INCLUDES`, libc++ will not include
transitive headers, regardless of the language version. This can be useful for users
to aid the transition to a newer language version, or by users who simply want to
make sure they include what they use in their code. However, note that defining this
macro means that the set of declarations and transitive includes provided by the library
may change from release to release, which can break your code.
-
-Rationale
----------
+## Rationale
Removing headers is not only an issue for software developers, but also for
vendors. When a vendor updates libc++ several of their upstream packages might
@@ -73,3 +68,4 @@ fail to compile, forcing them to fix these packages or file a bug with their
upstream packages. Usually upgrading software to a new language standard is
done explicitly by software developers. This means they most likely will
discover and fix the missing includes, lessening the burden for the vendors.
+
>From d3bd9e9afcc14538b66a64218fb4dfd2577c2fe9 Mon Sep 17 00:00:00 2001
From: Reid Kleckner <rkleckner at nvidia.com>
Date: Sat, 5 Sep 2026 04:10:05 +0000
Subject: [PATCH 2/3] [libc++][docs] Finish MyST migration
---
libcxx/docs/ABIGuarantees.md | 74 +++++++++----------
libcxx/docs/AddingNewCIJobs.md | 5 +-
libcxx/docs/CMakeLists.txt | 3 +
libcxx/docs/CodingGuidelines.md | 10 +--
libcxx/docs/Contributing.md | 5 +-
.../docs/Contributing/NewStandardProcedure.md | 1 -
.../docs/Contributing/PostMeetingProcedure.md | 1 -
libcxx/docs/DesignDocs/ABIVersioning.md | 1 -
libcxx/docs/DesignDocs/AtomicDesign.md | 3 +-
libcxx/docs/DesignDocs/CapturingConfigInfo.md | 1 -
.../docs/DesignDocs/ExperimentalFeatures.md | 7 +-
.../docs/DesignDocs/ExtendedCXX03Support.md | 5 +-
libcxx/docs/DesignDocs/FeatureTestMacros.md | 17 ++---
libcxx/docs/DesignDocs/FileTimeType.md | 1 -
libcxx/docs/DesignDocs/HeaderRemovalPolicy.md | 1 -
libcxx/docs/conf.py | 2 +-
16 files changed, 63 insertions(+), 74 deletions(-)
diff --git a/libcxx/docs/ABIGuarantees.md b/libcxx/docs/ABIGuarantees.md
index 6e94a2159764e..f58e22bdd6dc1 100644
--- a/libcxx/docs/ABIGuarantees.md
+++ b/libcxx/docs/ABIGuarantees.md
@@ -60,51 +60,50 @@ Changes the layout of {cpp:type}`std::vector` from pointer-based to size-based.
libc++ supports two different data layouts for {cpp:type}`std::vector`:
-```{eval-rst}
-.. list-table::
- :header-rows: 1
+:::{list-table}
+:header-rows: 1
- * - **Layout**
- - ABI
- - Description
- * - Pointer-based layout
- - Stable ABI (default)
- - :cpp:type:`std::vector` uses three pointers to manage its state:
+* - **Layout**
+ - ABI
+ - Description
+* - Pointer-based layout
+ - Stable ABI (default)
+ - {cpp:type}`std::vector` uses three pointers to manage its state:
- * A pointer to the beginning of the buffer (:cpp:expr:`begin_`);
- * A pointer to where the next element should be inserted (:cpp:expr:`end_`); and
- * A pointer to the end of the buffer (:cpp:expr:`cap_`).
+ * A pointer to the beginning of the buffer ({cpp:expr}`begin_`);
+ * A pointer to where the next element should be inserted ({cpp:expr}`end_`); and
+ * A pointer to the end of the buffer ({cpp:expr}`cap_`).
- This layout causes :cpp:type:`vector`'s implementation details to be pointer-oriented.
- The following methods are of particular interest:
+ This layout causes {cpp:type}`vector`'s implementation details to be pointer-oriented.
+ The following methods are of particular interest:
- * :cpp:expr:`vector::size()` returns :cpp:expr:`end_ - begin_`;
- * :cpp:expr:`vector::capacity()` returns :cpp:expr:`cap_ - begin_`; and
- * :cpp:expr:`vector::end()` returns :cpp:expr:`end_`.
+ * {cpp:expr}`vector::size()` returns {cpp:expr}`end_ - begin_`;
+ * {cpp:expr}`vector::capacity()` returns {cpp:expr}`cap_ - begin_`; and
+ * {cpp:expr}`vector::end()` returns {cpp:expr}`end_`.
- This is the original layout for libc++'s :cpp:type:`std::vector` implementation, and
- is the default layout as a result.
+ This is the original layout for libc++'s {cpp:type}`std::vector` implementation, and
+ is the default layout as a result.
- * - Size-based layout
- - Unstable ABI (opt-in)
- - :cpp:type:`std::vector` uses a pointer and two integers to manage its state:
+* - Size-based layout
+ - Unstable ABI (opt-in)
+ - {cpp:type}`std::vector` uses a pointer and two integers to manage its state:
- * A pointer to the beginning of the buffer (:cpp:expr:`begin_`);
- * An integer storing how many elements are in the vector (:cpp:expr:`size_`); and
- * An integer storing how many elements the vector can potentially hold before needing
- to reallocate (:cpp:expr:`capacity_`).
+ * A pointer to the beginning of the buffer ({cpp:expr}`begin_`);
+ * An integer storing how many elements are in the vector ({cpp:expr}`size_`); and
+ * An integer storing how many elements the vector can potentially hold before needing
+ to reallocate ({cpp:expr}`capacity_`).
- This layout causes :cpp:type:`vector`'s implementation details to be integer-oriented.
- The following methods are of particular interest:
+ This layout causes {cpp:type}`vector`'s implementation details to be integer-oriented.
+ The following methods are of particular interest:
- * :cpp:expr:`vector::size()` returns :cpp:expr:`size_`;
- * :cpp:expr:`vector::capacity()` returns :cpp:expr:`cap_`; and
- * :cpp:expr:`vector::end()` returns :cpp:expr:`begin_ + size_`.
+ * {cpp:expr}`vector::size()` returns {cpp:expr}`size_`;
+ * {cpp:expr}`vector::capacity()` returns {cpp:expr}`cap_`; and
+ * {cpp:expr}`vector::end()` returns {cpp:expr}`begin_ + size_`.
- This layout is opt-in, and is incompatible with the pointer-based layout. It has the
- potential for significant performance improvements, especially when combined with
- :ref:`hardening`.
-```
+ This layout is opt-in, and is incompatible with the pointer-based layout. It has the
+ potential for significant performance improvements, especially when combined with
+ {ref}`hardening`.
+:::
### `_LIBCPP_ABI_NO_RANDOM_DEVICE_COMPATIBILITY_LAYOUT`
@@ -145,8 +144,8 @@ flags like `-fexceptions`, which **do** change the observable behaviour. libc++
compiled with specific flags only and makes no guarantees for any of the flags not listed below.
The flags allowed (in any combination) are:
-\- `-f[no-]exceptions`
-\- `-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE{_FAST,_EXTENSIVE,_DEBUG,_NONE}`
+- `-f[no-]exceptions`
+- `-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE{_FAST,_EXTENSIVE,_DEBUG,_NONE}`
Note that this does not provide any guarantees about user-defined functions, but only that the libc++ functions linked
behave as the flags say.
@@ -255,4 +254,3 @@ mangling. Almost all of libc++'s symbols are inside an inline namespace. By defa
be changed by the vendor by setting `LIBCXX_ABI_NAMESPACE` during CMake configuration. There is also
`_LIBCPP_ABI_NO_FILESYSTEM_INLINE_NAMESPACE` to remove the `__fs` namespace from surrounding the `filesystem`
namespace. This shortens the mangling of the filesystem symbols a bit.
-
diff --git a/libcxx/docs/AddingNewCIJobs.md b/libcxx/docs/AddingNewCIJobs.md
index 2e059a750b782..02de072a7a42b 100644
--- a/libcxx/docs/AddingNewCIJobs.md
+++ b/libcxx/docs/AddingNewCIJobs.md
@@ -2,9 +2,9 @@
# Adding New CI Jobs
-```{contents}
+:::{contents}
:local: true
-```
+:::
## Adding The Job
@@ -66,4 +66,3 @@ order to avoid flaky failures, which reduce the value of CI for everyone.
We may be reluctant to add and support CI jobs that take a long time to finish
or that are too flaky.
-
diff --git a/libcxx/docs/CMakeLists.txt b/libcxx/docs/CMakeLists.txt
index d679761a5adb0..7e79fffe8d3b8 100644
--- a/libcxx/docs/CMakeLists.txt
+++ b/libcxx/docs/CMakeLists.txt
@@ -5,5 +5,8 @@ if (LLVM_ENABLE_SPHINX)
if (${SPHINX_OUTPUT_HTML})
add_sphinx_target(html libcxx)
endif()
+ if (${SPHINX_OUTPUT_MAN})
+ add_sphinx_target(man libcxx)
+ endif()
endif()
endif()
diff --git a/libcxx/docs/CodingGuidelines.md b/libcxx/docs/CodingGuidelines.md
index 266ed0f291d04..11e2404407a60 100644
--- a/libcxx/docs/CodingGuidelines.md
+++ b/libcxx/docs/CodingGuidelines.md
@@ -137,7 +137,7 @@ possible. They do force more eager evaluation though, which can be a problem in
## Apply `[[nodiscard]]` where relevant
-Libc++ adds `[[nodiscard]]` whenever relevant to catch potential bugs. The standards committee has decided to \_not\_
+Libc++ adds `[[nodiscard]]` whenever relevant to catch potential bugs. The standards committee has decided to *not*
have a recommended practice where to put them, so libc++ applies it whenever it makes sense to catch potential bugs.
`[[nodiscard]]` should be applied to functions
@@ -163,9 +163,10 @@ have a recommended practice where to put them, so libc++ applies it whenever it
in the presence of future optimizations.
`[[nodiscard]]` should not be applied to functions if Clang already diagnoses unused results, for example:
-\- conversion functions
-\- equality operators
-\- relational operators
+
+- conversion functions
+- equality operators
+- relational operators
Applications of `[[nodiscard]]` are code like any other code, so we aim to test them on public interfaces. This can be
done with a `.verify.cpp` test. Many examples are available. Just look for tests with the suffix
@@ -209,4 +210,3 @@ after the function they are measuring, with a few transformations to help filter
When multiple benchmarks measure the same function under different circumstances, we add context as a parenthesis
after the function signature. For example, `std::vector<bool>::ctor(Self&&, const allocator_type&) (equal allocators)`
would be the allocator-aware move constructor for `std::vector<bool>` in the case of equal allocators.
-
diff --git a/libcxx/docs/Contributing.md b/libcxx/docs/Contributing.md
index e3bb5d5bb9ba7..f30fcd558b7f9 100644
--- a/libcxx/docs/Contributing.md
+++ b/libcxx/docs/Contributing.md
@@ -154,7 +154,7 @@ updated list from the failed build at
Look for the failed build and select the `artifacts` tab. There, download the
abilist for the platform, e.g.:
-- C++\<version>.
+- `C++<version>`.
- macOS X86_64 and macOS arm64 for the Apple platform.
## Pre-commit CI
@@ -182,7 +182,7 @@ are used to build libc++ and execute its tests.
Unless specified otherwise, the configurations:
- use a nightly build of the `main` branch of Clang,
-- execute the tests using the language C++\<latest>. This is the version
+- execute the tests using the language `C++<latest>`. This is the version
"developed" by the C++ committee.
:::{note}
@@ -336,4 +336,3 @@ Contains the jobs executed in the CI. This file contains the version
information of the jobs being executed. Since this script differs between the
`main` and `release` branch, both branches can use different compiler
versions.
-
diff --git a/libcxx/docs/Contributing/NewStandardProcedure.md b/libcxx/docs/Contributing/NewStandardProcedure.md
index 16f8c5432fbfa..151997515c291 100644
--- a/libcxx/docs/Contributing/NewStandardProcedure.md
+++ b/libcxx/docs/Contributing/NewStandardProcedure.md
@@ -33,4 +33,3 @@ is noticed.
- Add any missing FTMs for the new standard version in the FTM generation script
- Regenerate the FTM files
- Update the tests for the FTM generation script itself
-
diff --git a/libcxx/docs/Contributing/PostMeetingProcedure.md b/libcxx/docs/Contributing/PostMeetingProcedure.md
index d3b1fba0d026e..0dbe3522c174d 100644
--- a/libcxx/docs/Contributing/PostMeetingProcedure.md
+++ b/libcxx/docs/Contributing/PostMeetingProcedure.md
@@ -98,4 +98,3 @@ libcxx/utils/conformance csv synchronize libcxx/docs/Status/Cxx<NN>Issues.csv \
```
This can then be committed as a follow-up PR.
-
diff --git a/libcxx/docs/DesignDocs/ABIVersioning.md b/libcxx/docs/DesignDocs/ABIVersioning.md
index 40c85d71f56eb..94d57267f8967 100644
--- a/libcxx/docs/DesignDocs/ABIVersioning.md
+++ b/libcxx/docs/DesignDocs/ABIVersioning.md
@@ -25,4 +25,3 @@ directly.
The exception to this is MSVC environments. Libc++ does not currently have users
that require a stable ABI in MSVC environments, so MSVC-only changes may be
applied unconditionally.
-
diff --git a/libcxx/docs/DesignDocs/AtomicDesign.md b/libcxx/docs/DesignDocs/AtomicDesign.md
index 9a6ba94e5196d..7a378da85eedf 100644
--- a/libcxx/docs/DesignDocs/AtomicDesign.md
+++ b/libcxx/docs/DesignDocs/AtomicDesign.md
@@ -491,7 +491,7 @@ Where:
the library defines `__atomic_flag__` as a typedef to `bool`.
- To communicate that the above intrinsics are available, the compiler must
arrange for `__has_feature` to return 1 when fed the intrinsic name
- appended with an '\_' and the mangled type name of `__atomic_flag__`.
+ appended with an '_' and the mangled type name of `__atomic_flag__`.
For example if `__atomic_flag__` is `unsigned int`:
@@ -788,4 +788,3 @@ void bar() { return A.compare_exchange_strong(y, z); }
If only **one** of these calls to `compare_exchange_strong` is implemented with
mutex-locked code, then that mutex-locked code will not be executed mutually
exclusively of the one implemented in a lock-free manner.
-
diff --git a/libcxx/docs/DesignDocs/CapturingConfigInfo.md b/libcxx/docs/DesignDocs/CapturingConfigInfo.md
index b9083ed794f63..e9e0694a300a9 100644
--- a/libcxx/docs/DesignDocs/CapturingConfigInfo.md
+++ b/libcxx/docs/DesignDocs/CapturingConfigInfo.md
@@ -58,4 +58,3 @@ include/<targetB>/c++/v1/
When compiling for `targetA`, Clang will use the `__config_site` inside
`include/<targetA>/c++/v1/`, and the corresponding `__config_site` for
`targetB`.
-
diff --git a/libcxx/docs/DesignDocs/ExperimentalFeatures.md b/libcxx/docs/DesignDocs/ExperimentalFeatures.md
index 8522383c8bc3d..5d611f2ca80f5 100644
--- a/libcxx/docs/DesignDocs/ExperimentalFeatures.md
+++ b/libcxx/docs/DesignDocs/ExperimentalFeatures.md
@@ -1,10 +1,10 @@
# Experimental Features
-```{contents}
+:::{contents}
:local: true
-```
+:::
-(experimental-features-1)=
+(experimental features)=
## Overview
@@ -188,4 +188,3 @@ We have not yet shipped an implementation of the Concurrency TS.
% | 4 | Atomic Smart Pointers | | | Adopted for C++20 |
% +---------+-------------------------------------------------------+--------------------+------------------------------------------+-------------------------+
-
diff --git a/libcxx/docs/DesignDocs/ExtendedCXX03Support.md b/libcxx/docs/DesignDocs/ExtendedCXX03Support.md
index 40911fd6a2a3c..f71742182eeef 100644
--- a/libcxx/docs/DesignDocs/ExtendedCXX03Support.md
+++ b/libcxx/docs/DesignDocs/ExtendedCXX03Support.md
@@ -1,8 +1,8 @@
# Extended C++03 Support
-```{contents}
+:::{contents}
:local: true
-```
+:::
## Overview
@@ -43,4 +43,3 @@ in new code.
This section will be updated once the libc++ developer community has further discussed the
future of C++03 with libc++.
:::
-
diff --git a/libcxx/docs/DesignDocs/FeatureTestMacros.md b/libcxx/docs/DesignDocs/FeatureTestMacros.md
index 8799442319028..7aeadf7dfc794 100644
--- a/libcxx/docs/DesignDocs/FeatureTestMacros.md
+++ b/libcxx/docs/DesignDocs/FeatureTestMacros.md
@@ -1,8 +1,8 @@
# Feature Test Macros
-```{contents}
+:::{contents}
:local: true
-```
+:::
## Overview
@@ -18,22 +18,21 @@ different dialects, and they may or may not be implemented by libc++. In order t
track all of these conditions correctly and easily, we want a Single Source of
Truth (SSoT) that defines each feature test macro, its values, the headers it
lives in, and whether or not it is implemented by libc++. From this SSoA we
-have enough information to automatically generate the `<version>` header,
+have enough information to automatically generate the {title-reference}`<version>` header,
the tests, and the documentation.
-Therefore we maintain a SSoA in `libcxx/utils/generate_feature_test_macro_components.py`
+Therefore we maintain a SSoA in {title-reference}`libcxx/utils/generate_feature_test_macro_components.py`
which doubles as a script to generate the following components:
-- The `<version>` header.
-- The version tests under `support.limits.general`.
+- The {title-reference}`<version>` header.
+- The version tests under {title-reference}`support.limits.general`.
- Documentation of libc++'s implementation of each macro.
## Usage
-The `generate_feature_test_macro_components.py` script is used to track and
+The {title-reference}`generate_feature_test_macro_components.py` script is used to track and
update feature test macros in libc++.
Whenever a feature test macro is added or changed, the table should be updated
and the script should be re-ran. The script will clobber the existing test files,
-the documentation and the `<version>` header.
-
+the documentation and the {title-reference}`<version>` header.
diff --git a/libcxx/docs/DesignDocs/FileTimeType.md b/libcxx/docs/DesignDocs/FileTimeType.md
index c625c8260e692..0a6ce1708159f 100644
--- a/libcxx/docs/DesignDocs/FileTimeType.md
+++ b/libcxx/docs/DesignDocs/FileTimeType.md
@@ -471,4 +471,3 @@ we commit to an ABI it will be too late to change. Committing to this seems
risky.
Therefore, `__int128_t` seems like the better solution.
-
diff --git a/libcxx/docs/DesignDocs/HeaderRemovalPolicy.md b/libcxx/docs/DesignDocs/HeaderRemovalPolicy.md
index 5b6b62576d86b..69d54f119e144 100644
--- a/libcxx/docs/DesignDocs/HeaderRemovalPolicy.md
+++ b/libcxx/docs/DesignDocs/HeaderRemovalPolicy.md
@@ -68,4 +68,3 @@ fail to compile, forcing them to fix these packages or file a bug with their
upstream packages. Usually upgrading software to a new language standard is
done explicitly by software developers. This means they most likely will
discover and fix the missing includes, lessening the burden for the vendors.
-
diff --git a/libcxx/docs/conf.py b/libcxx/docs/conf.py
index 729c5211f18a2..46828391e592c 100644
--- a/libcxx/docs/conf.py
+++ b/libcxx/docs/conf.py
@@ -193,7 +193,7 @@
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
-man_pages = [("contents", "libc++", "libc++ Documentation", ["LLVM project"], 1)]
+man_pages = [("index", "libc++", "libc++ Documentation", ["LLVM project"], 1)]
# If true, show URL addresses after external links.
# man_show_urls = False
>From 9b13054136c8df07442a4216ac6d06d8daff23bb Mon Sep 17 00:00:00 2001
From: Reid Kleckner <rkleckner at nvidia.com>
Date: Sun, 27 Sep 2026 14:43:32 +0000
Subject: [PATCH 3/3] [libc++][docs] Address Markdown conversion review
feedback
---
libcxx/docs/CMakeLists.txt | 3 ---
libcxx/docs/DesignDocs/FileTimeType.md | 2 +-
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/libcxx/docs/CMakeLists.txt b/libcxx/docs/CMakeLists.txt
index 7e79fffe8d3b8..d679761a5adb0 100644
--- a/libcxx/docs/CMakeLists.txt
+++ b/libcxx/docs/CMakeLists.txt
@@ -5,8 +5,5 @@ if (LLVM_ENABLE_SPHINX)
if (${SPHINX_OUTPUT_HTML})
add_sphinx_target(html libcxx)
endif()
- if (${SPHINX_OUTPUT_MAN})
- add_sphinx_target(man libcxx)
- endif()
endif()
endif()
diff --git a/libcxx/docs/DesignDocs/FileTimeType.md b/libcxx/docs/DesignDocs/FileTimeType.md
index 0a6ce1708159f..451e1cce0f106 100644
--- a/libcxx/docs/DesignDocs/FileTimeType.md
+++ b/libcxx/docs/DesignDocs/FileTimeType.md
@@ -386,7 +386,7 @@ Cons:
- `last_write_time` has to report an error when the time reported by the filesystem
is unrepresentable.
-#### \_\_int128_t
+#### `__int128_t`
Pros:
More information about the llvm-branch-commits
mailing list