1 2<details> 3<summary>License and copyright</summary> 4 5CDDL HEADER START 6 7The contents of this file are subject to the terms of the 8Common Development and Distribution License (the "License"). 9You may not use this file except in compliance with the License. 10 11You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 12or http://www.opensolaris.org/os/licensing. 13See the License for the specific language governing permissions 14and limitations under the License. 15 16When distributing Covered Code, include this CDDL HEADER in each 17file and include the License file at usr/src/OPENSOLARIS.LICENSE. 18If applicable, add the following below this CDDL HEADER, with the 19fields enclosed by brackets "[]" replaced with your own identifying 20information: Portions Copyright [yyyy] [name of copyright owner] 21 22CDDL HEADER END 23 24Copyright 2026 Gordon W. Ross 25 26</details> 27 28# Guidance for headers used in C++ 29 30## Background 31 32Two models exist for how C system headers expose library names to C++: 33 34**std-primary**: ISO C library functions are declared inside `namespace std {}`. 35The global namespace (`::`) is then populated via `using std::func` declarations. 36 37**global-primary**: ISO C library functions are declared directly in `::` via 38`extern "C" {}`. The `std::` namespace is then populated via `using ::func` 39declarations. 40 41For future illumos header work, use the **global-primary** model. It matches 42what modern C++ toolchains expect, keeps the C declarations in their natural 43namespace, and gives a clear rule for what may be exposed in `namespace std`. 44 45The most important cautionary example is IL-15209. In `<math.h>`, a 46std-primary layout let `using std::log` pull the float, double, and long double 47overloads into `::`, which made `log(int)` ambiguous. The guidance below is 48intended to prevent that class of problem when updating existing headers or 49adding C++ support to new ones. 50 51--- 52 53## Standards Basis: What Belongs in `::` vs. `namespace std` 54 55For a C header such as `<math.h>`, the practical guidance is: 56 57- put the C declarations in `::` 58- populate `namespace std` only with names the C++ standard requires 59- keep extension names in `::`, not in `namespace std` 60- use Pattern B for math functions and other functions commonly called with 61 integer arguments 62 63Those rules follow from the C and C++ standards, summarized here. 64 65### The C standard 66 67The C standard defines only the `double` forms of math functions in `<math.h>` 68(for example, `double log(double)`). The `float` and `long double` variants 69(`logf`, `logl`) are separate C function names, not overloads. Therefore, the 70C standard places only the `double` form in `::`. 71 72### C++11 §D.5 `[depr.c.headers]` 73 74C++11 Annex D §5 says: 75 76> Each C header `<name.h>` behaves as if each name placed in the standard 77> library namespace by the corresponding `<cname>` header is placed within the 78> global namespace scope. 79 80Read literally, this suggests that `<math.h>` should also expose in `::` the 81names that `<cmath>` places in `namespace std`. But the same paragraph makes 82the mechanism **implementation-defined**: 83 84> It is unspecified whether these names are first declared or defined within 85> namespace scope of the namespace `std` and are then injected into the global 86> namespace scope by explicit using-declarations. 87 88In illumos headers, that flexibility should be used in a way that keeps the 89rules simple for future maintenance: 90 91- C declarations stay in `::` 92- `namespace std` is populated explicitly, by `using ::func` and by C++-only 93 inlines where needed 94- the system header does not try to pre-populate `::` with every C++ overload 95 96### Pattern A: type variant overloads in `::` 97 98Pattern A puts C++-only type variant overloads in `::` alongside the 99C-standard form. `using ::func` in `namespace std` then brings all overloads 100at once. 101 102Use Pattern A only for functions not commonly called with integer arguments. 103For such functions, the layout is simple and there is no practical ambiguity 104problem. 105 106### Pattern B: type variant overloads in `namespace std` only 107 108For math functions, Pattern B is required: 109 110- `::` gets only what the C standard defines: for example, `double log(double)`. 111- `namespace std` gets that form via `using ::log`, plus the float and long 112 double overloads as C++-only inlines defined directly in `namespace std`. 113 114This avoids the IL-15209 failure mode. C++11 `[c.math]` requires `<cmath>` to 115provide enough overloads for calls such as `log(1)` to work without ambiguity. 116On GCC, the integer-covering support lives inside `namespace std`, not in `::`. 117If the float and long double overloads are also placed in `::`, `log(1)` becomes 118ambiguous. Pattern B keeps those overloads where the C++ library expects them. 119 120GCC signals this expectation with `__CORRECT_ISO_CPP_MATH_H_PROTO` 121(via `os_defines.h`). When that macro is defined, libstdc++ expects the system 122header to have already provided the type variant overloads in `namespace std` 123and skips adding its own. 124 125### Compatibility with other systems 126 127The illumos guidance here is intended to make header behavior more predictable 128for code written against other Unix-like systems and modern C++ libraries. 129 130**glibc (Linux) and FreeBSD** place no C++ overloads in `<math.h>` at all. 131Their system headers declare the C functions in `::`, and their C++ libraries 132handle the overload sets in `<cmath>`. 133([glibc math/math.h](https://github.com/bminor/glibc/blob/glibc-2.42/math/math.h), 134[FreeBSD lib/msun/src/math.h](https://github.com/freebsd/freebsd-src/blob/stable/14/lib/msun/src/math.h)) 135 136**LLVM libc++** uses a self-contained arrangement based on an internal 137`std::__math` namespace. It does not rely on illumos-style system header 138coordination, but it still follows the general expectation that the C library 139declarations live in `::` and the C++ library manages the overload model. 140([libcxx/include/math.h](https://github.com/llvm/llvm-project/blob/release/20.x/libcxx/include/math.h), 141[libcxx/include/cmath](https://github.com/llvm/llvm-project/blob/release/20.x/libcxx/include/cmath), 142[libcxx/include/__math/trigonometric_functions.h](https://github.com/llvm/llvm-project/blob/release/20.x/libcxx/include/__math/trigonometric_functions.h)) 143 144**libstdc++** uses Pattern B by default. Its `<cmath>` puts the type variant 145overloads in `namespace std`, and on Solaris or illumos it uses 146`__CORRECT_ISO_CPP_MATH_H_PROTO` to decide whether the system header already 147did that work. 148([libstdc++-v3/include/c_global/cmath](https://github.com/gcc-mirror/gcc/blob/releases/gcc-14/libstdc++-v3/include/c_global/cmath), 149[libstdc++-v3/include/bits/std_abs.h](https://github.com/gcc-mirror/gcc/blob/releases/gcc-14/libstdc++-v3/include/bits/std_abs.h)) 150 151For illumos, the key compatibility point is with **libstdc++**. If the system 152header uses global-primary structure and Pattern B for math, the system header 153and the C++ library cooperate cleanly. 154([libstdc++-v3/config/os/solaris/os_defines.h](https://github.com/gcc-mirror/gcc/blob/releases/gcc-14/libstdc++-v3/config/os/solaris/os_defines.h)) 155 156### In what namespace are extensions? 157 158Extension symbols (those gated on `__EXTENSIONS__`, `_XOPEN_SOURCE`, or 159similar macros) are declared in the C++ global namespace (`::`) only. 160`namespace std` is populated exclusively with names the C++ standard requires. 161This keeps the rule simple: if a name is an extension, it belongs in `::`. 162 163--- 164 165## Why Change from std-primary to global-primary? 166 167The older illumos headers were developed when the C and C++ standards were 168still evolving and when SunPro was the primary compiler. Today the important 169goal is to make future header work predictable and compatible with modern C++ 170toolchains. Adopting the global-primary model gives several advantages: 171 1721. **Standards conformance.** C declarations belong in `::` by definition; that 173 is what `extern "C"` means. The std-primary model placed them in 174 `namespace std` as a primary residence, which is non-standard. Global-primary 175 aligns with both the C standard (declarations in `::`) and the C++ standard 176 (`namespace std` contains what `<cname>` is required to provide). 177 1782. **Mismatch with other platforms.** glibc, FreeBSD, macOS, and other major 179 Unix systems use global-primary: C declarations in `::`, with the C++ library 180 responsible for populating `namespace std`. illumos being different causes 181 portability friction for application code. 182 1833. **Extension pollution of `namespace std`.** In the std-primary model it is 184 easy to accidentally declare extension symbols (those gated on `__EXTENSIONS__` 185 or `_XOPEN_SOURCE`) inside `namespace std`. The global-primary model makes 186 the boundary explicit: extensions go in `::` only, and `namespace std` is 187 populated exclusively via deliberate `using ::func` aliases. 188 1894. **Bugs from over-population of `::`.** The outer headers use `using std::func` 190 to pull names from `namespace std` into `::`. When `namespace std` contains 191 type variant overloads (float, long double), all of them land in `::` at once, 192 with no integer-covering template to resolve ambiguous calls. IL-15209 193 (`log(int)` ambiguous) is one instance of this class of bug. 194 195--- 196 197## Header Structure 198 199See the [`header-template.h`](#Header-template) below for the canonical 200annotated example. Each ISO header is structured into six sections: 201 202### Core principle 203 204The **global namespace is primary**. `std::` is secondary, populated only 205with what the C++ standard requires. 206 207illumos headers are currently in transition. Many still follow the old 208std-primary model. See [Status by header](#status-by-header) for the current 209state of each header. 210 211### Section 1: Unconditional C declarations (C++ global namespace) 212Standard C library functions are declared with C linkage, visible to both C 213and C++ translation units: 214 215```cpp 216#ifdef __cplusplus 217extern "C" { 218#endif 219 220extern double log(double); 221extern double acos(double); 222/* ... */ 223 224#ifdef __cplusplus 225} /* extern "C" */ 226#endif 227``` 228 229The outer header (`<math.h>`) needs no `using std::log` lines; `::log` is 230already there from the declaration. 231 232### Section 2: Conditional C declarations (C++ global namespace) 233Functions gated on environment macros (`_C99_SOURCE`, `_XOPEN_SOURCE`, 234`__EXTENSIONS__`, etc.) declared in `::` under the appropriate guards. 235Extension symbols (`__EXTENSIONS__`) are **not** aliased into `namespace std`. 236 237### Section 3: C-linkage helpers for C++ only (C++ global namespace) 238Type-variant C functions needed solely by C++ overloaded inlines in Section 4, 239with no purpose in C translation units. For `<math.h>` this means the `*f` 240and `*l` variants, declared inside the `extern "C"` block but guarded by 241`#ifdef __cplusplus`: 242 243```cpp 244#ifdef __cplusplus 245extern float acosf(float); 246extern long double acosl(long double); 247#endif 248``` 249 250### Sections 4–6: C++ block (always a separate top-level `extern "C++"`) 251 252The `extern "C++"` block is **never nested inside `extern "C"`**. It opens 253after the `extern "C"` block closes. 254 255**Section 4: C++ overloaded inlines (C++ global namespace or `namespace std`).** 256Where the inlines live depends on which pattern applies 257(see [Standards Basis](#standards-basis-what-belongs-in--vs-namespace-std)): 258 259- **Pattern A**: inlines go in the C++ global namespace (`extern "C++"` at 260 file scope, outside any `namespace` block). A subsequent `using ::func` 261 in Section 6 brings all overloads into `namespace std` at once. Safe only 262 for functions not commonly called with integer arguments. 263- **Pattern B**: no inlines here. Inlines are defined directly inside 264 `namespace std` in Section 6. Required for math functions (`log`, `sin`, 265 etc.) to prevent `log(1)` ambiguity. 266 267```cpp 268#if __cplusplus >= 199711L 269extern "C++" { 270 271 /* Pattern A: global namespace; acos(1) is unambiguous */ 272 inline float acos(float __x) { return acosf(__x); } 273 inline long double acos(long double __x) { return acosl(__x); } 274 275 /* Pattern B functions have no inlines here; see Section 6 */ 276``` 277 278**Section 5: C++ overloads for conditionally-exposed functions (C++ global 279namespace).** Same `extern "C++"` block. Type variant inlines for functions 280declared in Section 2, placed in the C++ global namespace and guarded by the 281same environment macro conditions (`_C99_SOURCE`, `_XOPEN_SOURCE`, 282`__EXTENSIONS__`, etc.) as their Section 2 declarations: 283 284```cpp 285#if defined(__EXTENSIONS__) 286 inline float acospi(float __x) { return acospif(__x); } 287 inline long double acospi(long double __x) { return acospil(__x); } 288#endif 289``` 290 291**Section 6: `namespace std`** (same `extern "C++"` block). Populated with 292only the names the C++ standard requires. No extensions. Pattern B inlines 293are defined here inside `namespace std`: 294 295```cpp 296 namespace std { 297 using ::acos; /* Pattern A: brings double+float+ldbl */ 298 299 using ::log; /* Pattern B: double form only */ 300 inline float log(float __x) { return logf(__x); } 301 inline long double log(long double __x) { return logl(__x); } 302 } 303 304} /* extern "C++" */ 305#endif /* __cplusplus >= 199711L */ 306``` 307 308## Header template 309 310``` 311/* 312 * top matter (CDDL, copyrights) 313 */ 314 315/* 316 * Global-primary namespace model 317 * -------------------------------- 318 * All C library function declarations go in the global namespace (::) 319 * inside extern "C" {}. The C++ standard namespace (std::) is then 320 * populated exclusively via "using ::" aliases, never by redeclaring 321 * symbols inside "namespace std {}". 322 * 323 * C++ requires additional type variant overloads (e.g., math.h's float 324 * and long double forms of acos). These are: 325 * - Forward-declared with C linkage inside extern "C" (Section 3) 326 * - Provided as overloaded inlines via extern "C++" (Sections 4 or 6) 327 * - Brought into std:: in Section 6 328 * 329 * There are two patterns for where the inlines live: 330 * 331 * Pattern A: inlines in :: (global namespace). 332 * "using ::func" in namespace std then brings all type variant 333 * overloads into std:: in one declaration. Use this when the 334 * function is unlikely to be called with integer arguments. 335 * 336 * Pattern B: inlines in namespace std only. 337 * "using ::func" brings only the C-standard (e.g., double) form 338 * into std::. Type variant inlines are defined directly in 339 * namespace std. Use this for functions that may be called with 340 * integer arguments: if type variant overloads were in ::, a call 341 * like log(1) would be ambiguous. Math functions use Pattern B. 342 * 343 * The extern "C++" block is always separate from (never nested inside) 344 * extern "C" {}. 345 */ 346 347#ifndef _INCLUDE_GUARD_ 348#define _INCLUDE_GUARD_ 349 350/* prerequisite includes etc. */ 351#include <sys/feature_tests.h> 352 353/* 354 * Section 1: Unconditional C linkage declarations (global namespace ::) 355 * 356 * Visible to both C and C++. For example, math.h declares 357 * `double acos(double)` here. 358 */ 359#ifdef __cplusplus 360extern "C" { 361#endif 362 363extern double acos(double); 364 365/* 366 * Section 2: Conditionally exposed declarations (global namespace ::) 367 * 368 * Functions exposed based on the compilation environment: C standard 369 * version (_C99_SOURCE, _C11_SOURCE), feature-test macros 370 * (_XOPEN_SOURCE, _POSIX_SOURCE, __EXTENSIONS__), and similar. 371 * Some of these may be aliased into std:: in Section 6. 372 */ 373#if defined(_C99_SOURCE) || defined(_XOPEN_SOURCE) 374 375/* extern double foo(double); */ 376 377#endif /* _C99_SOURCE || _XOPEN_SOURCE (and others) */ 378 379#if defined(__EXTENSIONS__) 380 381extern double acospi(double); 382 383#endif /* __EXTENSIONS__ */ 384 385/* 386 * Section 3: C-linkage functions needed only by the C++ overloaded 387 * inlines or templates in Section 4; they have no use in C 388 * translation units. Functions from Section 2 that also need 389 * type variant helpers belong here too, guarded by the same 390 * feature-test conditions as their Section 2 declarations. 391 * For example, math.h adds `float acosf(float)` and 392 * `long double acosl(long double)` here for use in the argument 393 * overloads in Section 4. 394 */ 395#ifdef __cplusplus 396extern float acosf(float); 397extern long double acosl(long double); 398#endif /* __cplusplus */ 399 400#ifdef __cplusplus 401} /* extern "C" */ 402#endif 403 404/* 405 * Section 4: C++ overloaded inlines (Pattern A: inlines in ::). 406 * 407 * This block is entirely separate from extern "C" above. 408 * Use Pattern A when the function is not commonly called with 409 * integer arguments. For example, acos(1) compiles fine even 410 * with type variant overloads in :: because there is no ambiguity 411 * in practice. 412 * 413 * For functions that ARE commonly called with integer arguments 414 * (most math functions), use Pattern B: omit the inlines here 415 * and define them directly inside namespace std in Section 6. 416 */ 417#if __cplusplus >= 199711L 418extern "C++" { 419#undef __X 420#undef __Y 421 422 inline float acos(float __X) { return acosf(__X); } 423 inline long double acos(long double __X) { return acosl(__X); } 424 425/* 426 * Section 5: C++ overloads for conditionally-exposed functions 427 * (C++ global namespace). 428 * 429 * Type variant inlines for functions declared in Section 2, guarded 430 * by the same environment macro conditions as their Section 2 431 * declarations. 432 */ 433#if defined(__EXTENSIONS__) 434#undef __X 435 436 inline float acospi(float __X) { return acospif(__X); } 437 inline long double acospi(long double __X) { return acospil(__X); } 438 439#endif /* __EXTENSIONS__ */ 440 441/* 442 * Section 6: namespace std population. 443 * 444 * Only declarations codified by C++ standards are aliased into std::. 445 * Aliases for Section 2 (conditionally exposed, standards-codified) 446 * functions may also appear here, guarded by the same conditions as 447 * Section 2. 448 * 449 * Pattern A: "using ::" brings all type variant overloads into std:: 450 * in one declaration; used when inlines are in :: (Section 4). 451 * 452 * Pattern B (math functions): "using ::" brings only the C-standard 453 * form; type variant inlines are defined directly here in namespace 454 * std to avoid ambiguity when called with integer args. 455 */ 456namespace std { 457 /* Pattern A example: */ 458 using ::acos; 459 460 /* Pattern B example (math.h style): */ 461 using ::log; /* double form only in :: */ 462 inline float log(float __X) { return logf(__X); } 463 inline long double log(long double __X) { return logl(__X); } 464 465} /* namespace std */ 466 467} /* extern "C++" */ 468#endif /* __cplusplus >= 199711L */ 469 470#endif /* _INCLUDE_GUARD_ */ 471``` 472