64 Commits

Author SHA1 Message Date
Timm Baeder
7f1907cea0
[clang][bytecode] Allow bool sizes in array new expressions (#180696)
Looks like this is a thing, so allow them.
2026-02-10 09:27:17 +01:00
Timm Baeder
323bb14349
[clang][bytecode] Finish support for msvc::constexpr (#177388)
Keep track of whether an `InterpFrame` is allowed to call
`msvc::constexpr` functions via two new opcodes.
2026-01-23 11:25:21 +01:00
Timm Baeder
d904de0806
[clang][bytecode] Fix a diagnostic discrepancy (#177384)
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.
2026-01-23 08:36:03 +01:00
Timm Baeder
95f0fab7fa
[clang][bytecode] Fix conditional operator scoping wrt. local variables (#169030)
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.
2025-11-24 07:34:48 +01:00
Timm Baeder
6a8072838c
[clang][bytecode][NFC] Limit pointer and array ops to integer indices (#168022)
AluOpcode includes fixed point as well, which isn't possible here.
2025-11-14 08:36:48 +01:00
Timm Baeder
70eb4b0a60
[clang][bytecode] Fix diagnosing subtration of zero-size pointers (#167839)
We need to get the element type size at bytecode generation time to
check. We also need to diagnose this in the LHS == RHS case.
2025-11-13 09:58:43 +01:00
Timm Baeder
a8a0ffba73
[clang][bytecode] Check source pointer for bitcast validity (#166907)
Unfortunately this is more dynamic than anticipated.

Fixes https://github.com/llvm/llvm-project/issues/165006
2025-11-10 08:17:08 +01:00
Timm Baeder
6fac21e404
[clang][bytecode] Avoid copies with elidable CXXConstructExprs (#166931)
To fix the newly added cwg6.cpp.
2025-11-08 05:30:01 +01:00
Timm Baeder
7c441b21b7
[clang][bytecode] Catch placement-new into invalid destination (#164804)
We failed to check for null and non-block pointers.

Fixes https://github.com/llvm/llvm-project/issues/152952
2025-10-24 08:08:18 +02:00
Timm Baeder
954a719056
[clang][bytecode] Fix unsigned wraparound behavior with bitfields (#164445)
and inc/dec operations. We need to truncate the new value to the
bitfield bitwidth.
2025-10-22 11:01:33 +02:00
Timm Baeder
c750487292
[clang][bytecode] Diagnose volatile writes (#160350) 2025-09-28 07:21:40 +02:00
Timm Baeder
29c55d0f7b
[clang][bytecode] Improve error detection in BitCastPrim op (#158575)
Reject bitcasts to pointer types unless it's to `nullptr_t` and always
reject bitcasts to member pointer types.


Fixes #156174
2025-09-16 10:02:18 +02:00
Timm Baeder
1b9ee0bb74
[clang][bytecode] Fix diagnostics for int128 enums (#151340)
CheckEnumValue was not handling PT_IntAP/PT_IntAPS.
2025-07-31 05:59:17 +02:00
Eli Friedman
0bbe1b30fa
[clang] Forbid reinterpret_cast of function pointers in constexpr. (#150557)
This has been explicitly forbidden since C++11, but somehow the edge
case of converting a function pointer to void* using a cast like
`(void*)f` wasn't handled.

Fixes #150340 .
2025-07-30 18:15:17 -07:00
Timm Baeder
23eef9a7c4
[clang][bytecode] Activate primitive fields before initializing them (#149963)
The initializer itself might need the field to be active.
2025-07-23 06:09:27 +02:00
Timm Baeder
fed6db45df
[clang][bytecode] Diagnose dereferencing a null pointer (#149330) 2025-07-19 21:39:06 +02:00
Timm Baeder
17d3029331
[clang][bytecode] Make union activation more granular (#148835)
Only activate things if the syntactical structure suggests so. This adds
a bunch of new opcodes to control whether to activate in stores, etc.

Fixes #134789
2025-07-16 09:03:33 +02:00
Timm Baeder
32fc625a3f
Reapply "Reapply "[clang][bytecode] Allocate IntegralAP and Floating … (#145014)
…types usi… (#144676)"

This reverts commit 68471d29eed2c49f9b439e505b3f24d387d54f97.

IntegralAP contains a union:
  union {
    uint64_t *Memory = nullptr;
    uint64_t Val;
  };

On 64bit systems, both Memory and Val have the same size. However, on 32
bit system, Val is 64bit and Memory only 32bit. Which means the default
initializer for Memory will only zero half of Val. We fixed this by
zero-initializing Val explicitly in the IntegralAP(unsigned BitWidth)
constructor.


See also the discussion in
https://github.com/llvm/llvm-project/pull/144246
2025-06-20 18:06:01 +02:00
Timm Bäder
68471d29ee Revert "Reapply "[clang][bytecode] Allocate IntegralAP and Floating types usi… (#144676)"
This reverts commit 7c15edb306932e41c159f3d69c161ed0d89d47b7.

This still breaks clang-armv8-quick:
https://lab.llvm.org/buildbot/#/builders/154/builds/17587
2025-06-18 15:17:53 +02:00
Timm Baeder
7c15edb306
Reapply "[clang][bytecode] Allocate IntegralAP and Floating types usi… (#144676)
…ng an allocator (#144246)"

This reverts commit 57828fec760f086b334ce0cb1c465fc559dcaea4.
2025-06-18 14:37:29 +02:00
Timm Bäder
57828fec76 Revert "[clang][bytecode] Allocate IntegralAP and Floating types using an allocator (#144246)"
This reverts commit c66be289901b3f035187d391e80e3610d7d6232e.

This breaks the armv8-quick builder:
https://lab.llvm.org/buildbot/#/builders/154/builds/17549
2025-06-17 21:08:23 +02:00
Timm Baeder
c66be28990
[clang][bytecode] Allocate IntegralAP and Floating types using an allocator (#144246)
Both `APInt` and `APFloat` will heap-allocate memory themselves using
the system allocator when the size of their data exceeds 64 bits.

This is why clang has `APNumericStorage`, which allocates its memory
using an allocator (via `ASTContext`) instead. Calling `getValue()` on
an ast node like that will then create a new `APInt`/`APFloat` , which
will copy the data (in the `APFloat` case, we even copy it twice).
That's sad but whatever.

In the bytecode interpreter, we have a similar problem. Large integers
and floating-point values are placement-new allocated into the
`InterpStack` (or into the bytecode, which is a `vector<std::byte>`).
When we then later interrupt interpretation, we don't run the destructor
for all items on the stack, which means we leak the memory the
`APInt`/`APFloat` (which backs the `IntegralAP`/`Floating` the
interpreter uses).

Fix this by using an approach similar to the one used in the AST. Add an
allocator to `InterpState`, which is used for temporaries and local
values. Those values will be freed at the end of interpretation. For
global variables, we need to promote the values to global lifetime,
which we do via `InitGlobal` and `FinishInitGlobal` ops.

Interestingly, this results in a slight _improvement_ in compile times:
https://llvm-compile-time-tracker.com/compare.php?from=6bfcdda9b1ddf0900f82f7e30cb5e3253a791d50&to=88d1d899127b408f0fb0f385c2c58e6283195049&stat=instructions:u
(but don't ask me why).

Fixes https://github.com/llvm/llvm-project/issues/139012
2025-06-17 18:31:06 +02:00
Timm Baeder
c75acb6f8b
[clang][bytecode] Remove some unused code (#142580)
Remove unused functions and add tests for fixed-point to bool casts,
which work.
2025-06-03 14:45:47 +02:00
Timm Baeder
294643e4bd
[clang][bytecode] Check lifetime of all ptr bases in placement-new (#141272)
placement-new'ing an object with a dead base object is not allowed, so
we need to check all the pointer bases.
2025-05-24 14:17:26 +02:00
Timm Baeder
d01355645b
[clang][bytecode] Check downcasts for the correct type (#140689)
In multiple inheritance/diamond scenarios, we might arrive at the wrong
type.
2025-05-20 11:19:24 +02:00
Timm Baeder
e5f8998ac8
[clang][bytecode] Explicitly start variable lifetimes via placement new (#140221)
placement new /std::construct{,_at} can resurrect a variable after it's
destructor has been called.
2025-05-16 12:48:22 +02:00
Timm Baeder
15579a8e72
[clang][bytecode] Check array sizes against step limit (#137679) 2025-04-29 05:47:22 +02:00
Timm Baeder
959905a5ad
[clang][bytecode] Don't create Function instances for builtins (#137618)
Now that we don't use them anymore in InterpBuiltin.cpp and we don't
create frames for them anymore anyway, just don't create Function
instances.
2025-04-28 14:08:42 +02:00
Timm Baeder
d775b911c9
[clang][bytecode] Diagnose pseudo dtor calls before C++20 (#137303) 2025-04-25 13:03:58 +02:00
Timm Baeder
90ddb54440
[clang][bytecode] Enter a non-constant context when revisiting (#136104)
Otherwise, things like __builtin_is_constant_evaluated() return the
wrong value.
2025-04-17 12:50:28 +02:00
Timm Baeder
2d63faead4
[clang][bytecode][NFC] Remove PT_FnPtr (#135947)
We don't need this anymore since we don't return it from classify()
anymore.
2025-04-16 13:21:25 +02:00
Timm Baeder
db7475a770
[clang][bytecode] Ignore overflow in unary operators if requested (#132557)
Add PreInc and PreDec ops for this purpose and ignore the overflow if
UnaryOperator::canOverflow() returns false.
2025-03-22 18:03:50 +01:00
Timm Baeder
ca1bde0b91
[clang][bytecode] Check dtor instance pointers for active-ness (#128732)
And diagnose if we're trying to destroy an inactive member of a union.
2025-03-17 19:01:35 +01:00
Timm Baeder
d08cf7900d
[clang][bytecode] Implement __builtin_constant_p (#130143)
Use the regular code paths for interpreting.

Add new instructions: `StartSpeculation` will reset the diagnostics
pointers to `nullptr`, which will keep us from reporting any diagnostics
during speculation. `EndSpeculation` will undo this.

The rest depends on what `Emitter` we use.

For `EvalEmitter`, we have no bytecode, so we implement `speculate()` by
simply visiting the first argument of `__builtin_constant_p`. If the
evaluation fails, we push a `0` on the stack, otherwise a `1`.

For `ByteCodeEmitter`, add another instrucion called `BCP`, that
interprets all the instructions following it until the next
`EndSpeculation` instruction. If any of those instructions fails, we
jump to the `EndLabel`, which brings us right before the
`EndSpeculation`. We then push the result on the stack.
2025-03-08 06:06:14 +01:00
Timm Baeder
5fbb6d919d
[clang][bytecode] Allow up/down casts of nullptr (#127615)
If the target type is a pointer type.
2025-02-18 14:43:35 +01:00
Timm Baeder
ee25a85ccc
[clang][bytecode] Handle CXXPseudoDestructorExprs (#125835)
Make lifetime management more explicit. We're only using this for
CXXPseudoDestructorExprs for now but we need this to handle
std::construct_at/placement-new after destructor calls later anyway.
2025-02-05 12:40:30 +01:00
Timm Baeder
e86b68ff56
[clang][bytecode] Add support for typeid pointers (#121251)
Add it as another kind of pointer, saving both a `Type*` for the result
of the typeid() expression as well as one for the type of the typeid
expression.
2024-12-28 14:07:01 +01:00
Timm Baeder
56fd46edb3
[clang][bytecode] Remove a bitcast nullptr_t special case (#120188)
We still need to check the input pointer, so let this go through
BitCastPrim.
2024-12-17 13:23:14 +01:00
Timm Baeder
44be794658
[clang][bytecode] Not all null pointers are 0 (#118601)
Get the Value from the ASTContext instead.
2024-12-05 06:03:50 +01:00
Timm Baeder
2588b8be56
[clang][bytecode] Implement bitcasts to composite types (#114776)
Only fixed-size, non-bitfield integral fields for now.
2024-11-04 15:10:10 +01:00
Timm Baeder
ef2a104c94
[clang][bytecode] Start implementing __builtin_bit_cast (#112126)
This is a subset of #68288, with hopefully narrower scope. It does not
support bitcasting to non-integral types yet.
Bitfields are supported, but only if they result in a full byte-sized
final buffer. It does not support casting from null-pointers yet or
casting from indeterminate bits.


The tests are from #68288 and partially from #74775.

The `BitcastBuffer` struct is currently always working in single bits,
but I plan to (try to) optimize this for the common full-byte case.
2024-10-31 18:09:40 +01:00
Timm Baeder
159f253017
[clang][bytecode] Diagnose invalid declrefs differently if we've... (#113140)
... tried their initializer already. In that case, diagnose the
non-const initializer instead of the reference to a non-constexpr
variable later. This is used in a lot of openmp tests.
2024-10-21 12:07:09 +02:00
Timm Baeder
3eaf4a9d1a
[clang][bytecode] Check for memory leaks after destroying global scope (#112868)
The global scope we create when evaluating expressions might free some
of the dynamic memory allocations, so we can't check for memory leaks
before destroying it.
2024-10-18 13:03:13 +02:00
Timm Baeder
f93258e4ac
[clang][bytecode] Diagnose class-specific operator delete calls (#111700) 2024-10-10 08:40:14 +02:00
Timm Baeder
fed8695bb8
[clang][bytecode] Emit better diagnostic for invalid shufflevector index (#111643) 2024-10-09 09:56:37 +02:00
Timm Baeder
6f04e65c3c
[clang][bytecode] Implement fixed-point shifts (#110429) 2024-09-29 20:56:17 +02:00
Timm Baeder
5c811ccc4d
[clang][bytecode] Implement more binary operators for fixed point types (#110423) 2024-09-29 17:36:17 +02:00
Timm Baeder
95ce78b742
[clang][bytecode] Implement fixed-point-to-int casts (#110417)
And some cleanups around overflow handling.
2024-09-29 13:31:44 +02:00
Timm Baeder
c2a37e41b9
[clang][bytecode] Implement fixed point casts (#110409) 2024-09-29 08:58:21 +02:00
Timm Baeder
defead4d2d
[clang][bytecode] Implement fixed-point add (#110405) 2024-09-29 07:13:17 +02:00