Skip to content

[temp.constr.atomic] if an atomic constraint is made by a requires-expression, invalid types/expressions in its requires-seq should not directly affect the satisfaction of the constraint itself #675

Open
@ingmaurorusso

Description

@ingmaurorusso

Reporter:
mauro russo

Reference (section label): Reference (section label):
temp.constr.atomic - p3

Link to reflector thread (if any):
None

Issue description:

As discussed on std-discussion mailing list (from 2882 to 2887),
the standard might be more precise when discussing about invalid types / expressions in an atomic constraint after the substitutions.

In particular, if the expression of atomic constraint is a requires-expression, then the requires-expression is valid (and eventually satisfied) even if its body (requires-seq) contains any invalid types/expression.
However, the text of temp.constr.atomic - p3 generically reads:
"... If substitution results in an invalid type or expression in the immediate context of the atomic constraint (...), the constraint is not satisfied. ... ".

Since no defintion or note or other clause excludes the requires-seq from what has to be considered as part of the immediate context here, then we fall in a lack of consistency compared to the text of expr.prim.req.general - p5 as it allows the expression to evaluate as true even if some invalid type or expression is within the sequence of its requirements.

In 2882 there is an example where the incosistency is in place, but here I prefer to report the nicer example from Andrew Schepler ( 2887 ):

template<typename T>
requires ( ! requires { T::value; } )
int func() { return 0;}

int a = func<int>();

Such a code is accepted by major compilers ( godbolt ) despite int::value is an invalid expression in the atomic constraint. This appears to be a fair behaviour, because any requires-expression should represent (IMHO) a boundary between different levels of a constraint hierarchy.
Such a boundary is already expressed for a nested requirement inside a requires-expression ( expr.prim.req.nested - p1 ).

Suggested resolution:

A note similar to temp.deduct.general - p9 (related to the body of a lambda-expression as not part of the immediate context) should help.
However, such a similar note alone would risk to consider invalid expressions inside the body of a requires-expression as an error in non-immediate context, which is even worse.

Therefore, some stronger boundary separation in temp.constr.atomic - p3 should be considered, exactly as in expr.prim.req.nested - p1 .
For example, add after "If substitution results in an invalid type or expression in the immediate
context of the atomic constraint (13.10.3.1), the constraint is not satisfied.
" the words "The validity of a requires-expression is not affected by the invalid types or expressions inside its requirements which only get involved in the constant evaluation of such expression as specified in (7.5.8)."

In addition, Andrew Schepler, in 2887 , remarkably suggested to enrich also the parts temp.deduct.general - p7 - Note 4 and temp.deduct.general - p8

His original comment on it reads:
I'd consider adding to the note in [temp.deduct.general]/7, which currently explains how a function's noexcept-specifier is instantiated, instead of during the TAD substitutions in the "deduction substitution loci". A template's constraints are a similar thing closely associated with the template declaration, but as you're clarifying, the substitution happens in a different way. Although in this case checking constraints always happens immediately after the TAD substitution (paragraph 5), it would still make clear that paragraph 8 "If a [TAD] substitution results in an invalid type or expression..." does not apply.

In conclusion, due to the presence of multiple points where it would be needed to reuse the idea of ignoring the invalid types or expressions in the body of a requires-expression, for any aim in the contexts including the requires-expression itself (other than its true/false constant evaluation), the best solution is likely to enrich the clause expr.prim.req.general, by adding a new part 6,
as proposed in the PR 7712
or, better, in this local branch.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions