Sirraide wrote:
> One thing that I still need to figure out is how to construct and evaluate a
> lambda in Sema, because that’s required for computing the expansion size.
Essentially, the expression we need to evaluate is this (CWG 3131 may end up
changing this a bit, but not in ways that matter for the main problem here):
```c++
[] consteval {
std::ptrdiff_t result = 0;
for (auto i = begin; i != end; ++i) ++result;
return result;
}()
```
I’ve been looking into this a bit more, and I can think of a few approaches,
but none of them seem ‘good’ to me:
1. Actually create and evaluate a lambda. This would basically entail
performing some of the steps done by `ParseLambdaExpressionAfterIntroducer()`;
the problem is that that’s a parser function, and we’re in Sema, so that would
entail some refactoring (e.g. `ParseScope` and the scope caching machinery
would have to be moved into `Sema`, but honestly, at least that part probably
belongs in Sema anyway considering that most of the `ParseScope` implementation
consists of calls to Sema functions). It also means that we’re, well, creating
an entire lambda just to evaluate a few statements, which is probably not the
fastest way of doing this. The main benefits of this approach are that we could
‘just evaluate it’, i.e. it wouldn’t require updating the constant interpreter,
and furthermore, we’d be doing exactly what the standard wants us to do, so we
*shouldn’t* run into any strange issues here that could be caused by us doing
‘something equivalent’ instead.
2. Somehow figure out a way to evaluate multiple statements in a row including
some that mutate local variables without requiring a stack frame (or by
introducing some sort of ‘fake’ stack frame); I’m not sure how well that would
work, and another issue is that creating a few local variables and a compound
statement without also introducing a scope for them seems like a bad idea (and
creating a scope requires the `ParseScope` refactor anyway). Moreover, this
approach may require updating both constant interpreters (unless the new one
happens to just support that already).
3. Instead of creating and evaluating statements, just evaluate the expressions
individually and introduce *some* way of representing compile-time mutable
variables, e.g. by having references to `result` above be some sort of
`FakeCompileTimeLValueExpr` (or maybe we could just reuse `ConstantExpr`?) that
is an lvalue to some `APValue` object defined elsewhere (e.g. just on the
stack). This would require updating `APValue::LValueBase` because we’d need to
introduce a new lvalue kind. This approach would save us from having to create
a bunch of AST nodes (or even an entire lambda) just to evaluate them and throw
them away; however, we’d still have to update both constant interpreters, and I
also think it’s just too much of a hack and might end up breaking in weird,
unforeseen ways because it’s quite far removed from what the standard
*actually* wants us to do here.
So if anyone has any better ideas or an opinion as to which of these approaches
seems the least horrible, please let me know.
https://github.com/llvm/llvm-project/pull/169684
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits