C++ Logo

std-discussion

Advanced search

Re: atomic constraint rules vs requires-clause rules

From: Brian Bi <bbi5291_at_[hidden]>
Date: Sat, 15 Feb 2025 09:33:08 +0100
On Wed, Feb 12, 2025 at 12:03 AM mauro russo via Std-Discussion <
std-discussion_at_[hidden]> wrote:

> I will try to shorten the post,
>
> referring for the moment to the first topic only (A) from previous post
> (2800):
>
> do you believe that when an atomic constraint is made by a
> requires-expression,
> the content of the requires-expression body (i.e., requirement-seq) is not
> part of the immediate context of the atomic constraint ?
>

> I do, as it currently seems more consistent to me, based on the different
> perspective provided by the text of the parts [expr.prim.req.general]-p5, [temp.constr.atomic]-p3,
> and [temp.res.general]-p(6.4).
>
>
> Do you believe that the fact that it is not part of the immediate context
> of the atomic constraint is already well clear in the standard ?
> I am not sure. I currently suppose that a note similar to
> [temp.deduct.general]-p9 would be needed,
> unless I have missed where we may get the basic definition of immediate
> context: I only see double quotes used for it in [temp.deduct.general]-p8
> (Note 6) (excluding library part)
>
>
> Hope to get some answer on this reduced post by any moderator.
>
> Il giorno mer 29 gen 2025 alle ore 23:57 mauro russo <
> ing.russomauro_at_[hidden]> ha scritto:
>
>> hello,
>>
>> I am writing again about the topic of:
>> https://lists.isocpp.org/std-discussion/2025/01/2783.php
>> and
>> https://lists.isocpp.org/std-discussion/2025/01/2787.php
>>
>> for which I have got no answer.
>>
>> I may suppose you are intentionally lowering the frequence to answer me
>> because of I am posting a quite number of questions in these months. That's
>> ok to me, but I hope you may increase the frequency in case no other
>> discussions are in place by other users.
>>
>
If you want faster replies, you need to get better at being concise:

   - lead with an example
   - if all compilers agree on the behavior of the example, ask something
   like "why does this compile?" or "why doesn't this compile?" or "why does
   this print 1 and not 2?", etc
   - if compilers disagree on the behavior of the example, say so and
   provide a godbolt link
   - keep the explanation short: people rarely have time to read walls of
   text
   - don't scatter the actual questions throughout the email

I suggest looking at descriptions of some recent core issues to get a sense
of how to communicate these kinds of questions concisely.


