xref: /illumos-gate/usr/src/head/README.cplusplus.md (revision 8c0afdd33bb297ecccc824153fb86a0cb0d929d2)
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