C++ Freestanding and Conditionally Supported

ISO/IEC JTC1 SC22 WG21 N3256 = 11-0026 - 2011-02-27

Lawrence Crowl, crowl@google.com, Lawrence@Crowl.org
Alberto Ganesh Barbati, ganesh@barbati.net

Introduction
Freestanding Implementations
    GB 55 Freestanding <ratio> and <chrono>
    GB 56 Freestanding <utility> and <tuple>
    GB 57 Freestanding <atomic>
    C1X Freestanding Compatibility
    GB 90 Freestanding <type_traits>
    At Least as Much as C
        17.6.1.3 Freestanding implementations [compliance]
    Avoid Large Implementations
        17.6.1.3 Freestanding implementations [compliance]
    Avoid Threading
        17.6.1.3 Freestanding implementations [compliance]
    Allow Small Helpers
        17.6.1.2 Headers [headers]
        17.6.1.3 Freestanding implementations [compliance]
        20.? Helper components [helpers]
        20.3.2 20.?.1 swap [utility.swap]
        20.3.3 20.?.2 forward/move helpers [forward]
        20.3.4 20.?.3 Function template declval [declval]
        20.3 Utility components [utility]
    Allow <utility> and <tuple>
        17.6.1.3 Freestanding implementations [compliance]
Conditional Features
    DE 13 Strict Pointer Macro
    GB 107 Monotonic Clock Macro
    DE 23 Threads Macro
    C1X Conditional Feature Compatibility
    Remove Conditional Contents
        17.6.1.3 Freestanding implementations [compliance]
        30.3 Threads [thread.threads]
    Add Predefined Macros
        16.8 Predefined macro names [cpp.predefined]
    Add Library-Defined Macros
        17.6.1.2 Headers [headers]
        17.6.1.3 Freestanding implementations [compliance]
        18.? Library header support [header.support]

Introduction

Several issues have centered on the requirements on freestanding implementations and the indication of conditionally supported behavior. We list those issues, discuss the general problems, propose solutions, and provide wording.

Freestanding Implementations

C++ has no defined policy for choosing what belongs in freestanding headers and what does not. As a consequence, this aspects of the standard is incomplete and inconsistent.

GB 55 Freestanding <ratio> and <chrono>

Section
17.6.1.3 table 15
Comment
The thread header uses duration types, found in the <chrono> header, and which rely on the ratio types declared in the <ratio> header.
Proposal
Add the <chrono> and <ratio> headers to the freestanding requirements. It might be necessary to address scaled-down expectations of clock support in a freestanding environment, much like <thread>.
Issue
LWG 1359
Status
Open
Resolution
See the proposed resolution in LWG 1359.

GB 56 Freestanding <utility> and <tuple>

Section
17.6.1.3 table 15
Comment
The <utility> header provides support for several important C++ idioms with move, forward and swap. Likewise, declval will be frequently used like a type trait. In order to complete cycles introduced by std::pair, the <tuple> header should also be made available. This is a similarly primitive set of functionality, with no dependency of a hosted environment, but does go beyond the minimal set of functionality otherwise suggested by the freestanding libraries. Alternatively, split the move/forward/swap/declval functions out of <utility> and into a new primitive header, requiring only that of freestanding implementation.
Proposal
Add <utility> and <tuple> to table 15, headers required for a free-standing implementation.
Issue
LWG 1359
Status
NAD
Rationale
No consensus for change.

GB 57 Freestanding <atomic>

Section
17.6.1.3 table 15
Comment
The atomic operations facility is closely tied to clause 1 and the memory model. It is not easily supplied as an after-market extension, and should be trivial to implement of a single-threaded serial machine. The consequence of not having this facility will be poor interoperability with future C++ libraries that memory model concerns seriously, and attempt to treat them in a portable way.
Proposal
Add <atomic> to table 15, headers required for a free-standing implementation.
Issue
LWG 1360
Status
Resolved in N3225.
Resolution
Add <atomic> to table 15, headers required for a free-standing implementation.

