libstdc++: Defined __cpp_lib_replaceable_contract_violation_handler.
Checks
| Context |
Check |
Description |
| linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_gcc_build--master-arm |
success
|
Build passed
|
Commit Message
This implements P3886R0: Wording for AT1-057, by defining the
__cpp_lib_replaceable_contract_violation_handler. The macro is defined
only if contracts are supported (i.e. under same conditions as
__cpp_lib_contracts).
GCC supports providing custom violation handler by providing an separate
defintion of handle_contract_violation. This is supported on the targets
that uses ELF format, so the macro is defined for with non-zero value
for them.
libstdc++-v3/ChangeLog:
* include/bits/version.def (replaceable_contract_violation_handler)
[(__cplusplus > 202302L) && (__cpp_contracts >= 202502L)]:
Define to 202603 for ELF targets, and 0 otherwise.
* include/bits/version.h: Regenerate.
* include/std/contracts: Define
__cpp_lib_replaceable_contract_violation_handler.
---
From the discussion with Jason, this for sure is supported for ELF
targets. We were not sure regarding Darwin, but we could always expand
the set of targets where macro is defined.
OK for trunk?
libstdc++-v3/include/bits/version.def | 15 +++++++++++++++
libstdc++-v3/include/bits/version.h | 15 +++++++++++++++
libstdc++-v3/include/std/contracts | 1 +
3 files changed, 31 insertions(+)
Comments
* Tomasz Kamiński:
> This implements P3886R0: Wording for AT1-057, by defining the
> __cpp_lib_replaceable_contract_violation_handler. The macro is defined
> only if contracts are supported (i.e. under same conditions as
> __cpp_lib_contracts).
>
> GCC supports providing custom violation handler by providing an separate
> defintion of handle_contract_violation. This is supported on the targets
> that uses ELF format, so the macro is defined for with non-zero value
> for them.
>
> libstdc++-v3/ChangeLog:
>
> * include/bits/version.def (replaceable_contract_violation_handler)
> [(__cplusplus > 202302L) && (__cpp_contracts >= 202502L)]:
> Define to 202603 for ELF targets, and 0 otherwise.
> * include/bits/version.h: Regenerate.
> * include/std/contracts: Define
> __cpp_lib_replaceable_contract_violation_handler.
> ---
> From the discussion with Jason, this for sure is supported for ELF
> targets. We were not sure regarding Darwin, but we could always expand
> the set of targets where macro is defined.
Wouldn't you have to declare the symbol as weak in the header, so that
multiple definitions won't conflict?
With ELF, there can only be one strong definition of a symbol in the
link, and whether this works as expected depends on the contents of the
object file that contains the symbol definition.
Even if the symbol is defined as weak in the header, multiple TUs
reacting to __cpp_lib_replaceable_contract_violation_handler need to
coordinate. A simple macro does not really capture that. A library
should not assume that because the macro is defined, replacing the
handler has the intended effect, or is indeed successful.
Thanks,
Florian
On Wed, 8 Apr 2026, 15:48 Florian Weimer, <fweimer@redhat.com> wrote:
> * Tomasz Kamiński:
>
> > This implements P3886R0: Wording for AT1-057, by defining the
> > __cpp_lib_replaceable_contract_violation_handler. The macro is defined
> > only if contracts are supported (i.e. under same conditions as
> > __cpp_lib_contracts).
> >
> > GCC supports providing custom violation handler by providing an separate
> > defintion of handle_contract_violation. This is supported on the targets
> > that uses ELF format, so the macro is defined for with non-zero value
> > for them.
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/bits/version.def (replaceable_contract_violation_handler)
> > [(__cplusplus > 202302L) && (__cpp_contracts >= 202502L)]:
> > Define to 202603 for ELF targets, and 0 otherwise.
> > * include/bits/version.h: Regenerate.
> > * include/std/contracts: Define
> > __cpp_lib_replaceable_contract_violation_handler.
> > ---
> > From the discussion with Jason, this for sure is supported for ELF
> > targets. We were not sure regarding Darwin, but we could always expand
> > the set of targets where macro is defined.
>
> Wouldn't you have to declare the symbol as weak in the header, so that
> multiple definitions won't conflict?
>
> With ELF, there can only be one strong definition of a symbol in the
> link, and whether this works as expected depends on the contents of the
> object file that contains the symbol definition.
>
> Even if the symbol is defined as weak in the header, multiple TUs
> reacting to __cpp_lib_replaceable_contract_violation_handler need to
> coordinate. A simple macro does not really capture that.
The intended purpose of the macro is not "replacing the handler works as
expected", it's "attempting to replace the handler doors not have undefined
behaviour". It's not intended to day there's only one definition.
It's entirely expected that users of contracts need to coordinate: the
knobs for controlling behaviour are all currently global.
A library
> should not assume that because the macro is defined, replacing the
> handler has the intended effect, or is indeed successful.
>
IMHO libraries should not try to replace the handler at all. That should be
a decision made by the application, not sub-components.
On Wed, 8 Apr 2026, 15:48 Florian Weimer, <fweimer@redhat.com> wrote:
> * Tomasz Kamiński:
>
> > This implements P3886R0: Wording for AT1-057, by defining the
> > __cpp_lib_replaceable_contract_violation_handler. The macro is defined
> > only if contracts are supported (i.e. under same conditions as
> > __cpp_lib_contracts).
> >
> > GCC supports providing custom violation handler by providing an separate
> > defintion of handle_contract_violation. This is supported on the targets
> > that uses ELF format, so the macro is defined for with non-zero value
> > for them.
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/bits/version.def (replaceable_contract_violation_handler)
> > [(__cplusplus > 202302L) && (__cpp_contracts >= 202502L)]:
> > Define to 202603 for ELF targets, and 0 otherwise.
> > * include/bits/version.h: Regenerate.
> > * include/std/contracts: Define
> > __cpp_lib_replaceable_contract_violation_handler.
> > ---
> > From the discussion with Jason, this for sure is supported for ELF
> > targets. We were not sure regarding Darwin, but we could always expand
> > the set of targets where macro is defined.
>
> Wouldn't you have to declare the symbol as weak in the header, so that
> multiple definitions won't conflict?
>
There is no declaration in the header.
> With ELF, there can only be one strong definition of a symbol in the
> link, and whether this works as expected depends on the contents of the
> object file that contains the symbol definition.
>
> Even if the symbol is defined as weak in the header, multiple TUs
> reacting to __cpp_lib_replaceable_contract_violation_handler need to
> coordinate. A simple macro does not really capture that. A library
> should not assume that because the macro is defined, replacing the
> handler has the intended effect, or is indeed successful.
>
> Thanks,
> Florian
>
>
On Wed, Apr 8, 2026 at 4:48 PM Florian Weimer <fweimer@redhat.com> wrote:
> * Tomasz Kamiński:
>
> > This implements P3886R0: Wording for AT1-057, by defining the
> > __cpp_lib_replaceable_contract_violation_handler. The macro is defined
> > only if contracts are supported (i.e. under same conditions as
> > __cpp_lib_contracts).
> >
> > GCC supports providing custom violation handler by providing an separate
> > defintion of handle_contract_violation. This is supported on the targets
> > that uses ELF format, so the macro is defined for with non-zero value
> > for them.
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/bits/version.def (replaceable_contract_violation_handler)
> > [(__cplusplus > 202302L) && (__cpp_contracts >= 202502L)]:
> > Define to 202603 for ELF targets, and 0 otherwise.
> > * include/bits/version.h: Regenerate.
> > * include/std/contracts: Define
> > __cpp_lib_replaceable_contract_violation_handler.
> > ---
> > From the discussion with Jason, this for sure is supported for ELF
> > targets. We were not sure regarding Darwin, but we could always expand
> > the set of targets where macro is defined.
>
> Wouldn't you have to declare the symbol as weak in the header, so that
> multiple definitions won't conflict?
>
Yes, libstdc++ defines handle_contract_violation as weak symbol.
>
> With ELF, there can only be one strong definition of a symbol in the
> link, and whether this works as expected depends on the contents of the
> object file that contains the symbol definition.
>
> Even if the symbol is defined as weak in the header, multiple TUs
> reacting to __cpp_lib_replaceable_contract_violation_handler need to
> coordinate. A simple macro does not really capture that. A library
> should not assume that because the macro is defined, replacing the
> handler has the intended effect, or is indeed successful.
>
Note that I am implementing the paper that was voted in.
And this feature test macro is intended for the user composing
programs, where they provide a single new definition of the
handle_contract_violation,
in similiar manner that the operator new is overloaded.
This macro is solving a very particular quirk of the wording in
https://eel.is/c++draft/basic.contract.handler#3
> It is implementation-defined whether the contract-violation handler is
replaceable ([dcl.fct.def.replace]
<https://eel.is/c++draft/dcl.fct.def.replace#term.replaceable.function>).
<https://eel.is/c++draft/basic.contract.handler#3.sentence-1>
If the contract-violation handler is not replaceable, a declaration of a
replacement function for the contract-violation handler is ill-formed, no
diagnostic required.
<https://eel.is/c++draft/basic.contract.handler#3.sentence-2>
The wording here means that if your program override for handle_contract_
violation, <https://eel.is/c++draft/basic.contract#handler-1.sentence-1>
but implementation does not support replacing it, you whole program is
meanigless.
The intent of this macro is to check if you even can attemt to provide
declaration.
> Thanks,
> Florian
>
>
@@ -2351,6 +2351,21 @@ ftms = {
};
};
+ftms = {
+ name = replaceable_contract_violation_handler;
+ values = {
+ v = 202603;
+ cxxmin = 26;
+ extra_cond = "__cpp_contracts >= 202502L "
+ "&& __ELF__";
+ };
+ values = {
+ v = 0;
+ cxxmin = 26;
+ extra_cond = "__cpp_contracts >= 202502L";
+ };
+};
+
ftms = {
name = simd;
values = {
@@ -2626,6 +2626,21 @@
#endif /* !defined(__cpp_lib_contracts) */
#undef __glibcxx_want_contracts
+#if !defined(__cpp_lib_replaceable_contract_violation_handler)
+# if (__cplusplus > 202302L) && (__cpp_contracts >= 202502L && __ELF__)
+# define __glibcxx_replaceable_contract_violation_handler 202603L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_replaceable_contract_violation_handler)
+# define __cpp_lib_replaceable_contract_violation_handler 202603L
+# endif
+# elif (__cplusplus > 202302L) && (__cpp_contracts >= 202502L)
+# define __glibcxx_replaceable_contract_violation_handler 0L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_replaceable_contract_violation_handler)
+# define __cpp_lib_replaceable_contract_violation_handler 0L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_replaceable_contract_violation_handler) */
+#undef __glibcxx_want_replaceable_contract_violation_handler
+
#if !defined(__cpp_lib_simd)
# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED && (__cpp_structured_bindings >= 202411L && __cpp_expansion_statements >= 202411L && __SSE2__)
# define __glibcxx_simd 202506L
@@ -33,6 +33,7 @@
#pragma GCC system_header
#define __glibcxx_want_contracts
+#define __glibcxx_want_replaceable_contract_violation_handler
#include <bits/version.h>
#ifdef __cpp_lib_contracts