[clang] Enable AST mutation in the constant evaluator (PR #115168)

Vlad Serebrennikov via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 25 15:14:44 PST 2024


Endilll wrote:

> > > the special "the language rules say this is manifestly constant evaluated" cases that should be able to perform AST mutations, that we need to be extremely careful to invoke at exactly the right times and in exactly the right cases and to invoke only once
> > 
> > 
> > Can you expand on the "to invoke only once" bit? As I understand the position of authors of P2996, calls to `define_aggregate` with the same arguments are supposed to be idempotent. Do you see reasons why we wouldn't be able to achieve that, meaning that we need to prevent `define_aggregate` to be called multiple times (with the same arguments) on the language level?
> 
> I think it's short-sighted to imagine that will work for the breadth of compile-time constructs we'll end up providing. People have already asked for things like a consteval function that produces a warning or an error -- is that also going to be idempotent? What about consteval facilities that generate random numbers, or produce a log file on the build machine? What about a consteval utility that generates a new anonymous global? What do you do if you _want_ each call to your "make a new type" facility to guarantee to produce a new, distinct type?
> 
> Maybe we can say no to some of those things, but I don't think we'll be able to say no to all of them forever. It seems more forward-looking to me to instead guarantee that we will evaluate exactly the things we're required to evaluate in this new mode, exactly once each.

Consider the following example:
```cpp
struct S;
consteval int f() {
  define_aggregate(^^S, {}); // we say this function is not idempotent,
                             // so we want guarantees that it can't be evaluated more than once
  write_char_to_file("output.txt", 'a'); // presumably we want this to evaluated as many times as we get here
  return 0;
}

constexpr int a = f();
constexpr int b = f();
```
I think there's a contradiction between what `define_aggregate` needs and that hypothetical `write_char_to_file` needs from the same language construct (which is currently called _plainly constant-evaluated expression_). If we say that we're not going to guarantee idempotency for any function that can have side effects during constant evaluation, then it seems that it just can't work. What do you think of this?

I'm collecting material to present to WG21 (and for my own understanding, too), because I don't feel we have a strong position there.

https://github.com/llvm/llvm-project/pull/115168


More information about the cfe-commits mailing list