15 Commits

Author SHA1 Message Date
Serosh
60250aaa25
[clang][bytecode] Fix crash in void functions returning non-void expr… (#176550)
The bytecode compiler was incorrectly emitting an 
RVOPtr
opcode for void functions if the return expression had a non-void type
(e.g. from a conditional operator). This triggered an assertion in the
interpreter because void functions lack RVO metadata.

This patch updates 
visitReturnStmt
 to check the function’s return type and use 
discard()
 for the expression in void contexts, preventing erroneous RVO pathing.

Fixes #176536
2026-01-27 07:18:22 +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
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
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
8b091961b1
[clang][bytecode] Implement Pointer::getType() for function pointers (#154788)
Fixes #152920
2025-08-21 20:01:22 +02:00
Timm Baeder
373206d5e0
[clang][bytecode] Prefer ParmVarDecls as function parameters (#153952)
We might create a local temporary variable for a ParmVarDecl, in which
case a DeclRefExpr for that ParmVarDecl should _still_ result in us
choosing the parameter, not that local.
2025-08-16 17:22:14 +02:00
Timm Baeder
870aa979c4
[clang][bytecode] Use visitExpr() in interpretCall (#152857)
This is the correct function to use and it will create a variable scope.

Fixes #152822
2025-08-09 18:30:26 +02:00
Timm Baeder
8704ca0fb8
[clang][ExprConst] Consider integer pointers of value 0 nullptr (#150164)
When casting a 0 to a pointer type, the IsNullPtr flag was always set to
false, leading to weird results like a pointer with value 0 that isn't a
null pointer.

This caused

```c++
struct B { const int *p;};
template<B> void f() {}
template void f<B{nullptr}>();
template void f<B{fold(reinterpret_cast<int*>(0))}>();
```

to be valid code, since nullptr and (int*)0 aren't equal. This seems
weird and GCC doesn't behave like this.
2025-08-06 16:49:00 +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
Oleksandr T.
2e8e254d18
[Clang] include attribute scope in diagnostics (#144619)
This patch updates diagnostics to print fully qualified attribute names,
including scope when present.
2025-07-08 11:36:52 +03:00
Timm Baeder
bdbc434498
[clang][bytecode] Ignore function calls with depth > 0... (#129887)
... when checking for a potential constant expression. This is also what
the current interpreter does.
2025-03-05 16:21:03 +01:00
Timm Baeder
53d433e702
[clang][bytecode] Only emit literal_comparison for string literals (#129691)
This is what the current interpreter does as well.
2025-03-04 14:07:53 +01:00
Timm Baeder
fd6baa477f
[clang][ExprConst] Add diagnostics for invalid binary arithmetic (#118475)
... between unrelated declarations or literals.

Leaving this small (I haven't run the whole test suite locally) to get
some feedback on the wording and implementation first.

The output of the sample in
https://github.com/llvm/llvm-project/issues/117409 is now:
```console
./array.cpp:57:6: warning: expression result unused [-Wunused-value]
   57 |   am - aj.af();
      |   ~~ ^ ~~~~~~~
./array.cpp:70:8: error: call to consteval function 'L::L<bx>' is not a constant expression
   70 |   q(0, [] {
      |        ^
./array.cpp:57:6: note: arithmetic on addresses of literals has unspecified value
   57 |   am - aj.af();
      |      ^
./array.cpp:62:5: note: in call to 'al(&""[0], {&""[0]})'
   62 |     al(bp.af(), k);
      |     ^~~~~~~~~~~~~~
./array.cpp:70:8: note: in call to 'L<bx>({})'
   70 |   q(0, [] {
      |        ^~~~
   71 |     struct bx {
      |     ~~~~~~~~~~~
   72 |       constexpr operator ab<g<l<decltype(""[0])>::e>::e>() { return t(""); }
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   73 |     };
      |     ~~
   74 |     return bx();
      |     ~~~~~~~~~~~~
   75 |   }());
      |   ~~~
```

The output for 
```c++
int a, b;
constexpr int n = &b - &a
```

is now:
```console
./array.cpp:80:15: error: constexpr variable 'n' must be initialized by a constant expression
   80 | constexpr int n = &b - &a;
      |               ^   ~~~~~~~
./array.cpp:80:22: note: arithmetic involving '&b' and '&a' has unspecified value
   80 | constexpr int n = &b - &a;
      |                      ^
1 error generated.

```
2025-01-09 11:42:35 +01:00
Timm Baeder
056cd12284
[clang][bytecode] Don't check returned pointers for liveness (#120107)
We're supposed to let them through and then later diagnose reading from
them, but returning dead pointers is fine.
2024-12-17 06:20:14 +01:00
Timm Baeder
a07aba5d44
[clang] Rename all AST/Interp stuff to AST/ByteCode (#104552)
"Interp" clashes with the clang interpreter and people often confuse
this.
2024-08-16 17:13:12 +02:00