@@ -135,13 +135,26 @@ _LIBCPP_HARDENING_MODE_EXTENSIVE, \
135135_LIBCPP_HARDENING_MODE_DEBUG
136136#endif
137137
138- // Hardening assertion semantics generally mirror the evaluation semantics of C++26 Contracts:
138+ // The library provides the macro `_LIBCPP_ASSERTION_SEMANTIC` for configuring the assertion semantic used by hardening;
139+ // it can be set to one of the following values:
140+ //
141+ // - `_LIBCPP_ASSERTION_SEMANTIC_IGNORE`;
142+ // - `_LIBCPP_ASSERTION_SEMANTIC_OBSERVE`;
143+ // - `_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE`;
144+ // - `_LIBCPP_ASSERTION_SEMANTIC_ENFORCE`.
145+ //
146+ // libc++ assertion semantics generally mirror the evaluation semantics of C++26 Contracts:
139147// - `ignore` evaluates the assertion but doesn't do anything if it fails (note that it differs from the Contracts
140148// `ignore` semantic which wouldn't evaluate the assertion at all);
141149// - `observe` logs an error (indicating, if possible, that the error is fatal) and continues execution;
142150// - `quick-enforce` terminates the program as fast as possible (via trapping);
143151// - `enforce` logs an error and then terminates the program.
144152//
153+ // Additionally, a special `hardening-dependent` value selects the assertion semantic based on the hardening mode in
154+ // effect: the production-capable modes (`fast` and `extensive`) map to `quick_enforce` and the `debug` mode maps to
155+ // `enforce`. The `hardening-dependent` semantic cannot be selected explicitly, it is only used when no assertion
156+ // semantic is provided by the user _and_ the library's default semantic is configured to be dependent on hardening.
157+ //
145158// Notes:
146159// - Continuing execution after a hardening check fails results in undefined behavior; the `observe` semantic is meant
147160// to make adopting hardening easier but should not be used outside of this scenario;
@@ -150,32 +163,53 @@ _LIBCPP_HARDENING_MODE_DEBUG
150163// hardened preconditions, however, be aware that using `ignore` does not produce a conforming "Hardened"
151164// implementation, unlike the other semantics above.
152165// clang-format off
153- # define _LIBCPP_ASSERTION_SEMANTIC_IGNORE (1 << 1 )
154- # define _LIBCPP_ASSERTION_SEMANTIC_OBSERVE (1 << 2 )
155- # define _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE (1 << 3 )
156- # define _LIBCPP_ASSERTION_SEMANTIC_ENFORCE (1 << 4 )
166+ # define _LIBCPP_ASSERTION_SEMANTIC_HARDENING_DEPENDENT (1 << 1 )
167+ # define _LIBCPP_ASSERTION_SEMANTIC_IGNORE (1 << 2 )
168+ # define _LIBCPP_ASSERTION_SEMANTIC_OBSERVE (1 << 3 )
169+ # define _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE (1 << 4 )
170+ # define _LIBCPP_ASSERTION_SEMANTIC_ENFORCE (1 << 5 )
157171// clang-format on
158172
159- // Allow users to define an arbitrary assertion semantic; otherwise, use the default mapping from modes to semantics.
160- // The default is for production-capable modes to use `quick-enforce` (i.e., trap) and for the `debug` mode to use
161- // `enforce` (i.e., log and abort).
162- #ifndef _LIBCPP_ASSERTION_SEMANTIC
163-
164- # if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
165- # define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_ENFORCE
166- # else
167- # define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
168- # endif
169-
170- #else
171-
173+ // If the user attempts to configure the assertion semantic, check that it is allowed in the current environment.
174+ #if defined(_LIBCPP_ASSERTION_SEMANTIC)
172175# if !_LIBCPP_HAS_EXPERIMENTAL_LIBRARY
173176# error "Assertion semantics are an experimental feature."
174177# endif
175178# if defined(_LIBCPP_CXX03_LANG)
176179# error "Assertion semantics are not available in the C++03 mode."
177180# endif
181+ #endif // defined(_LIBCPP_ASSERTION_SEMANTIC)
182+
183+ // User-provided semantic takes top priority -- don't override if set.
184+ #ifndef _LIBCPP_ASSERTION_SEMANTIC
178185
179- #endif // _LIBCPP_ASSERTION_SEMANTIC
186+ # ifndef _LIBCPP_ASSERTION_SEMANTIC_DEFAULT
187+ # error _LIBCPP_ASSERTION_SEMANTIC_DEFAULT is not defined. This definition should be set at configuration time in \
188+ the `__config_site` header, please make sure your installation of libc++ is not broken.
189+ # endif
190+
191+ # if _LIBCPP_ASSERTION_SEMANTIC_DEFAULT != _LIBCPP_ASSERTION_SEMANTIC_HARDENING_DEPENDENT
192+ # define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_DEFAULT
193+ # else
194+ # if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
195+ # define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_ENFORCE
196+ # else
197+ # define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
198+ # endif
199+ # endif // _LIBCPP_ASSERTION_SEMANTIC_DEFAULT != _LIBCPP_ASSERTION_SEMANTIC_HARDENING_DEPENDENT
200+
201+ #endif // #ifndef _LIBCPP_ASSERTION_SEMANTIC
202+
203+ // Finally, validate the selected semantic (in case the user tries setting it to an incorrect value):
204+ #if _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_IGNORE && \
205+ _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_OBSERVE && \
206+ _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE && \
207+ _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_ENFORCE
208+ # error _LIBCPP_ASSERTION_SEMANTIC must be set to one of the following values: \
209+ _LIBCPP_ASSERTION_SEMANTIC_IGNORE, \
210+ _LIBCPP_ASSERTION_SEMANTIC_OBSERVE, \
211+ _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE, \
212+ _LIBCPP_ASSERTION_SEMANTIC_ENFORCE
213+ #endif
180214
181215#endif // _LIBCPP___CONFIGURATION_HARDENING_H
0 commit comments