[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 5: Iterating Expansion Statements) (PR #169684)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Nov 27 10:34:25 PST 2025
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
More information about the llvm-branch-commits
mailing list