| (CodingGuidelines)= |
| |
| # libc++ Coding Guidelines |
| |
| ```{contents} |
| :local: true |
| ``` |
| |
| ## 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. |
| |
| 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 |
| |
| 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, |
| 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: |
| |
| ```cpp |
| for (; __first1 != __last1; ++__first1, (void)++__first2) { |
| ... |
| } |
| ``` |
| |
| This is mostly enforced by the clang-tidy check `libcpp-robust-against-adl`. |
| |
| ## 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. |
| 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 |
| |
| `_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`. |
| |
| ## 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 |
| |
| ```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 |
| #endif |
| ``` |
| |
| 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, |
| so this guideline only applies when introducing a new macro. |
| |
| This is partially enforced by the clang-tidy check `libcpp-internal-ftms`. |
| |
| ## Use `_LIBCPP_STD_VER` |
| |
| 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`. |
| |
| ## 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 |
| 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`. |
| |
| ## 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 |
| 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). |
| |
| 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` |
| |
| `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 |
| |
| `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` |
| |
| 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. |
| |
| ## 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 |
| |
| 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 |
| |
| - where discarding the return value is most likely a correctness issue. For example a locking constructor in |
| `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()`. |
| |
| 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()`. |
| |
| 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)`. |
| |
| 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 |
| |
| 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 |
| |
| 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 |
| 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). |
| |
| 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` |
| |
| 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`) |
| should be annotated for the same reason. |
| |
| This is enforced by the clang-tidy check `libcpp-nodebug-on-aliases`. |
| |
| ## 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 |
| 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. |