C1X Freestanding Compatibility

Section
17.6.1.3
Comment

The C++ working draft N3225 requires freestanding implementations to provide: <atomic> <exception> <initializer_list> <limits> <new> <cstdarg> <cstddef> <cstdlib> <thread> <type_traits> <typeinfo>

The C working draft N1539 section 4 paragraph 6 requires freestanding implementations to provide: <float.h> <iso646.h> <limits.h> <stdalign.h> <stdarg.h> <stdbool.h> <stddef.h> <stdint.h>

These two requirements have notable inconsistencies.

Taken as a whole, the C specification for freestanding implementations does not require run-time library support: memory allocation, string routines, and input/output. This is in marked contrast to C++, which seems to require more than necessary.

GB 90 Freestanding <type_traits>

Section
20.7
Comment
type_traits is a core support facility offered by the compiler, and exposed with a library interface that is required in a free-standing implementation. It has far more in common with numeric_limits than the utility components in clause 20, and should move to clause 18.
Proposal
Move clause 20.7 into clause 18.
Issue
None.
Status
Rejected.
Rationale
Type traits support queries about all types, not just built-in types. They do not belong in Clause 18.

At Least as Much as C

The set of freestanding headers required by C++ should include at least those required by C. Implementors will anyway because few would support only C++, so failing to support those headers simply invites an inconsistency between the standard and practice.

17.6.1.3 Freestanding implementations [compliance]

Edit table 16 as follows.

Table 16 — C++ headers for freestanding implementations
SubclauseHeader(s)
17.6.1.2, C.2.2.3Named operators <ciso646> <iso646.h>
18.2Types <cstddef> <stddef.h>
18.3Implementation properties <cfloat> <float.h> <limits> <climits> <limits.h>
18.4Integer types <cstdint> <stdint.h>
.........
18.10Other runtime support <cstdalign> <stdalign.h> <cstdarg> <stdarg.h> <cstdbool> <stdbool.h>
.........

Avoid Large Implementations

Since freestanding implementations are generally for embedded systems, the requirements should not require significant run-time implementation. The C standards community is generally closer to embedded systems, and the list of C freestanding headers reflects lean implementations. C++ policy should do the same.

In particular, C does not require <stdlib.h> in freestanding implementations because of the run-time overhead embodied in that header. Even though C++ only requires a subset of <stdlib.h>, requiring it would still be a burden on some implementations. Likewise, features requiring dynamic memory allocation or unneeded code size are also often avoided in embedded systems. The headers <exception>, <new>, and <typeinfo> are in this class. They would also be a burden on some implementations. (We recognize that their absence would prevent use of some language features, but such systems already prohibit their use.)

17.6.1.3 Freestanding implementations [compliance]

Edit table 16 as follows.

Table 16 — C++ headers for freestanding implementations
SubclauseHeader(s)
.........
18.5Start and termination <cstdlib>
18.6Dynamic memory management <new>
18.7Type identification <typeinfo>
18.8Exception handling <exception>
.........

Edit paragraph 3 as follows.

The supplied version of the header <cstdlib> shall declare at least the functions abort, atexit, at_quick_exit, exit, and quick_exit (18.5). The supplied version of the header <thread> shall meet the same requirements as for a hosted implementation or including it shall have no effect. The other headers listed in this table shall meet the same requirements as for a hosted implementation.

Avoid Threading

Atomics are fairly tightly integrated into the language, and are required on any concurrent system. On systems without concurrency, atomics have trivial implementation. So under the above criteria, as suggested by GB 57, should be included in the freestanding headers.

In contrast, <mutex> is more likely to be implemented in freestanding implementations than is <thread> and yet their freestanding requirements are opposite. Furthermore, there are many single-threaded embedded systems. So, <thread> should not be required of freestanding implementations. Consequently, <ratio> and <chrono> would not need to be freestanding and GB 55 would become moot.

