[libc-commits] [libc] [llvm] [libc] Clean up libc_errno implementation, dependencies, and add __errno_location alias (PR #235421)

via libc-commits libc-commits at lists.llvm.org
Sun Oct 25 04:00:13 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: lntue

<details>
<summary>Changes</summary>

### Summary

- **Inline `struct Errno` in `libc_errno.h`**:
  - Inline `Errno::operator=(int)`, `Errno::operator int()`, and `Errno::operator&()` (`LIBC_INLINE ... const noexcept`) in `libc/src/__support/libc_errno.h` and replace `extern Errno libc_errno;` with `LIBC_INLINE_VAR constexpr Errno libc_errno{}`.
  - Simplify `libc/src/errno/libc_errno.cpp` so that it only defines the backing storage (`thread_errno` / `shared_errno`) and `extern "C" int *__llvm_libc_errno() noexcept`.
- **Add `__errno_location` GNU/glibc ABI alias**:
  - Add `LIBC_COPT_PROVIDE_GNU_ALIASES` (defaulting to `false` in `libc/config/config.json` and `true` in `libc/config/linux/config.json`) to emit `__errno_location` as a C symbol alias of `__llvm_libc_errno` via `LLVM_LIBC_ADD_FUNCTION_C_ALIAS`.
  - Declare `int *__errno_location(void) __NOEXCEPT;` in `libc/include/errno.h.def`.
  - Remove the manual `__errno_location` shim from `libc/test/UnitTest/HermeticTestUtils.cpp` and add `libc.src.errno.errno` to `_get_libc_coverage_dependencies`.
- **Fix `LIBC_ERRNO_MODE` resolution for `libc/shared/libc_common.h`**:
  - Handle `-DLIBC_ERRNO_MODE=LIBC_ERRNO_MODE_DEFAULT` in `libc/shared/libc_common.h` and `libc/src/__support/libc_errno.h` so `libc/shared/*` consumers resolve `LIBC_ERRNO_MODE_DEFAULT` to `LIBC_ERRNO_MODE_SYSTEM_INLINE` in overlay/shared builds while preserving the target's `LIBC_ERRNO_MODE` in full-build hermetic tests.
- **Clean up `libc.src.errno.errno` dependencies in `libc/src/__support/`**:
  - Remove stale `libc.src.errno.errno` dependencies from `libc/src/__support/` targets (`FPUtil`, `math`, `StringUtil/tables`, `File/linux`, `threads/linux`, `printf_core`), replacing them with `libc.hdr.errno_macros` or `libc.src.__support.libc_errno`.
  - Split the header-only `syscall` target out of `linux_util` (`osutil`) in `libc/src/__support/OSUtil/linux/` so `syscall_wrappers` depend only on `libc.src.__support.OSUtil.linux.syscall`.
  - Automatically link `libc.src.errno.errno` in `_get_libc_test_dependencies`, `add_libc_fuzzer`, and `perf_test`, and enable `libc.test.src.errno.errno_test` in overlay mode.
- **Documentation**:
  - Add a developer guide on `errno` and `libc_errno` architecture and usage in `libc/docs/dev/errno.md` and update `libc/docs/dev/code_style.md`.

Assisted-by: Gemini


---

Patch is 78.09 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/235421.diff


36 Files Affected:

- (modified) libc/cmake/modules/LLVMLibCCompileOptionRules.cmake (+4) 
- (modified) libc/cmake/modules/LLVMLibCTestRules.cmake (+4-3) 
- (modified) libc/config/config.json (+4) 
- (modified) libc/config/linux/config.json (+5) 
- (modified) libc/docs/dev/code_style.md (+34-28) 
- (added) libc/docs/dev/errno.md (+191) 
- (modified) libc/docs/dev/index.md (+1) 
- (modified) libc/include/errno.h.def (+1) 
- (modified) libc/shared/libc_common.h (+5-5) 
- (modified) libc/src/__support/CMakeLists.txt (+1) 
- (modified) libc/src/__support/FPUtil/CMakeLists.txt (+3-4) 
- (modified) libc/src/__support/FPUtil/ManipulationFunctions.h (+1) 
- (modified) libc/src/__support/FPUtil/NearestIntegerOperations.h (+1) 
- (modified) libc/src/__support/File/linux/CMakeLists.txt (+1-2) 
- (modified) libc/src/__support/File/linux/file.cpp (+1-1) 
- (modified) libc/src/__support/OSUtil/linux/CMakeLists.txt (+16-2) 
- (modified) libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt (+137-138) 
- (modified) libc/src/__support/StringUtil/tables/CMakeLists.txt (+2-2) 
- (modified) libc/src/__support/StringUtil/tables/linux_extension_errors.h (+1-1) 
- (modified) libc/src/__support/libc_errno.h (+19-4) 
- (modified) libc/src/__support/math/CMakeLists.txt (+4-6) 
- (modified) libc/src/__support/math/cos.h (+1) 
- (modified) libc/src/__support/math/exp10m1f.h (+1-1) 
- (modified) libc/src/__support/math/exp2m1f.h (+1-1) 
- (modified) libc/src/__support/math/expm1.h (+1) 
- (modified) libc/src/__support/math/expm1f.h (+1) 
- (modified) libc/src/__support/math/sin.h (+1) 
- (modified) libc/src/__support/printf_core/CMakeLists.txt (+1) 
- (modified) libc/src/__support/threads/linux/CMakeLists.txt (-1) 
- (modified) libc/src/__support/threads/linux/thread.cpp (-1) 
- (modified) libc/src/errno/libc_errno.cpp (+8-24) 
- (modified) libc/test/UnitTest/HermeticTestUtils.cpp (-3) 
- (modified) libc/test/src/errno/CMakeLists.txt (+1-1) 
- (modified) libc/test/src/errno/errno_test.cpp (+5) 
- (modified) libc/test/src/math/performance_testing/CMakeLists.txt (+1) 
- (modified) utils/bazel/llvm-project-overlay/libc/BUILD.bazel (+1) 


``````````diff
diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
index b26c1957880a5f..dec75057333fd8 100644
--- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
+++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
@@ -210,6 +210,10 @@ function(_get_compile_options_from_config output_var)
     list(APPEND config_options "-DLIBC_COPT_SCANF_PROVIDE_ISOC99_ALIASES")
   endif()
 
+  if(LIBC_COPT_PROVIDE_GNU_ALIASES)
+    libc_add_definition(config_options "LIBC_COPT_PROVIDE_GNU_ALIASES")
+  endif()
+
   set(${output_var} ${config_options} PARENT_SCOPE)
 endfunction()
 _get_compile_options_from_config(LIBC_COMPILE_OPTIONS_FROM_CONFIG)
diff --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake
index e9cd18ad076048..25aa8187a207e5 100644
--- a/libc/cmake/modules/LLVMLibCTestRules.cmake
+++ b/libc/cmake/modules/LLVMLibCTestRules.cmake
@@ -413,6 +413,7 @@ endfunction()
 # needed to support code coverage profiling in hermetic/full-build mode.
 function(_get_libc_coverage_dependencies output_var)
   set(${output_var}
+    libc.src.errno.errno
     libc.src.stdio.fclose
     libc.src.stdio.fdopen
     libc.src.stdio.feof
@@ -459,6 +460,7 @@ endfunction()
 # entrypoints, subprocess support, and coverage dependencies.
 function(_get_libc_test_dependencies output_var user_depends startup_target_dep is_c_test is_fp_test is_integration_test)
   get_fq_deps_list(fq_deps_list ${user_depends})
+  list(APPEND fq_deps_list libc.src.errno.errno)
   if(is_integration_test)
     list(APPEND fq_deps_list
       generate-libc-headers
@@ -815,8 +817,7 @@ function(create_libc_test fq_target_name)
   )
 
   target_include_directories(${fq_build_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
-  target_include_directories(${fq_build_target_name} PRIVATE ${LIBC_SOURCE_DIR})
-  target_include_directories(${fq_build_target_name} PRIVATE ${LIBC_BUILD_DIR})
+  target_include_directories(${fq_build_target_name} PRIVATE ${LIBC_SOURCE_DIR} ${LIBC_BUILD_DIR})
 
   _get_common_test_compile_options(compile_options "${TEST_C_TEST}" "${TEST_FLAGS}")
   target_compile_options(${fq_build_target_name} PRIVATE ${compile_options} ${TEST_COMPILE_OPTIONS})
@@ -909,7 +910,7 @@ function(add_libc_fuzzer target_name)
 
 
   get_fq_target_name(${target_name} fq_target_name)
-  get_fq_deps_list(fq_deps_list ${LIBC_FUZZER_DEPENDS})
+  get_fq_deps_list(fq_deps_list ${LIBC_FUZZER_DEPENDS} libc.src.errno.errno)
   get_object_files_for_test(
     link_object_files skipped_entrypoints_list ${fq_deps_list})
   if(skipped_entrypoints_list)
diff --git a/libc/config/config.json b/libc/config/config.json
index 604b03c9b5688a..d58002a84330f1 100644
--- a/libc/config/config.json
+++ b/libc/config/config.json
@@ -175,6 +175,10 @@
     "LIBC_ADD_NULL_CHECKS": {
       "value": true,
       "doc": "Add nullptr checks in the library's implementations to some functions for which passing nullptr is undefined behavior."
+    },
+    "LIBC_COPT_PROVIDE_GNU_ALIASES": {
+      "value": false,
+      "doc": "Provide GNU/glibc compatibility symbol aliases (such as __errno_location)."
     }
   },
   "wctype": {
diff --git a/libc/config/linux/config.json b/libc/config/linux/config.json
index 260ec3b43f72c3..bc27cfd1b9e0e5 100644
--- a/libc/config/linux/config.json
+++ b/libc/config/linux/config.json
@@ -1,4 +1,9 @@
 {
+  "general": {
+    "LIBC_COPT_PROVIDE_GNU_ALIASES": {
+      "value": true
+    }
+  },
   "scanf": {
     "LIBC_CONF_SCANF_PROVIDE_ISOC99_ALIASES": {
       "value": "${LLVM_LIBC_OVERLAY}"
diff --git a/libc/docs/dev/code_style.md b/libc/docs/dev/code_style.md
index bfc13f0d0be2ee..e0bd8e6fb975a3 100644
--- a/libc/docs/dev/code_style.md
+++ b/libc/docs/dev/code_style.md
@@ -98,17 +98,20 @@ the system libc is affected. When a libc function that can potentially affect
 affected. If the global `errno` is affected, then the operation of the unit
 test infrastructure itself can be affected.
 
-To handle `errno` correctly across all build modes and avoid silent thread-local
-storage mismatches, the following rules must be followed:
+For a complete architectural overview of `errno` modes (`LIBC_ERRNO_MODE`),
+targets, and build rules, see {doc}`errno`. To handle `errno` correctly across
+all build modes and avoid silent thread-local storage mismatches, the following
+rules must be followed:
 
 1. **Header Inclusion:**
-   Runtime code and unit tests must **ONLY** `#include "src/__support/libc_errno.h"`
-   and refer to `libc_errno`.
+   Runtime code and unit tests that read or write `errno` must **ONLY**
+   `#include "src/__support/libc_errno.h"` and refer to `libc_errno`.
    - Never `#include <errno.h>`.
    - Never `#include "src/errno/libc_errno.h"` (this is a legacy path; the header
      lives in `src/__support/`).
-   - For standard error constants (such as `EINVAL`, `ENOMEM`), include
-     `"hdr/errno_macros.h"`.
+   - If a file only needs standard error constants (such as `EINVAL`, `ENOMEM`)
+     and does not read or write `libc_errno`, include `"hdr/errno_macros.h"`
+     instead.
 
    Setting `errno` should be done directly via `libc_errno`:
 
@@ -126,35 +129,38 @@ storage mismatches, the following rules must be followed:
    to return error values.
 
 3. **CMake Dependencies for Public Entrypoints:**
-   Any entrypoint that reads or sets `errno` should ideally declare **BOTH** of the
-   following in the `DEPENDS` list of its `add_entrypoint_object`:
-   - **`libc.src.__support.libc_errno`**: Satisfies the header dependency for
-     `src/__support/libc_errno.h`.
-   - **`libc.src.errno.errno`**: Satisfies the link-time requirement for the compiled
-     runtime storage (`libc_errno.cpp`) defining `thread_errno`, `__llvm_libc_errno()`,
-     and the C++ `Errno` class.
+   - Entrypoints that only use error macros (for example, `pthread_*` functions
+     returning `EINVAL` directly) should depend on **`libc.hdr.errno_macros`**.
+   - Entrypoints that read or set `libc_errno` should declare
+     **`libc.src.__support.libc_errno`** (for the `src/__support/libc_errno.h`
+     header and inline `Errno` wrapper) and **`libc.src.errno.errno`** (for the
+     compiled runtime storage in `libc_errno.cpp` defining `thread_errno` /
+     `shared_errno` and `__llvm_libc_errno()`).
 
    While LLVM-libc generally disallows dependencies between public entrypoints,
    `libc.src.errno.errno` is an **explicitly allowed exception** in the build system
-   (see `ALLOWED_DEPS` in `libc/cmake/modules/LLVMLibCObjectRules.cmake`). Downstream
-   consumers and test suites that link the entrypoint require this dependency so that
-   the storage for `libc_errno` is linked.
+   (see `ALLOWED_DEPS` in `libc/cmake/modules/LLVMLibCObjectRules.cmake`).
 
 4. **CMake Dependencies for Internal Support Libraries:**
-   Header-only utility libraries under `libc/src/__support/` (such as `OSUtil` syscall
-   wrappers or `FPUtil`) that reference `libc_errno.h` should depend on
-   **`libc.src.__support.libc_errno`** so they remain pure header libraries without
-   introducing compiled entrypoint object dependencies.
+   Targets under `libc/src/__support/` must **never** depend on
+   `libc.src.errno.errno` (both because `libc/src/__support` is configured
+   before `libc/src/errno` and because header-only `libc/shared/*` and math
+   consumers must not pull in `libc_errno.cpp`). Instead:
+   - Support libraries that only need error constants (`EINVAL`, etc.) must
+     depend on **`libc.hdr.errno_macros`**.
+   - Support libraries that reference `libc_errno` must depend on
+     **`libc.src.__support.libc_errno`**.
 
 5. **Unit and Hermetic Testing:**
-   Unit tests verifying functions that set `errno` must use the `ErrnoCheckingTest`
-   fixture (`test/UnitTest/ErrnoCheckingTest.h`) and `ErrnoSetterMatcher`
-   (`test/UnitTest/ErrnoSetterMatcher.h`).
-   - Both `ErrnoCheckingTest` and `ErrnoSetterMatcher` already declare `DEPENDS libc.src.errno.errno`,
-     so tests using them inherit the compiled `errno` object transitively.
-   - Tests that check `libc_errno` directly without those matchers must declare
-     `libc.src.errno.errno` in their test `DEPENDS`.
-   - Tests must never `#include <errno.h>`.
+   Unit tests verifying functions that set `errno` should use the
+   `ErrnoCheckingTest` fixture (`test/UnitTest/ErrnoCheckingTest.h`) and
+   `ErrnoSetterMatcher` (`test/UnitTest/ErrnoSetterMatcher.h`).
+   - Test targets created with `add_libc_test`, `add_fp_unittest`,
+     `add_integration_test`, and `add_libc_fuzzer` (as well as
+     `ErrnoCheckingTest` and `ErrnoSetterMatcher`) automatically link
+     `libc.src.errno.errno`.
+   - Tests must never `#include <errno.h>` (except `libc/test/shared/*`, which
+     tests the public header-only `libc/shared/*` interface).
 
 6. **The "Dual-TLS" Pitfall in Overlay Mode:**
    Why is strictly adhering to `libc_errno` and `"src/__support/libc_errno.h"` critical?
diff --git a/libc/docs/dev/errno.md b/libc/docs/dev/errno.md
new file mode 100644
index 00000000000000..6c18cfce0068bc
--- /dev/null
+++ b/libc/docs/dev/errno.md
@@ -0,0 +1,191 @@
+(errno)=
+
+# `errno` and `libc_errno` in LLVM-libc
+
+Many C standard library and POSIX functions report errors by setting `errno`.
+Because LLVM-libc supports multiple deployment models—including
+{doc}`../full_host_build`, {doc}`../full_cross_build`, {doc}`../overlay_mode`,
+baremetal targets, GPUs, and header-only consumption via `libc/shared/`—access
+to `errno` inside the library and its test suites is abstracted through
+`libc_errno`.
+
+This guide explains how `libc_errno` is architected, the supported
+`LIBC_ERRNO_MODE` configurations, and the rules for using `libc_errno` in source
+files, build targets, and tests.
+
+## Architecture Overview: Header vs. Runtime Storage
+
+In LLVM-libc, `errno` support is split across three distinct targets:
+
+| CMake Target | Header / Source | Purpose |
+| :--- | :--- | :--- |
+| `libc.hdr.errno_macros` | `libc/hdr/errno_macros.h` | Provides standard error number constants (`EINVAL`, `ERANGE`, `EDOM`, `ENOMEM`, etc.) without declaring `libc_errno`. |
+| `libc.src.__support.libc_errno` | `libc/src/__support/libc_errno.h` | Declares `libc_errno` (either as `#define libc_errno errno` or as `LIBC_INLINE_VAR constexpr Errno libc_errno{}`). |
+| `libc.src.errno.errno` | `libc/src/errno/libc_errno.cpp` | Defines the runtime backing storage (`thread_errno` or `shared_errno`), the public C symbol `extern "C" int *__llvm_libc_errno() noexcept`, and (when `LIBC_COPT_PROVIDE_GNU_ALIASES` is enabled) its Linux/glibc ABI alias `extern "C" int *__errno_location() noexcept`. |
+
+### Why `libc.src.__support.libc_errno` and `libc.src.errno.errno` Are Separated
+
+Keeping the `libc_errno` header library separate from the `libc.src.errno.errno`
+object target is required for five reasons:
+
+1. **Isolating Unit Tests from Host `errno` in Overlay Mode ("Dual-TLS")**:
+   - When building the public overlay archive (`libllvmlibc.a`), entrypoints are
+     compiled with `-DLIBC_COPT_PUBLIC_PACKAGING`, which resolves `libc_errno`
+     to the host system's `<errno.h>` (`LIBC_ERRNO_MODE_SYSTEM_INLINE`).
+   - When building unit tests (`add_libc_test`), entrypoints and tests are
+     compiled *without* `-DLIBC_COPT_PUBLIC_PACKAGING`, which resolves
+     `libc_errno` to LLVM-libc's internal thread-local storage
+     (`LIBC_ERRNO_MODE_THREAD_LOCAL`). This guarantees that running a test never
+     clobbers the host libc's `errno` used by the test harness itself (and vice
+     versa).
+
+2. **Header-Only Shared Libraries (`libc/shared/*`)**:
+   - External LLVM subprojects (such as `libc++` and the offloading runtime)
+     consume internal headers under `libc/src/__support/` via `libc/shared/*.h`.
+   - `libc/shared/libc_common.h` configures `LIBC_ERRNO_MODE_SYSTEM_INLINE` so
+     that `libc_errno` maps directly to `<errno.h>` without compiling or linking
+     `libc_errno.cpp`.
+
+3. **`errno`-Free Math and Vector Math (`FEnvImpl.h`)**:
+   - `libc/src/__support/FPUtil/FEnvImpl.h` includes `src/__support/libc_errno.h`
+     to implement `fputil::set_errno_if_required(int err)`, which guards
+     `libc_errno = err;` behind `if (!cpp::is_constant_evaluated())` and
+     `#ifndef LIBC_MATH_HAS_NO_ERRNO`.
+   - Vector math functions (`libc/src/__support/mathvec/`), builds with
+     `LIBC_MATH_NO_ERRNO` or `LIBC_MATH_FAST`, and scalar math functions that
+     only manipulate floating-point exceptions or rounding modes (`ceil`,
+     `floor`, `trunc`, `round`, `rint`, `copysign`, `frexp`, `modf`, etc.)
+     include `FEnvImpl.h` but emit no link-time reference to
+     `__llvm_libc_errno()`.
+
+4. **Archive Separation (`libc.a` vs. `libm.a` / `libmvec.a`)**:
+   - In full builds, `libc.src.errno.errno` belongs in `libc.a`
+     (`TARGET_LIBC_ENTRYPOINTS`) and must not be packaged into `libm.a` or
+     `libmvec.a`.
+
+5. **Topological Directory Ordering**:
+   - `libc/src/CMakeLists.txt` configures `add_subdirectory(__support)` before
+     `add_subdirectory(errno)` because `libc.src.errno.errno` depends on
+     `libc.src.__support.*`. Targets under `libc/src/__support/` therefore
+     cannot depend on `libc.src.errno.errno`.
+
+## `LIBC_ERRNO_MODE` Configurations
+
+The behavior of `libc_errno` is controlled by the `LIBC_CONF_ERRNO_MODE` CMake
+option (passed to the compiler as `-DLIBC_ERRNO_MODE=<mode>`). In
+`libc/src/__support/libc_errno.h`, `Errno::operator=(int)` and
+`Errno::operator int()` are defined inline (`LIBC_INLINE`), delegating to
+`*__llvm_libc_errno()` when runtime storage is used:
+
+| Mode | `libc_errno` Implementation | Backing Storage (`libc_errno.cpp`) | Typical Use Case |
+| :--- | :--- | :--- | :--- |
+| **`LIBC_ERRNO_MODE_DEFAULT`** | Auto-selects `SYSTEM_INLINE` or `THREAD_LOCAL` (see below). | `thread_errno` (`THREAD_LOCAL`) | Default CMake / Bazel configuration. |
+| **`LIBC_ERRNO_MODE_THREAD_LOCAL`** | `Errno` inline wrapper calling `*__llvm_libc_errno()`. | `LIBC_THREAD_LOCAL int thread_errno;` | Full builds on Linux/macOS/Windows; overlay unit tests. |
+| **`LIBC_ERRNO_MODE_SHARED`** | `Errno` inline wrapper calling `*__llvm_libc_errno()`. | Global `int shared_errno;` | Single-threaded or thread-local-free targets (GPU, UEFI). |
+| **`LIBC_ERRNO_MODE_EXTERNAL`** | `Errno` inline wrapper calling `*__llvm_libc_errno()`. | None (provided by external embedder). | Baremetal targets (`libc/config/baremetal/config.json`). |
+| **`LIBC_ERRNO_MODE_UNDEFINED`** | `Errno` inline no-op (`operator=` does nothing, `operator int()` returns `0`). | None (empty TU). | Minimal embedded environments without `errno`. |
+| **`LIBC_ERRNO_MODE_SYSTEM_INLINE`** | `#define libc_errno errno` (from system `<errno.h>`). | None (empty TU). | Overlay public archive (`libllvmlibc.a`) and `libc/shared/*`. |
+
+### How `LIBC_ERRNO_MODE_DEFAULT` Resolves
+
+When `LIBC_ERRNO_MODE` is unset or set to `LIBC_ERRNO_MODE_DEFAULT`,
+`libc/src/__support/libc_errno.h` resolves it as follows:
+
+- If `LIBC_FULL_BUILD` is defined: resolves to `LIBC_ERRNO_MODE_THREAD_LOCAL`.
+- Otherwise (overlay / non-full build):
+  - If `LIBC_COPT_PUBLIC_PACKAGING` is defined (building `libllvmlibc.a`) **or**
+    `LLVM_LIBC_SHARED_LIBC_COMMON_H` is defined (included after
+    `libc/shared/libc_common.h`): resolves to `LIBC_ERRNO_MODE_SYSTEM_INLINE`.
+  - Otherwise (building unit tests, fuzzers, or benchmarks): resolves to
+    `LIBC_ERRNO_MODE_THREAD_LOCAL`.
+
+## Usage Rules for Contributors
+
+### 1. Header Inclusion in Source and Test Files
+
+- **Never `#include <errno.h>`** in implementation (`libc/src/**`) or test
+  (`libc/test/**`) files.
+- **If you only need error constants (`EINVAL`, `ERANGE`, `EDOM`, `ENOMEM`, etc.)**:
+  Include `"hdr/errno_macros.h"`:
+
+  ```c++
+  #include "hdr/errno_macros.h"
+  ```
+
+- **If you read or write `errno`**:
+  Include `"src/__support/libc_errno.h"` and access `libc_errno`:
+
+  ```c++
+  #include "src/__support/libc_errno.h"
+
+  // Setting errno:
+  libc_errno = EINVAL;
+  ```
+
+  *(Note: `"src/__support/libc_errno.h"` transitively includes
+  `"hdr/errno_macros.h"`, though including `"hdr/errno_macros.h"` explicitly when
+  using error macros is good practice.)*
+
+### 2. Where to Set `libc_errno`
+
+- Set `libc_errno` **only** at the top-level public entrypoint boundary
+  (`LLVM_LIBC_FUNCTION`) just before returning an error value, or via
+  `fputil::set_errno_if_required` in math implementations.
+- Internal helper functions in `libc/src/__support/` should **not** mutate
+  `libc_errno` directly (unless specifically designed as an `errno`-reporting
+  layer). Instead, return `ErrorOr<T>` (`cpp::expected<T, int>`) or
+  `cpp::optional<T>` and convert the error at the entrypoint boundary:
+
+  ```c++
+  LLVM_LIBC_FUNCTION(int, close, (int fd)) {
+    auto res = linux_syscalls::close(fd);
+    if (!res) {
+      libc_errno = res.error();
+      return -1;
+    }
+    return 0;
+  }
+  ```
+
+### 3. CMake `DEPENDS` Rules
+
+Choose the CMake dependency that matches how the target uses `errno`:
+
+1. **Internal Support Libraries (`libc/src/__support/**`)**:
+   - Only uses error constants (`EINVAL`, etc.):
+     `DEPENDS libc.hdr.errno_macros`
+   - Reads or writes `libc_errno`:
+     `DEPENDS libc.src.__support.libc_errno`
+   - **Never** add `libc.src.errno.errno` to a target in `libc/src/__support/**`.
+
+2. **Public Entrypoints (`add_entrypoint_object` under `libc/src/`)**:
+   - Only uses error constants (for example, `pthread_*` functions that return
+     `EINVAL` directly without setting `errno`):
+     `DEPENDS libc.hdr.errno_macros`
+   - Reads or writes `libc_errno`:
+     `DEPENDS libc.src.__support.libc_errno` (and `libc.src.errno.errno` for
+     non-math `libc.a` entrypoints). Note that `libc.src.errno.errno` is the
+     only entrypoint target permitted in another entrypoint's `DEPENDS` list
+     (`ALLOWED_DEPS` in `LLVMLibCObjectRules.cmake`).
+
+3. **Header-Only Shared Tests (`libc/test/shared/*`)**:
+   - Must include `shared/<header>.h` (which includes `shared/libc_common.h`)
+     **before** any internal headers or test headers so that
+     `LLVM_LIBC_SHARED_LIBC_COMMON_H` is defined prior to
+     `src/__support/libc_errno.h`.
+   - When checking `errno` in `libc/test/shared/*`, inspect `errno` directly
+     (since `shared/` uses `LIBC_ERRNO_MODE_SYSTEM_INLINE` in overlay builds and
+     public `<errno.h>` in full builds).
+
+4. **Unit Tests, Integration Tests, Fuzzers, and Performance Tests**:
+   - `add_libc_test`, `add_fp_unittest`, `add_integration_test`,
+     `add_libc_fuzzer`, and `perf_test` automatically link
+     `libc.src.errno.errno`.
+   - Unit tests that verify `errno` behavior should use `ErrnoCheckingTest`
+     (`test/UnitTest/ErrnoCheckingTest.h`) and/or `ErrnoSetterMatcher`
+     (`test/UnitTest/ErrnoSetterMatcher.h`):
+     - `ErrnoCheckingTest` resets `libc_errno = 0` before each `TEST_F` body and
+       asserts that `libc_errno` is `0` at the end of the test (requiring tests
+       that intentionally trigger errors to validate and clear `libc_errno`).
+     - `ErrnoSetterMatcher` (`ASSERT_THAT(..., Fails(EINVAL))` / `Succeeds()`)
+       automatically checks and resets `libc_errno`.
diff --git a/libc/docs/dev/index.md b/libc/docs/dev/index.md
index 25b8102c71059b..fc9711c2ab5cfc 100644
--- a/libc/docs/dev/index.md
+++ b/libc/docs/dev/index.md
@@ -12,6 +12,7 @@ code_style
 source_tree_layout
 entrypoints
 implementing_a_function
+errno
 config_options
 date_and_time
 fuzzing
diff --git a/libc/include/errno.h.def b/libc/include/errno.h.def
index f731accc3b24bf..d08dcfdb14074c 100644
--- a/libc/include/errno.h.def
+++ b/libc/include/errno.h.def
@@ -36,6 +36,7 @@
 __BEGIN_C_DECLS
 
 int *__llvm_libc_errno(void) __NOEXCEPT;
+int *__errno_location(void) __NOEXCEPT;
 
 __END_C_DECLS
 
diff --git a/libc/shared/libc_common.h b/libc/shared/libc_common.h
index 5f7bebdee04b92..60db6b84ba3b7a 100644
--- a/libc/shared/libc_common.h
+++ b/libc/shared/libc_common.h
@@ -10,13 +10,13 @@
 #define LLVM_LIBC_SHARED_LIBC_COMMON_H
 
 // Use system errno.
-#ifdef LIBC_ERRNO_MODE
-#if LIBC_ERRNO_MODE != LIBC_ERRNO_MODE_SYSTEM_INLINE
+#ifndef LIBC_ERRNO_MODE
+#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_SYSTEM_INLINE
+#elif defined(LLVM_LIBC_SRC___SUPPORT_LIBC_ERRNO_H) &&                         \
+    !defined(LIBC_FULL_B...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/235421


More information about the libc-commits mailing list