Date: Mon, 20 Oct 2025 13:31:49 +0200
One major complication in this is that the C++ standard doesn't define
compilers or build modes. There is nothing we can add to the standard
within its current mandate that would fix this.
For P2900 as far as I know, it is completely legal for an implementation to
support only one contract evaluation mode. It is completely legal for it to
always check caller side, always check callee side, or to choose another
implementation method. As the compiler can choose ignore as the evaluation
mode for everything, it could just expression-check all contracts and not
use them. It can also export the full setup for all evaluation modes to
link time, load time or run time, allowing the linker (by doing a function
variant selection, or using LTO) or loader (with something like ifuncs) to
optimize out what it can based on information available at that point.
There is nothing in P2900 that is causing this problem. The implicit
assumption that people will be selecting a contract mode at compile time to
the exclusion of others with some compiler flag is what is causing this
problem. This also makes it hard to address this problem in P2900 or in the
current draft, as it is an implementation choice that causes the problems,
not the design. Admittedly, we *do* want there to be a fast compile output
and allowing the optimizer to look at your contracts is a very good
approach to do so. We should be smart enough to consider this separately
from the design of the contracts feature in C++ and to realize that we are
in the terrain of compiler flags, implementation-defined as-if usage and
linker + ABI changes, where we can achieve wonders if we're willing to put
in the leg work to implement such a faster output mode.
The problems that we are discussing stem from the choice to allow a
translation unit to pre-select a contract evaluation mode, and the implicit
assumption that this must not result in an ABI incompatibility. If and only
if we take those two assumptions do we end up with a situation where the
linker will see multiple function bodies that are meaningfully different.
However, they are only meaningfully different in out-of-contract behavior.
Each of them - including the ignore and observe ones - have the same
in-contract behavior. As such, the program in-contract validity is not
affected at all by which the compiler chooses. Each option results in a
valid output for the program compilation that does the exact same thing for
all in-contract calls.
That said, for the out-of-contract detection that contracts is trying to
offer, it *does* matter which we end up selecting. And as mentioned by
others, it is for some essential that it is checked and that the program is
terminated, while it is equally essential for others that it is checked and
that the program is *not* terminated. No fixed default choice of semantic
as proposed by P3640 can do this.
Within the contracts feature that we can still refer to by P2900 I see no
part that would still need changing in this regard. I do see a lot of space
for implementers to make choices and to create better, faster and more
optimized outputs that do implement the full scope of P2900's contracts, by
making the changes that are required at those levels to do so, and to
provide compiler flags to make particular selections.
On Mon, Oct 20, 2025 at 1:04 PM Oliver Rosten via SG15 <
sg15_at_[hidden]> wrote:
> To try to avoid the risk of going around in circles, John, can I confirm
> that my understanding of your position is correct.
>
> First, *I think* that everyone agrees on the following two points
> 1. The situation in which non-inlined inline functions end up with
> different semantics is not ideal.
>
> 2. This is a manifestation of a pre-existing problem in C++
>
> I think we also all agree on the 3rd point:
> 3. Contracts increases the surface area of exposure to this problem
>
> If I'm on the right track so far then is it fair to say that the bone of
> contention boils down to this?
>
> The weight each of us ascribes to the benefits of P2900 over the drawback
> of point 3. is different?
>
> John, I assume you see at least some value in P2900 (i.e. it's not
> completely worthless in your opinion, though correct me if I'm wrong).
> However, you see (amongst other things such as constification but that's a
> different discussion) that increased exposure to 3. outweighs any benefits
> of P2900 in your mind?
>
> O.
>
> On Mon, 20 Oct 2025 at 11:58, John Spicer via SG21 <sg21_at_[hidden]>
> wrote:
>
>> That assumes facilities that linkers might not have, and even if they
>> have them, it may require expert use to select the version of the function
>> you want.
>>
>> This also potentially requires you to *know* which functions you and your
>> libraries use.
>>
>> On most systems with conventional linkers you do not have the capability
>> you describe.
>>
>> John.
>>
>> On Oct 20, 2025, at 6:52 AM, Gašper Ažman via SG21 <sg21_at_[hidden]>
>> wrote:
>>
>> John,
>>
>> it shouldn't be "assigned randomly" - it's at best a final link-time
>> property (as specified). The final link (+LTO) can do it.
>>
>> On Mon, Oct 20, 2025 at 11:50 AM John Spicer <jhspicer_at_[hidden]> wrote:
>>
>>> The problem is that for function templates, member functions of class
>>> templates, and inline functions, the semantic is essentially assigned
>>> randomly if it is used in multiple TUs that are compiled with different
>>> semantics.
>>>
>>> In most complex environments you are dealing with things like libraries
>>> that are provided by others, so you may not have control over how it is
>>> built.
>>>
>>> You can also have two libraries that use a third library, but if those
>>> two libraries are a different semantic any user of the third library has no
>>> idea what semantic they’ll get even if their code also uses the third
>>> library and is built with a particular semantic.
>>>
>>> John.
>>>
>>> On Oct 17, 2025, at 11:45 AM, Gašper Ažman via SG21 <
>>> sg21_at_[hidden]> wrote:
>>>
>>> +1 to what Tom said.
>>>
>>> One part of this discussion is speaking as if semantics are assigned
>>> randomly or arbitrarily, where they are assigned by the person who ships
>>> the product - it has been pointed out time and time again that the actor
>>> deploying the application is the final arbiter of what "safe" means for a
>>> given contract check, because it's actually a function of "safe(context) ->
>>> bloom" (where "bloom" is a type with exactly two values of "no" and
>>> "perhaps").
>>>
>>> The stakeholder with the best context is the deployer of the
>>> application; the farther away you go from that stakeholder, the less
>>> context they have. Deferring the choice of semantic to as late as possible
>>> gives a better outcome.
>>>
>>> On Fri, Oct 17, 2025 at 4:33 PM Tom Honermann via SG21 <
>>> sg21_at_[hidden]> wrote:
>>>
>>>>
>>>> On Oct 17, 2025, at 10:23 AM, Harald Achitz via SG21 <
>>>> sg21_at_[hidden]> wrote:
>>>>
>>>>
>>>> On 2025-10-17 16:00, René Ferdinand Rivera Morell wrote:
>>>>
>>>> On Fri, Oct 17, 2025 at 8:53 AM Harald Achitz via SG15 <
>>>> sg15_at_[hidden]> wrote:
>>>>
>>>>> Today's
>>>>>
>>>>> void fun(Foo* ptr) {
>>>>> my_supper_assert_macro (ptr!=nullpter);
>>>>> my_supper_assert_macro(ptr->hasData());
>>>>> }
>>>>>
>>>>> should not have any problems, ever
>>>>>
>>>>
>>>> AFAIU, if my_supper_assert_macro implements something equivalent to
>>>> observe, that is still UB at present. Or is it EB now?
>>>>
>>>> --
>>>> -- René Ferdinand Rivera Morell
>>>> -- Don't Assume Anything -- No Supongas Nada
>>>> -- Robot Dreams - http://robot-dreams.net
>>>>
>>>>
>>>> On devices that keep you alive, one example where I have seen such
>>>> super asserts in action, contracts are contracts They do not exist only
>>>> sometimes.
>>>>
>>>> Correct, (plain language) contracts are omnipresent. The contract
>>>> checking statements above violate the function contract and are thus
>>>> defective. Static analysis can diagnose such cases. For example, I would
>>>> expect a contracts enabled version of Coverity to report a FORWARD_NULL
>>>> issue for the above code.
>>>>
>>>>
>>>> I am not even sure if contracts as specified would pass regulatory
>>>> requirements, I think not.
>>>>
>>>> I’m not an expert on the subject by any means, but I would expect
>>>> regulatory requirements to consider the manner in which the software is
>>>> built; just as they consider the content of the source code and require
>>>> other supply chain guards. A requirement that deployed software not contain
>>>> portions for which the observe semantic is selected seems reasonable and
>>>> prudent.
>>>>
>>>> Tom.
>>>>
>>>> /Harald
>>>>
>>>> _______________________________________________
>>>> SG21 mailing list
>>>> SG21_at_[hidden]
>>>> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/sg21
>>>> Link to this post: http://lists.isocpp.org/sg21/2025/10/11351.php
>>>>
>>> _______________________________________________
>>> SG21 mailing list
>>> SG21_at_[hidden]
>>> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/sg21
>>> Link to this post: http://lists.isocpp.org/sg21/2025/10/11352.php
>>>
>>>
>>> _______________________________________________
>> SG21 mailing list
>> SG21_at_[hidden]
>> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/sg21
>> Link to this post: http://lists.isocpp.org/sg21/2025/10/11422.php
>>
>>
>> _______________________________________________
>> SG21 mailing list
>> SG21_at_[hidden]
>> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/sg21
>> Link to this post: http://lists.isocpp.org/sg21/2025/10/11424.php
>>
> _______________________________________________
> SG15 mailing list
> SG15_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg15
>
compilers or build modes. There is nothing we can add to the standard
within its current mandate that would fix this.
For P2900 as far as I know, it is completely legal for an implementation to
support only one contract evaluation mode. It is completely legal for it to
always check caller side, always check callee side, or to choose another
implementation method. As the compiler can choose ignore as the evaluation
mode for everything, it could just expression-check all contracts and not
use them. It can also export the full setup for all evaluation modes to
link time, load time or run time, allowing the linker (by doing a function
variant selection, or using LTO) or loader (with something like ifuncs) to
optimize out what it can based on information available at that point.
There is nothing in P2900 that is causing this problem. The implicit
assumption that people will be selecting a contract mode at compile time to
the exclusion of others with some compiler flag is what is causing this
problem. This also makes it hard to address this problem in P2900 or in the
current draft, as it is an implementation choice that causes the problems,
not the design. Admittedly, we *do* want there to be a fast compile output
and allowing the optimizer to look at your contracts is a very good
approach to do so. We should be smart enough to consider this separately
from the design of the contracts feature in C++ and to realize that we are
in the terrain of compiler flags, implementation-defined as-if usage and
linker + ABI changes, where we can achieve wonders if we're willing to put
in the leg work to implement such a faster output mode.
The problems that we are discussing stem from the choice to allow a
translation unit to pre-select a contract evaluation mode, and the implicit
assumption that this must not result in an ABI incompatibility. If and only
if we take those two assumptions do we end up with a situation where the
linker will see multiple function bodies that are meaningfully different.
However, they are only meaningfully different in out-of-contract behavior.
Each of them - including the ignore and observe ones - have the same
in-contract behavior. As such, the program in-contract validity is not
affected at all by which the compiler chooses. Each option results in a
valid output for the program compilation that does the exact same thing for
all in-contract calls.
That said, for the out-of-contract detection that contracts is trying to
offer, it *does* matter which we end up selecting. And as mentioned by
others, it is for some essential that it is checked and that the program is
terminated, while it is equally essential for others that it is checked and
that the program is *not* terminated. No fixed default choice of semantic
as proposed by P3640 can do this.
Within the contracts feature that we can still refer to by P2900 I see no
part that would still need changing in this regard. I do see a lot of space
for implementers to make choices and to create better, faster and more
optimized outputs that do implement the full scope of P2900's contracts, by
making the changes that are required at those levels to do so, and to
provide compiler flags to make particular selections.
On Mon, Oct 20, 2025 at 1:04 PM Oliver Rosten via SG15 <
sg15_at_[hidden]> wrote:
> To try to avoid the risk of going around in circles, John, can I confirm
> that my understanding of your position is correct.
>
> First, *I think* that everyone agrees on the following two points
> 1. The situation in which non-inlined inline functions end up with
> different semantics is not ideal.
>
> 2. This is a manifestation of a pre-existing problem in C++
>
> I think we also all agree on the 3rd point:
> 3. Contracts increases the surface area of exposure to this problem
>
> If I'm on the right track so far then is it fair to say that the bone of
> contention boils down to this?
>
> The weight each of us ascribes to the benefits of P2900 over the drawback
> of point 3. is different?
>
> John, I assume you see at least some value in P2900 (i.e. it's not
> completely worthless in your opinion, though correct me if I'm wrong).
> However, you see (amongst other things such as constification but that's a
> different discussion) that increased exposure to 3. outweighs any benefits
> of P2900 in your mind?
>
> O.
>
> On Mon, 20 Oct 2025 at 11:58, John Spicer via SG21 <sg21_at_[hidden]>
> wrote:
>
>> That assumes facilities that linkers might not have, and even if they
>> have them, it may require expert use to select the version of the function
>> you want.
>>
>> This also potentially requires you to *know* which functions you and your
>> libraries use.
>>
>> On most systems with conventional linkers you do not have the capability
>> you describe.
>>
>> John.
>>
>> On Oct 20, 2025, at 6:52 AM, Gašper Ažman via SG21 <sg21_at_[hidden]>
>> wrote:
>>
>> John,
>>
>> it shouldn't be "assigned randomly" - it's at best a final link-time
>> property (as specified). The final link (+LTO) can do it.
>>
>> On Mon, Oct 20, 2025 at 11:50 AM John Spicer <jhspicer_at_[hidden]> wrote:
>>
>>> The problem is that for function templates, member functions of class
>>> templates, and inline functions, the semantic is essentially assigned
>>> randomly if it is used in multiple TUs that are compiled with different
>>> semantics.
>>>
>>> In most complex environments you are dealing with things like libraries
>>> that are provided by others, so you may not have control over how it is
>>> built.
>>>
>>> You can also have two libraries that use a third library, but if those
>>> two libraries are a different semantic any user of the third library has no
>>> idea what semantic they’ll get even if their code also uses the third
>>> library and is built with a particular semantic.
>>>
>>> John.
>>>
>>> On Oct 17, 2025, at 11:45 AM, Gašper Ažman via SG21 <
>>> sg21_at_[hidden]> wrote:
>>>
>>> +1 to what Tom said.
>>>
>>> One part of this discussion is speaking as if semantics are assigned
>>> randomly or arbitrarily, where they are assigned by the person who ships
>>> the product - it has been pointed out time and time again that the actor
>>> deploying the application is the final arbiter of what "safe" means for a
>>> given contract check, because it's actually a function of "safe(context) ->
>>> bloom" (where "bloom" is a type with exactly two values of "no" and
>>> "perhaps").
>>>
>>> The stakeholder with the best context is the deployer of the
>>> application; the farther away you go from that stakeholder, the less
>>> context they have. Deferring the choice of semantic to as late as possible
>>> gives a better outcome.
>>>
>>> On Fri, Oct 17, 2025 at 4:33 PM Tom Honermann via SG21 <
>>> sg21_at_[hidden]> wrote:
>>>
>>>>
>>>> On Oct 17, 2025, at 10:23 AM, Harald Achitz via SG21 <
>>>> sg21_at_[hidden]> wrote:
>>>>
>>>>
>>>> On 2025-10-17 16:00, René Ferdinand Rivera Morell wrote:
>>>>
>>>> On Fri, Oct 17, 2025 at 8:53 AM Harald Achitz via SG15 <
>>>> sg15_at_[hidden]> wrote:
>>>>
>>>>> Today's
>>>>>
>>>>> void fun(Foo* ptr) {
>>>>> my_supper_assert_macro (ptr!=nullpter);
>>>>> my_supper_assert_macro(ptr->hasData());
>>>>> }
>>>>>
>>>>> should not have any problems, ever
>>>>>
>>>>
>>>> AFAIU, if my_supper_assert_macro implements something equivalent to
>>>> observe, that is still UB at present. Or is it EB now?
>>>>
>>>> --
>>>> -- René Ferdinand Rivera Morell
>>>> -- Don't Assume Anything -- No Supongas Nada
>>>> -- Robot Dreams - http://robot-dreams.net
>>>>
>>>>
>>>> On devices that keep you alive, one example where I have seen such
>>>> super asserts in action, contracts are contracts They do not exist only
>>>> sometimes.
>>>>
>>>> Correct, (plain language) contracts are omnipresent. The contract
>>>> checking statements above violate the function contract and are thus
>>>> defective. Static analysis can diagnose such cases. For example, I would
>>>> expect a contracts enabled version of Coverity to report a FORWARD_NULL
>>>> issue for the above code.
>>>>
>>>>
>>>> I am not even sure if contracts as specified would pass regulatory
>>>> requirements, I think not.
>>>>
>>>> I’m not an expert on the subject by any means, but I would expect
>>>> regulatory requirements to consider the manner in which the software is
>>>> built; just as they consider the content of the source code and require
>>>> other supply chain guards. A requirement that deployed software not contain
>>>> portions for which the observe semantic is selected seems reasonable and
>>>> prudent.
>>>>
>>>> Tom.
>>>>
>>>> /Harald
>>>>
>>>> _______________________________________________
>>>> SG21 mailing list
>>>> SG21_at_[hidden]
>>>> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/sg21
>>>> Link to this post: http://lists.isocpp.org/sg21/2025/10/11351.php
>>>>
>>> _______________________________________________
>>> SG21 mailing list
>>> SG21_at_[hidden]
>>> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/sg21
>>> Link to this post: http://lists.isocpp.org/sg21/2025/10/11352.php
>>>
>>>
>>> _______________________________________________
>> SG21 mailing list
>> SG21_at_[hidden]
>> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/sg21
>> Link to this post: http://lists.isocpp.org/sg21/2025/10/11422.php
>>
>>
>> _______________________________________________
>> SG21 mailing list
>> SG21_at_[hidden]
>> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/sg21
>> Link to this post: http://lists.isocpp.org/sg21/2025/10/11424.php
>>
> _______________________________________________
> SG15 mailing list
> SG15_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg15
>
Received on 2025-10-20 11:32:06