17.6.1.3 Freestanding implementations [compliance]

Edit table 16 as follows.

Table 16 — C++ headers for freestanding implementations
SubclauseHeader(s)
.........
29Atomics <atomic>
30.3Threads <thread>

Edit paragraph 3 as follows.

The supplied version of the header <cstdlib> shall declare at least the functions abort, atexit, at_quick_exit, exit, and quick_exit (18.5). The supplied version of the header <thread> shall meet the same requirements as for a hosted implementation or including it shall have no effect. The other headers listed in this table shall meet the same requirements as for a hosted implementation.

Allow Small Helpers

C++ is necessarily a larger language than C, and the line between the language and the library is fuzzier. C++ should be willing and able to incorporate headers into freestanding implementations when the need is apparent and the run-time implementation is small.

As an example, rvalue references are very difficult to use without (at least replicating) some of the facilities defined in <utility>. Their implementation is tiny. So, GB 56 should be reconsidered. At a minimum, the move, forward, swap, and declval functions should be split into a separate header.

17.6.1.2 Headers [headers]

Table 14 — C++ library headers
....
<future>
<helpers>
<initializer_list>
....

17.6.1.3 Freestanding implementations [compliance]

Edit table 16 as follows.

Table 16 — C++ headers for freestanding implementations
SubclauseHeader(s)
.........
20.?Helper components <helpers>
20.7Type traits <type_traits>
.........

20.? Helper components [helpers]

Create a new section "Helper components" before 20.3 Utility components [utility].

Add a paragraph 1.

This subclause contains some basic function and class templates that are used throughout the rest of the library.

Add a synopsis.

Header <helpers> synopsis

namespace std {

// 20.?.1, swap:
template<class T> void swap(T& a, T& b) noexcept(see below);
template <class T, size_t N> void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b)));

// 20.?.2, forward/move:
template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;
template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept;
template <class T> typename remove_reference<T>::type&& move(T&&) noexcept;
template <class T> typename conditional<
  !is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value,
  const T&, T&&>::type move_if_noexcept(T& x) noexcept;

// 20.?.3, declval:
template <class T>
  typename add_rvalue_reference<T>::type declval() noexcept;  // as unevaluated operand

}

20.3.2 20.?.1 swap [utility.swap]

Move the entire subsubclause 20.3.2 into the new subclause above.

20.3.3 20.?.2 forward/move helpers [forward]

Move the entire subsubclause 20.3.3 into the new subclause above.

20.3.4 20.?.3 Function template declval [declval]

Move the entire subsubclause 20.3.4 into the new subclause above.

20.3 Utility components [utility]

Edit the synopsis as follows.

Header <utility> synopsis

#include <initializer_list>
#include <helpers>

namespace std {

....

// 20.3.2, swap:
template<class T> void swap(T& a, T& b) noexcept(see below);
template <class T, size_t N> void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b)));

// 20.3.3, forward/move:
template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;
template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept;
template <class T> typename remove_reference<T>::type&& move(T&&) noexcept;
template <class T> typename conditional<
  !is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value,
  const T&, T&&>::type move_if_noexcept(T& x) noexcept;

// 20.3.4, declval:
template <class T>
  typename add_rvalue_reference<T>::type declval() noexcept;  // as unevaluated operand

....

Allow <utility> and <tuple>

As an alternative to the change above, we could do all that GB 56 requests.

17.6.1.3 Freestanding implementations [compliance]

Edit table 16 as follows.

Table 16 — C++ headers for freestanding implementations
SubclauseHeader(s)
.........
20.3Utility components <utility>
20.4Tuples <tuple>
20.7Type traits <type_traits>
.........

Conditional Features

C++ has no defined mechanism for indicating conditional features. As a consequence, this aspects of the standard is incomplete and inconsistent.

