[concepts] Should requires-expressions contain a decl?

Hey,
I’m working on our concepts implementation and am pretty close to finishing the implementation. All that’s left is requires-expressions which I have the code mostly written for, and am testing it now.
I came across a dilemma with requires-expressions and would like to know what you guys think should happen.
We have requires expressions which declare local parameters - parameters that need to be visible in the body of the requires-expression. The current machinery would require such decls to reside in a declcontext which itself should be a decl as it stands today.
Should requires-expr therefore be an expression linked to a generated decl? The closest existing thing to this would be a lambda expression, but lambda expressions cannot appear in unevaluated contexts while requires-expressions clearly can.
Also, requires expressions as I have them now can contain another kind of declaration - when using a constrained-parameter requirement (e.g. requires {{ 0 } → Same;} ), a template parameter list with one parameter is generated.

My initial thought seems to indicate a “RequiresExprBodyDecl : Decl, DeclContext” is requires here, but I may be missing some implications of this right now - are there any inherent problems with having this sort of declaration generated here?

Thanks :slight_smile:

Hey,
I'm working on our concepts implementation and am pretty close to
finishing the implementation. All that's left is requires-expressions which
I have the code mostly written for, and am testing it now.
I came across a dilemma with requires-expressions and would like to know
what you guys think should happen.
We have requires expressions which declare local parameters - parameters
that need to be visible in the body of the requires-expression. The current
machinery would require such decls to reside in a declcontext which itself
should be a decl as it stands today.

Agreed that we need Decls for the parameters, and the requires-expression
is a reasonable place for the DeclContext. I am not sure if making the
expression itself also a Decl helps or harms, but trying it probably does
not hurt.

Should requires-expr therefore be an expression linked to a generated
decl? The closest existing thing to this would be a lambda expression, but
lambda expressions cannot appear in unevaluated contexts while
requires-expressions clearly can.

We *do* allow lambda expressions in unevaluated operands now (see P0315);
however, the rules are set up so that we can avoid mangling their content
or comparing them within a translation unit.
For the purposes of *requires-expression*s, we will need to both be able to
mangle their content and compare them within a translation unit (for
redeclaration matching).
The comparison will need to adjust for the difference between the Decls in
one instance and the Decls in another. The Standard should probably be
adjusted so that the names of the local parameters are ignored for the
purpose of determining whether expressions involving template parameters
are equivalent.

Also, requires expressions as I have them now can contain another kind of
declaration - when using a constrained-parameter requirement (e.g. requires
{{ 0 } -> Same<int>;} ), a template parameter list with one parameter is
generated.

I believe for the similar case of "auto" variables, we produce the template
parameter list on the stack.

With compound requirements, you have a complete abstract-declarator as part of the deduced-against types, which can reference the template parameter in all manner of ways. That’s what led me to store the template parameter list - do you see a specific problem with storing it?

I don't see a problem with storing it other than the usual concerns around
memory usage. The template parameter list is an artifact that is mainly
useful for performing the deduction, but the deduction is not likely to
occur with every instance of the "same" *requires-expression*. The
information for the *return-type-requirement* can be stored as a type. This
is straightforward for the *trailing-return-type* case. For the latter
case, I think it is not a stretch to implement a derived class of
clang::DeducedType that represents a constrained placeholder type.