Capture of a local parameter in requires expression
Asked Answered
I

1

6

A requires-expression similarly to a function can introduce local parameters using a parameter list. And lambda expressions defined at block scope may have captures without initializers. Is it allowed to capture local parameters of requires-expression?

Consider the example:

template<typename T>
concept C = requires( T t ) { 
    [t]{ [t]{}; };
};

which is accepted by both GCC and MSVC. And only Clang complains (demo: https://gcc.godbolt.org/z/o17hWGabG) here:

error: constraint variable 't' cannot be used in an evaluated context

As far as I understand [t]{ [t]{}; }; is a simple requirement, where the expression is an unevaluated operand; only language correctness is checked.

What is the expected behavior of a compiler here?

Interlace answered 25/9, 2024 at 19:40 Comment(4)
Tricky. C++20 says A local parameter shall only appear as an unevaluated operand within the constraint-expression and t doesn't have any storage or lifetime. Perhaps capturing it therefore counts as evaluating it... Hmm... – Wireless
@TedLyngmo, no, it doesn't. See also here. – Quarta
Apparently I may be wrong πŸ˜” – Quarta
@Quarta I still don't know what to make of this. I hope you are right though. :-) – Wireless
Q
3

From expr.prim.req.general#2 (my emphasis):

A requires-expression is a prvalue of type bool whose value is described below. Expressions appearing within a requirement-body are unevaluated operands.

where "requirement-body" refers to the { … } part.

So Clang is complaining incorrectly, I believe.

Furthermore, this discussion on llvm-project seems to support my understanding. I suspect you're are the one who reported it there too, by the way.


user17732522's point below is that

Quarta answered 25/9, 2024 at 19:52 Comment(7)
The expressions in the body of a lambda expression are not subexpressions of the lambda expression and therefore they are still potentially-evaluated, even if the lambda expression is subexpression of an unevaluated operand. The initializers of captures (as in your linked discussion) are subexpressions of the lambda expression and therefore inherit the "unevaluated" property. So it is different from this question. – Ordinance
Also, the current highlighted wording in your quote makes it sound as if each expression appearing anywhere in the requirements was unevaluated, but that is clearly not the intended meaning. It should apply only to the top-level expressions of each requirement. See cplusplus.github.io/CWG/issues/2911.html. – Ordinance
However, t doesn't appear in any potentially-evaluated expression anyway. It only appears as a capture, which is not an expression. So that shouldn't really be relevant. That the lambdas capture t implies that they odr-use it regardless, but I also couldn't find any reason that odr-use of the parameter should be disallowed. – Ordinance
@user17732522, please help me understand with some quotes in the draft: 1. The expressions in the body of a lambda expression are not subexpressions of the lambda expression; where do I read/understand/deduce this from the draft? 2. and therefore they are still potentially-evaluated, even if the lambda expression is subexpression of an unevaluated operand; are you referring to basic.def.odr#3, in which "An expression" is [t]{};, which is however not a subexpression of [t]{ [t]{}; };, this latter being an unevaluated operand as per my quote? – Quarta
(I see that the part of the quote I've put in bold would be deleted, if 2911 was accepted, right?) – Quarta
1. "subexpression" is defined in eel.is/c++draft/basic#intro.execution-4. If you go through the definition you'll see that expressions in the lambda body are not covered by it. 2. Yes. 3. It would be reworded so that only the top-level expressions in the requirements would be unevaluated operands. – Ordinance
I'll have read of that later in the day. In the meanwhile, I think the fact that something "unevaluated" can textually contain something "evaluated" is very, very, very confusing! – Quarta

© 2022 - 2025 β€” McMap. All rights reserved.