DE 13 Strict Pointer Macro

Section
16.8
Comment
Committee Draft comment DE 18 has only been partially addressed, and the record of response ignores the missing item, namely the absence of a macro __STDCPP_STRICT_POINTER_SAFETY__ that indicates that a given implementation has strict pointer safety (see 3.7.4.3).
Proposal
Add the macro to the list of predefined macros in 16.8.
Issue
CWG 1169
Status
Resolved November 2010
Resolution
Add the following to the end of 16.8 [cpp.predefined] paragraph 2:
__STDCPP_STRICT_POINTER_SAFETY__
Defined, and has the value integer constant 1, if and only if the implementation has strict pointer safety (3.7.4.3 [basic.stc.dynamic.safety]).

GB 107 Monotonic Clock Macro

Section
20.10.5.2 paragraph 2
Comment
1.4p9 states that which conditionally supported constructs are available should be provided in the documentation for the implementation. This doesn't help programmers trying to write portable code, as they must then rely on implementation-specific means to determine the availability of such constructs. In particular, the presence or absence of std::chrono::monotonic_clock may require different code paths to be selected. This is the only conditionally-supported library facility, and differs from the conditionally-supported language facilities in that it has standard-defined semantics rather than implementation defined semantics.
Proposal
Provide feature test macro for determining the presence of std::chrono::monotonic_clock. Add _STDCPP_HAS_MONOTONIC_CLOCK to the <chrono> header, which is defined if monotonic_clock is present, and not defined if it is not present.
Issue
LWG 1410
Status
Resolved
Resolution
Moot by the conversion of conditionally-supported monotonic clocks to required steady clocks in N3191.

DE 23 Threads Macro

Section
30.3
Comment
Predefined macros usually start and end with two underscores, see 16.8 and FDIS 29124 = WG21 N3060 clause 7. __STDCPP_THREADS should blend in.
Proposal
Change the macro name to __STDCPP_THREADS__.
Issue
LWG 1483
Status
NAD Editorial.
Resolution
Change the macro name to __STDCPP_THREADS__.

C1X Conditional Feature Compatibility

Section
Various.
Comment

The C working draft N1539 section 6.10.8.3 paragraph 1 requires conditionally macros indicating (lack of) support for conditional features.

__STDC_ANALYZABLE__
The integer constant 1, intended to indicate conformance to the specifications in annex L (Analyzability).
__STDC_IEC_559__
The integer constant 1, intended to indicate conformance to the specifications in annex F (IEC 60559 floating-point arithmetic).
__STDC_IEC_559_COMPLEX__
The integer constant 1, intended to indicate adherence to the specifications in annex G (IEC 60559 compatible complex arithmetic).
__STDC_LIB_EXT1__
The integer constant 201ymmL, intended to indicate support for the extensions defined in annex K (Bounds-checking interfaces).
__STDC_NO_COMPLEX__
The integer constant 1, intended to indicate that the implementation does not support complex types or the <complex.h> header.
__STDC_NO_THREADS__
The integer constant 1, intended to indicate that the implementation does not support atomic types (including the _Atomic type qualifier and the <stdatomic.h> header) or the <threads.h> header.
__STDC_NO_VLA__
The integer constant 1, intended to indicate that the implementation does not support variable length arrays or variably modified types.

(Note that there are NB comments on C1x against the current formulation of __STDC_NO_THREADS__.)

In constrast, The C++ working draft N3225 generally ignores conditional behavior, except that the <thread> header either defines _STDCPP_THREADS__ and the full set of symbols, or has no effect. This mechanism is different from that of C, and more difficult to use.

Remove Conditional Contents

Most programmers will not write code that adapts to the presence or absence of conditional features. As a consequence, the use of a missing feature should be transparently obvious. Therefore, if a feature is missing, the C++ implementation should simply not provide the corresponding header. The error message will be brutally obvious — header not found.

