The current interpreter does _not_ evaluate function calls when checking
for a potential constant expression.
However, it _does_ evaluate the initializers of constructors. In the
bytecode interpreter, this is harder because we compile the initializers
and the body of a constructor all in the same function.
Add a special opcode that we emit after the constructor initializers and
that aborts when we're checking for a potential constant expression.
When activating a union member, none of the unions in that path can have
a non-trivial constructor. Unfortunately, this is something we have to
do when evaluating the bytecode, not while compiling it.
The original problem description sounded sane but it was lacking a bit.
What happens where is that the global block is ultimately not
initialized simply because it was already created before and its
initializer failed, causing us to call invokeDtor() in a previous
evaluation.
Check for the initialion state earlier and abort there instead of
accessing the (now uninitialized) data of the block, causing msan
failures.
See the failed msan build at
https://lab.llvm.org/buildbot/#/builders/164/builds/17206
Fixes#173950.
The bytecode interpreter was crashing when evaluating typeid() on
references to dynamically allocated objects. For example, this would
cause an assertion failure:
static A &a = *new A;
const std::type_info &a_ti = typeid(a);
The problem was that when initialization failed, the code tried to call
invokeDtor() on blocks that were never marked as initialized. This
caused the assertion "IsInitialized" to fail. With this fix, we first
check if the block is actually initialized before trying to invoke its
destructor.
The test case I added reproduces the original crash and with the fix, it
now passes.
Otherwise, the scope might be (lazily) initialized in one of the arms of
the conditional operator, which means the will NOT be intialized in the
other arm.
Fixes https://github.com/llvm/llvm-project/issues/170981
And use them instead of the extending decl. This is close to what the
current interpreter is doing.
This is NFC right now but fixes a problem I encountered while looking
into the expansion statement stuff.
We didn't take `IntAP`/`IntAPS` into account when casting to and from
the computation LHS type. This broke the
`std/ranges/range.factories/range.iota.view/end.pass.cpp` test.
We used to create a scope for the true- and false expression of a
conditional operator. This was done so e.g. in this example:
```c++
struct A { constexpr A(){}; ~A(); constexpr int get() { return 10; } }; // all-note 2{{declared here}}
static_assert( (false ? A().get() : 1) == 1);
```
we did _not_ evaluate the true branch at all, meaning we did not
register the local variable for the temporary of type `A`, which means
we also didn't call it destructor.
However, this breaks the case where the temporary needs to outlive the
conditional operator and instead be destroyed via the surrounding
`ExprWithCleanups`:
```
constexpr bool test2(bool b) {
unsigned long __ms = b ? (const unsigned long &)0 : __ms;
return true;
}
static_assert(test2(true));
```
Before this patch, we diagnosed this example:
```console
./array.cpp:180:15: error: static assertion expression is not an integral constant expression
180 | static_assert(test2(true));
| ^~~~~~~~~~~
./array.cpp:177:24: note: read of temporary whose lifetime has ended
177 | unsigned long __ms = b ? (const unsigned long &)0 : __ms;
| ^
./array.cpp:180:15: note: in call to 'test2(true)'
180 | static_assert(test2(true));
| ^~~~~~~~~~~
./array.cpp:177:51: note: temporary created here
177 | unsigned long __ms = b ? (const unsigned long &)0 : __ms;
| ^
1 error generated.
```
because the temporary created for the true branch got immediately
destroyed.
The problem in essence is that since the conditional operator doesn't
create a scope at all, we register the local variables for both its
branches, but we later only execute one of them, which means we should
also only destroy the locals of one of the branches.
We fix this similar to clang codgen's `is_active` flag: In the case of a
conditional operator (which is so far the only case where this is
problematic, and this also helps minimize the performance impact of this
change), we make local variables as disabled-by-default and then emit a
`EnableLocal` opcode later, which marks them as enabled. The code
calling their destructors checks whether the local was enabled at all.
This reverts commit b1e511bf5a4c702ace445848b30070ac2e021241.
https://github.com/llvm/llvm-project/issues/160243
Reverting because the GCC C front end is incorrect.
---------
Co-authored-by: Jim Lin <jim@andestech.com>
This rename was made as part of
https://github.com/llvm/llvm-project/pull/147835 in order to ease
rebasing the PR, and give a nice window for other patches to get rebased
as well.
It has been a while already, so lets go ahead and rename it back.
So the static invoker's Function still points to the static invoker
instead of the call operator of the lambda record. This is important for
a later commit.
This is not implemented at compile time and asserts in assertion builds,
so reject it here.
Fixed the coding style in `BuiltinShuffleVector` at the same time.
Fixes#158471