>
>> I will try again to recap the 3 questions. related to the constraints.
>>
>> As general idea, I have got that an invalid type/expression leads the
>> constraint just to fail if it is in immediate-context, otherwise to an
>> ill-formed program if in non-immediate-context (e.g., in the body of a
>> lambda expression),
>> provided that the verification of that type/expression is triggered by
>> the fact that previous parts of the constraint (in the lexical order, e.g.,
>> in the pieces of a requires expression, or in the combined list of atomic
>> constraints for a normal form) weren't able to determine already an overall
>> result for the constraint (e.g., false for an AND combination, or true for
>> an OR combination),
>> but also that an invalid type/expression always in place for a templated
>> entity (i.e., regardless of the instantiation) represents an IFNDR case.
>>
>> That said, I have reported in
>> https://lists.isocpp.org/std-discussion/2025/01/2783.php the text
>> associated to both requires expression ([expr.prim.req.general]-p5) and
>> atomic constraint ([temp.constr.atomic]-p3 and
>> [temp.res.general]-p(6.4)),
>> and I have noticed two potential problematic topics when an atomic
>> constraint is made by a requires expression.
>> I recall them in the following, and refine/fix details of the discussion.
>>
>> Before discussing the detail of the first 2 questions, it is important to
>> highlight that the normal form of the constraints associated to a function,
>> is built according to rules from [temp.constr.normal], where no 'explosion'
>> is indicated in case of requires expression, which means that a requires
>> expression boils down to be an atomic constraint even when it contains
>> multiple requirements (simple, type, compound, nested:
>> [expr.prim.req.general]-p1).
>>
>> A) the first topic is for the case when that requires expression contains
>> a nested requirement, which therefore contains a constraint-expression, in
>> turn supposed to contain AND / OR operators, combining further nested
>> constraints/requirements; let's now suppose that one of these nested ones
>> contains an invalid type/expression, but also that another
>> constraint/requirement preceding in the lexical order, allows to provide a
>> true value for the original requires expression.
>> If I would exactly apply the text of [temp.constr.atomic]-p3, then it
>> reads that an invalid type/expression (in immediate context) leads soon the
>> constraint to be not satisfied, whereas the rules from [expr.prim.req.general]-p5
>> postpone the check of invalid type/expression for each contained
>> requirement only after that previous requirements have already been checked
>> and successfully verified (true result), and similarly the rules from [temp.constr.op]-p2/p3
>> state that the constraints conjunctions and disjunctions are checked one by
>> one, ignoring the residual ones as soon as a constraint allows to get a
>> logical overall result.
>> Please, note that in my original post (2783), I erroneuosly considered a
>> case with false overall logical result for the requires expression, and
>> invoked only the rules from [expr.prim.req.general]-p5, but this is not
>> a conflict because the final result as false is provided by both [temp.constr.atomic]-p3
>> and [expr.prim.req.general]-p5.
>>
>> As highlighted in the second post (2787), I really believe that
>> everything becomes clear and well consistent if the presence of an invaild
>> type/expression within a requires expression does not mean that the
>> requires expression is itself an invalid expression. Indeed, this would
>> represent a hierarchical separation between the atomic constraint and what
>> is inside the requires expression.
>> Please, let me know if this is true, and if in your opinion this is in
>> some way already clear in the standard for any motivation (e.g., concept of
>> 'immediate context', or anything else).
>> If the solution is in the definition of 'immediate context', don't you
>> believe that the standard might state clearly something (similar to
>> [temp.deduct.general]-p9) about the requirement-body not being part of the
>> immediate context of an atomic constraint corresponding to the requires
>> expression ? However, in such case, I would be also afraid of formally
>> incorrectness about the effect of invalid within the requirements of the
>> requires-expression (i.e., invalid in a non-immediate context for the
>> original atomic constraint), and therefore some more note should be added
>> to clarify that any decision is based on the rules for those requirements.
>> Otherwise (if none of the previous ones apply), do you believe (as I do)
>> that the standard may be clarified in [temp.constr.atomic]-p3 when an
>> atomic constraint is made by a requires expression, and eventually even in [expr.prim.req.general]-p5
>> in order to introduce a similar 'hierarchical separation' when one of the
>> requirements is a nested requirement ? (but I don't know if it was really
>> intended to have also the second mentioned kind of hierarchy... likely not).
>>
>>
>> B) the second topic is related to the cases of IFNDR when the invalid
>> type/expression is always in place; indeed, [expr.prim.req.general]-p5
>> reads that the IFNDR is there anyway, which means regardless of any
>> satisfation check is performed or not involving the part containing the
>> invalid type/expression; on the contrary, [temp.res.general]-p(6.4)
>> reads that the IFNDR is only effective with the additional condition that
>> no satisfaction check is performed on the constraint-expression containing
>> the always-invalid type/expression.
>> But, what happens if the invalid is in an immediate context, a check is
>> performed, therefore (based on [temp.constr.atomic]-p3) the constraint
>> is just not satisfied but no ill-forming is notified by the compiler ?
>> Is it really wanted to drop the IFNDR just because a check was performed ?
>> Can I state that if the invalid is inside a requires expression, the
>> IFNDR remains anyway in place based on [expr.prim.req.general]-p5 ?
>> Was also here any hierarchical separation intended as discussed for
>> previous topic ?
>> Note also that [temp.res.general]-p(6.4) makes no distinction between
>> immediate and non-immediate contexts, nor between templated and
>> non-templated entities -> is it really wanted not to have IF for
>> non-immediate contexts ? Not even for non-templated entities (for them, Note
>> 1 in [expr.prim.req.general]-p5 for requires expressions states IF
>> instead of IFNDR) ?
>> Note finally that last part of [expr.prim.req.general]-p5 (after Note 1)
>> seems not to be specific for immediate or non-immediate contexts, but I do
>> believe that for non-immediate ones the intended behaviour is IF instead of
>> IFNDR, isn't it ?
>>
>>
>> Last topic, with a short question:
>> C) (which was presented since the post 2783):
>> In [temp.constr.normal], the example in p1.4) reads that the atomic
>> constraint-expression 'true' has empty mapping.
>> The point is that no rule from [temp.constr.normal] exactly states the
>> possibility to get an empty mapping.
>> We have part p(1.9) as default case always indicating an identity
>> mapping. I guess it should be extended to indicate empty mapping when
>> the expression is constant, that is, not involving any template
>> parameter (you know
>> for sure the best formal words to say it there).
>> I don't believe it's fair to consider the definition of this special
>> case just through the example in p(1.4).
>>
>>
>> Thank you.
>>
>>
>> Il giorno gio 16 gen 2025 alle ore 01:15 mauro russo <
>> ing.russomauro_at_[hidden]> ha scritto:
>>
>>> I thought about the topics once more.
>>> (https://lists.isocpp.org/std-discussion/current/2783.php)
>>>
>>> Maybe the solution about the potential ambiguity between the rules on
>>> atomic constraints and the rules on requires-clause, is that a
>>> requires-clause including invalid type/expression, is not itself an invalid
>>> expression, as this would mean that an atomic constraint being a
>>> requires-clause means that the requires-clause is well-formed (valid
>>> expression) and so only the rules for requires-clause apply.
>>>
>>> Please, confirm this is true. However, in such a case, I would suggest
>>> to add a short note in [temp.constr.atomic]. I am not convinced such a note
>>> would be a 'tutoring'... but you can choose.
>>>
>>> Additionally, I still wonder about the text in [temp.res.general] -
>>> p(6.4), which appear with a different spirit from [expr.prim.req.general] -
>>> p5, because in case the always-ill-forming is in an immediate context and
>>> there is any code triggering the check involving that context, the former
>>> does not lead to IFNDR (nor to a compilation error triggered by the
>>> existing check), whereas the latter does it (IFNDR for immediate context,
>>> and of course compilation error for non-immediate context).
>>>
>>> Even my third doubt, that is about the need to specify the generation of
>>> atomic constraints with empty mapping, still applies.
>>>
>>> Please, read previous message (mentioned above) of this thread for the
>>> complete background.
>>>
>> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>


-- 
*Brian Bi*

Received on 2025-02-15 08:33:24