172 Commits

Author SHA1 Message Date
Timm Baeder
1cf62af0ee
[clang][bytecode] Don't call InterpFrame::getThis() on the bottom frame (#180682)
This happens when we're in checkingPotentialConstantExpression() and we
try to evaluate a delete expression.
2026-02-10 08:43:25 +01:00
Timm Baeder
f71e321966
[clang][bytecode] Implement constexpr step limit (#176150)
This only calls `noteStep()` on jump opcodes, so this works for loops.
It does not prevent "hangs" when a function is just _very_ long (could
be interesting how this interfaces with expand statements?).

Fixes https://github.com/llvm/llvm-project/issues/165951
2026-02-09 12:22:48 +01:00
Timm Baeder
43358cb3d6
[clang][bytecode] Check pointer lifetime in CheckDestructor (#179957)
So we diagnose double-destroy scenarios.
2026-02-06 07:06:18 +01:00
Timm Baeder
afb2e4f2e2
[clang][bytecode] Clean up interp::Function parameter handling (#178621)
Replace the multiple data structures with a vector + a map holding all
`ParamDescriptor`s. Update docs.
2026-01-30 10:07:23 +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
7f39d92d56
[clang][bytecode][NFC] Move some opcode impls to the source file (#177543)
They aren't templated, so move them to Interp.cpp to make the header
file a bit shorter.
2026-01-23 11:10:48 +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
ab366170db
[clang][bytecode] Add lifetime information for primitive array elements (#173333)
Double the allocated size of the `InitMap` and use the second half for
lifetime information.
2026-01-21 09:41:35 +01:00
Timm Baeder
a15adf5b9b
[clang][bytecode][NFC] Add Pointer::stripBaseCasts() helper (#176875)
We do this is in a few places, so add a helper function for it.
2026-01-20 11:21:22 +01:00
Timm Baeder
7d5fe7e194
[clang][bytecode] Reject all function calls in C (#175920)
C doesn't have constexpr functions, so this can't ever work anyway.

Fixes https://github.com/llvm/llvm-project/issues/175877
2026-01-14 14:20:59 +01:00
Timm Baeder
ef44d25971
[clang][ExprConst] Diagnose out-of-lifetime access consistently (#175562)
Previously, we had two very similar diagnostics, "read of object outside
its lifetime" and "read of variable whose lifetime has ended".
The difference, as far as I can tell, is that the latter was used when
the variable was created in a function frame that has since vanished,
i.e. in this case:
```c++
constexpr const int& return_local() { return 5; }
static_assert(return_local() == 5);
```
so the output used to be:
```console
array.cpp:602:15: error: static assertion expression is not an integral constant expression
  602 | static_assert(return_local() == 5);
      |               ^~~~~~~~~~~~~~~~~~~
array.cpp:602:15: note: read of temporary whose lifetime has ended
array.cpp:601:46: note: temporary created here
  601 | constexpr const int& return_local() { return 5; }
      |                                              ^
```

But then this scenario gets the other diagnostic:
```c++
constexpr int b = b;
```
```console
array.cpp:603:15: error: constexpr variable 'b' must be initialized by a constant expression
  603 | constexpr int b = b;
      |               ^   ~
array.cpp:603:19: note: read of object outside its lifetime is not allowed in a constant expression
  603 | constexpr int b = b;
      |                   ^
```

With this patch, we diagnose both cases similarly:
```c++
constexpr const int& return_local() { return 5; }
static_assert(return_local() == 5);
constexpr int b = b;
```
```console
array.cpp:602:15: error: static assertion expression is not an integral constant expression
  602 | static_assert(return_local() == 5);
      |               ^~~~~~~~~~~~~~~~~~~
array.cpp:602:15: note: read of object outside its lifetime is not allowed in a constant expression
  602 | static_assert(return_local() == 5);
      |               ^~~~~~~~~~~~~~
array.cpp:601:46: note: temporary created here
  601 | constexpr const int& return_local() { return 5; }
      |                                              ^
array.cpp:603:15: error: constexpr variable 'b' must be initialized by a constant expression
  603 | constexpr int b = b;
      |               ^   ~
array.cpp:603:19: note: read of object outside its lifetime is not allowed in a constant expression
  603 | constexpr int b = b;
      |                   ^
```

We do lose the "object" vs. "temporary" distinction in the note and only
mention it in the "created here" note. That can be added back if it's
important enough. I wasn't sure.
2026-01-14 08:59:28 +01:00
Timm Baeder
f0982d5d44
[clang][bytecode] Fix calling lambdas with broken instance pointers (#175511)
Clang will make the instance pointer be of type 'int' if it is invalid,
which trips up later logic. Mark functions as invalid if any of their
parameters is and compile + check them early in CallPtr.

Fixes https://github.com/llvm/llvm-project/issues/175425
2026-01-12 12:34:22 +01:00
Timm Baeder
bf017614ae
[clang][bytecode] Limit "... variable whose value is not known" diags (#175287)
To variables with reference types.
2026-01-10 15:40:48 +01:00
Timm Baeder
eec258dcf3
[clang][bytecode] Diagnose unknown reference params pre-C++23 (#175013)
Otherwise, we will ultimately create dummy pointers for them and
possibly not diagnose anything.
2026-01-09 08:11:17 +01:00
Timm Baeder
4da37d3295
[clang][bytecode] Check for non-trivial default ctors in unions (#174745)
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.
2026-01-08 06:07:12 +01:00
Timm Baeder
cf8d4d4069
[clang][bytecode] Fix a crash in CheckExtern() (#174428)
Check if the pointer field descriptor can be accessed at all before
calling `isInitialized()`, which relies on that.

Fixes https://github.com/llvm/llvm-project/issues/174382
2026-01-06 07:49:32 +01:00
Timm Baeder
354f412d32
[clang][bytecode] Allow operations on volatile objects in ctors (#174425) 2026-01-06 06:43:13 +01:00
Timm Baeder
db557bee1e
[clang][bytecode][NFC] Add Block::getBlockDesc<T>() (#172218)
Which returns the block-level descriptor. This way we don't have to do
the reinterpret_cast dance everywhere.
2025-12-15 09:21:41 +01:00
Timm Bäder
773a6a9cc8 Revert "[clang][bytecode] Allocate InitMaps via Program/InterpState allocators (#170272)"
This reverts commit 8fe38c4c9c71c7a86ecdba476ee5bae4c02c0dfe.

This breaks the clang-armv7-2stage build bot:
https://lab.llvm.org/buildbot/#/builders/79/builds/2531
2025-12-09 06:19:09 +01:00
Timm Baeder
8fe38c4c9c
[clang][bytecode] Allocate InitMaps via Program/InterpState allocators (#170272)
Save them as a pointer intead of using a shared_ptr. This we we can use
the pointer integer value to differentiate the "no initmap yet" and "all
values initialzed" cases.

This regresses one test case in const-eval.c, but as it turns out, that
only worked coincidentally before.
2025-12-06 06:37:45 +01:00
Timm Baeder
bd95a74a2c
[clang][bytecode] Check for invalid record decls in IntPointer::atOffset (#169786)
We can't access the RecordLayout of an invalid decl, so return failure
if that happens.

Fixes https://github.com/llvm/llvm-project/issues/167076
2025-11-27 13:06:15 +01:00
Timm Baeder
6696e0c8f8
[clang][bytecode] Remove double diagnostic emission (#169658)
We emit this diagnostic from CheckPointerToIntegralCast() already, so
remove the emission from CastPointerIntegral().
2025-11-27 07:15:23 +01:00
Timm Baeder
3841e7d818
[clang][bytecode] Don't call getThis() on the bottom function frame (#169044)
We can't access the calling frame in that case.

Fixes https://github.com/llvm/llvm-project/issues/169032
2025-11-22 05:18:18 +00:00
Timm Baeder
90e1391d18
[clang][bytecode] Check pointers in GetPtrField{,Pop} (#167335)
The pointer needs to point to a record.

Fixes https://github.com/llvm/llvm-project/issues/166371
2025-11-17 08:24:44 +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
f49cd170c0
[clang][bytecode] Check overrider for pure virtual (#165262)
Instead of checking the initial callee, check the callee after the
virtual dispatch. This means we need to check whether we're in a ctor to
not regress existing tests.

Fixes https://github.com/llvm/llvm-project/issues/165234
2025-10-28 08:35:48 +01:00
Timm Baeder
d7e40f3e71
[clang][bytecode] Call CheckStore() before activating pointers (#165235)
We used to do this the other way around to work around an awkwardness
with CheckStore, namely that we shouldn't check pointers for being
activated when activating them.

Add a parameter to CheckStore instead and call CheckStore() _before_
activating and initializing the pointers in the respective opcode
implementations.

Fixes https://github.com/llvm/llvm-project/issues/164975
2025-10-27 14:41:21 +01:00
Timm Baeder
f29235d698
[clang][bytecode] Don't diagnose defined functions that will have a body (#165002)
Don't use `hasBody()`, which checks all declarations.

Fixes https://github.com/llvm/llvm-project/issues/164995
2025-10-27 14:06:54 +01:00
Timm Baeder
bc37018a0b
[clang][bytecode] Fail on reads from constexpr-unknown pointers (#164996)
If they aren't const.

Fixes https://github.com/llvm/llvm-project/issues/164985
2025-10-27 09:38:23 +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
06cc20c10f
[clang][bytecode] Diagnose out-of-bounds enum values in .... (#163530)
... non-constexpr variable initializers.
2025-10-16 08:41:47 +02:00
marius doerner
5296d01738
[clang][bytecode] Assert on virtual func call from array elem (#158502)
Fixes #152893.

An assert was raised when a constexpr virtual function was called from
an constexpr array element with -fexperimental-new-constant-interpreter
set.
2025-10-06 15:08:38 +02:00
Timm Baeder
c750487292
[clang][bytecode] Diagnose volatile writes (#160350) 2025-09-28 07:21:40 +02:00
Timm Baeder
b98f0b8209
[clang][bytecode] Use stack offsets for This/RVO ptrs (#160285)
Instead of keeping the `Pointer`s itself in `InterpFrame`, just save
them as offsets and use stackRef<>() when we need them.
2025-09-24 10:30:51 +02:00
Timm Baeder
68c9ddb930
[clang][bytecode] Typecheck called function pointers more thorougly (#159757)
Fix two older FIXME items from the `functions.cpp` test.
2025-09-19 14:24:48 +02:00
Timm Baeder
fefe670be0
[clang][bytecode] Compile the definition, not the most recent decl (#158093) 2025-09-12 07:12:09 +02:00
Timm Baeder
21b99e1311
[clang][bytecode] Check reads for null block pointers (#157695)
All pointer types can be null, so check that independently from the
pointer type.

Fixes #157650
2025-09-11 06:35:28 +02:00
Timm Baeder
66e7168f5e
[clang][bytecode][NFC] Use an early return in CheckLoad (#157105)
If the block is not accessible, one of the check has to fail.
2025-09-05 15:56:10 +02:00
Timm Baeder
4931c3afc3
[clang][bytecode] Reject null pointers in CheckStore() (#156645)
In the attached test case, the global variable later only points to
gargbage, because the MaterializeTemporaryExpr used to initialize it is
a local variable, which is gone by the time we try to evaluate the
store.

Fixes #156223
2025-09-04 15:19:26 +02:00
Timm Baeder
0eebb8bbe5
[clang][bytecode][NFC] Check hasTrivialDtor() in RunDestructors (#155381)
We do this when calling Free() on dynamically allocated memory.
2025-08-26 13:03:17 +02:00
Timm Baeder
97b3cb2239
[clang][bytecode] Don't call getIndex() on one-past-end pointers (#155173)
That doesn't work.

Fixes #152903
2025-08-26 06:33:24 +02:00
Timm Baeder
e0acf6592b
[clang][bytecode] Call CheckFinalLoad in all language modes (#154496)
Fixes #153997
2025-08-21 08:24:09 +02:00
Timm Baeder
e16ced3ef4
[clang][bytecode] Diagnose one-past-end reads from global arrays (#154484)
Fixes #154312
2025-08-20 10:34:44 +02:00
Timm Baeder
8f0da9b8bd
[clang][bytecode] Disable EndLifetime op for array elements (#154119)
This breaks a ton of libc++ tests otherwise, since calling
std::destroy_at will currently end the lifetime of the entire array not
just the given element.

See https://github.com/llvm/llvm-project/issues/147528
2025-08-18 16:32:50 +02:00
Timm Baeder
b08e86cb7f
[clang][bytecode] Move CheckExtern call into isAccessible() block (#152926)
This is where it belongs, but it was accidentally left where it was.
2025-08-10 18:56:15 +02:00
Timm Baeder
7a6c9813d6
[clang][bytecode] Add AccessFlags to Block (#152590)
This way, we can check a single uint8_t for != 0 to know whether this
block is accessible or not. If not, we still need to figure out why not
and diagnose appropriately of course.
2025-08-09 15:46:28 +02:00
Matheus Izvekov
91cdd35008
[clang] Improve nested name specifier AST representation (#147835)
This is a major change on how we represent nested name qualifications in
the AST.

* The nested name specifier itself and how it's stored is changed. The
prefixes for types are handled within the type hierarchy, which makes
canonicalization for them super cheap, no memory allocation required.
Also translating a type into nested name specifier form becomes a no-op.
An identifier is stored as a DependentNameType. The nested name
specifier gains a lightweight handle class, to be used instead of
passing around pointers, which is similar to what is implemented for
TemplateName. There is still one free bit available, and this handle can
be used within a PointerUnion and PointerIntPair, which should keep
bit-packing aficionados happy.
* The ElaboratedType node is removed, all type nodes in which it could
previously apply to can now store the elaborated keyword and name
qualifier, tail allocating when present.
* TagTypes can now point to the exact declaration found when producing
these, as opposed to the previous situation of there only existing one
TagType per entity. This increases the amount of type sugar retained,
and can have several applications, for example in tracking module
ownership, and other tools which care about source file origins, such as
IWYU. These TagTypes are lazily allocated, in order to limit the
increase in AST size.

This patch offers a great performance benefit.

It greatly improves compilation time for
[stdexec](https://github.com/NVIDIA/stdexec). For one datapoint, for
`test_on2.cpp` in that project, which is the slowest compiling test,
this patch improves `-c` compilation time by about 7.2%, with the
`-fsyntax-only` improvement being at ~12%.

This has great results on compile-time-tracker as well:

![image](https://github.com/user-attachments/assets/700dce98-2cab-4aa8-97d1-b038c0bee831)

This patch also further enables other optimziations in the future, and
will reduce the performance impact of template specialization resugaring
when that lands.

It has some other miscelaneous drive-by fixes.

About the review: Yes the patch is huge, sorry about that. Part of the
reason is that I started by the nested name specifier part, before the
ElaboratedType part, but that had a huge performance downside, as
ElaboratedType is a big performance hog. I didn't have the steam to go
back and change the patch after the fact.

There is also a lot of internal API changes, and it made sense to remove
ElaboratedType in one go, versus removing it from one type at a time, as
that would present much more churn to the users. Also, the nested name
specifier having a different API avoids missing changes related to how
prefixes work now, which could make existing code compile but not work.

How to review: The important changes are all in
`clang/include/clang/AST` and `clang/lib/AST`, with also important
changes in `clang/lib/Sema/TreeTransform.h`.

The rest and bulk of the changes are mostly consequences of the changes
in API.

PS: TagType::getDecl is renamed to `getOriginalDecl` in this patch, just
for easier to rebasing. I plan to rename it back after this lands.

Fixes #136624
Fixes https://github.com/llvm/llvm-project/issues/43179
Fixes https://github.com/llvm/llvm-project/issues/68670
Fixes https://github.com/llvm/llvm-project/issues/92757
2025-08-09 05:06:53 -03:00
Timm Baeder
1b1f352cb9
[clang][bytecode] Handle reads on zero-size arrays (#152706) 2025-08-08 16:03:02 +02:00
Timm Baeder
193995d5a2
[clang][bytecode] Handle more invalid member pointer casts (#152546) 2025-08-07 19:24:01 +02:00
Timm Baeder
c869ef6ebc
[clang][bytecode] Refactor Check* functions (#152300)
... so we don't have to create Pointer instances when we don't need
them.
2025-08-07 11:32:39 +02:00