In C++ 2003, there are no macros indicating C++ conditional features. We could as well do the same thing in C++0x, which would serve the vast majority of programmers.

Therefore, we should remove the __STDCPP_THREADS__ macro from <thread>.

17.6.1.3 Freestanding implementations [compliance]

Edit paragraph 3 as follows.

The supplied version of the header <cstdlib> shall declare at least the functions abort, atexit, at_quick_exit, exit, and quick_exit (18.5). The supplied version of the header <thread> shall meet the same requirements as for a hosted implementation or including it shall have no effect. The other headers listed in this table shall meet the same requirements as for a hosted implementation.

30.3 Threads [thread.threads]

Edit the synopsis as follows.


namespace std {
  #define __STDCPP_THREADS__ __cplusplus

....

Add Predefined Macros

Some programmers can and would will write code that adapts to the presence or absence of conditional features, if a language mechanism were available.

C uses predefined macros to indicate conditional features. C++ could do the same.

C uses a mix of positive and negative sense macros. C++ defines mostly positive macros in 16.8 [cpp.predefined]. As postive sense macros are easier to reason with, we should use them.

So, we should add a predefined __STDCPP_THREADS__ macro.

As it is somewhat likely that other thread-related headers will be implemented or not in concert with <thread>, we should make those headers conditional under the same macro.

16.8 Predefined macro names [cpp.predefined]

Add the following to the end of paragraph 2.

__STDCPP_THREAD__
Defined, and has the value integer constant 1, if and only if the implementation provides the headers <condition_variable> (30.5 [thread.condition]), <future> (30.6 [futures]), <mutex> (30.4 [thread.mutex]), and <thread> (30.3 [thread.threads]).

Add Library-Defined Macros

As an alternative to the approach above, we can provide a library header that provides the macros indicating whether or not a header is present, as suggested in the proposed resolution to LWG 1358. This approach has the virtue of moving indications of library features to the library implementation. Its cost is that library implementations must provide another header and programmers testing conditional features would need to include that header.

17.6.1.2 Headers [headers]

Table 14 — C++ library headers
....
<iterator>
<library_support>
<limits>
....

17.6.1.3 Freestanding implementations [compliance]

Edit table 16 as follows.

Table 16 — C++ headers for freestanding implementations
SubclauseHeader(s)
.........
20.?Library header support <library_support>
20.7Type traits <type_traits>
.........

Edit paragraph 3 as follows.

The supplied version of the header <cstdlib> shall declare at least the functions abort, atexit, at_quick_exit, exit, and quick_exit (18.5). The supplied version of the header <thread> shall meet the same requirements as for a hosted implementation or including it shall have no effect. The other headers listed in this table shall meet the same requirements as for a hosted implementation. A program can detect the presence of standard headers not listed in Table 16 using the facilities provided by the <library_support> header.

18.? Library header support [header.support]

Add a new section in Clause 18.

Add a new paragraph as follows.

The header <library_support> defines an implementation-defined set of macros to enable a program detect the presence of standard headers in freestanding implementations. [Note: Hosted implementations shall provide all standard headers, thus shall provide all macros. —end note]

Add a new paragraph as follows.

For each standard header listed in Tables 14 (C++ library headers) and 15 (C++ headers for C library facilities) that is provided by the implementation, <library_support> shall define a macro with name __STDCPP_HAS_XXX_HEADER__ where XXX is replaced by the uppercase version of the name of the header. Each such macro shall expand to the value __cplusplus.

Add a new paragraph as follows.

[Example:


#include <library_support>

#ifdef __STDCPP_HAS_THREAD_HEADER__
  #include <thread>
  // code that exploit the presence of threads
#else
  // fallback code that doesn't rely on threads
#endif

end example]

Add a new paragraph as follows.

No other standard header shall define macros with a name beginning with __STDCPP_HAS_ and ending with _HEADER__.