llvm / llvm/llvm-project

[Clang] Confusing diagnostic about implicit use of `this` involving immediate-escalating function

Open
#171,074 0 comments 2 reactions 0 assignees View on GitHub
clang:diagnostics
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

Consider (https://godbolt.org/z/e1qnxsMeY):
```c++
struct S {
int value = 42;
void f(auto visitor) {
visitor(value);
}
};

void not_constexpr();
consteval void g(bool b) {
if (b) not_constexpr();
}

void f() {
S s;
s.f([](int value) { g(true); });
}
```
For this, we emit the following diagnostics:
```console
:4:9: error: call to immediate function 'f()::(anonymous class)::operator()' is not a constant expression
4 | visitor(value);
| ^
:15:7: note: in instantiation of function template specialization 'S::f<(lambda at :15:9)>' requested here
15 | s.f([](int value) { g(true); });
| ^
:4:17: note: implicit use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function
4 | visitor(value);
|
```

The wording ‘implicit use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function’ (which is `note_constexpr_this` in DiagnosticASTKinds.ts) is... not great. What this is probably trying to say is that `this` is not a constant expression here (this diagnostic is emitted if we can’t find a `this` pointer in the evaluation stack during constant evaluation), but it doesn’t exactly communicate that—and the wording is outright wrong in that it implies that implicit `this` requires a function to be `constexpr`, which is just not the case.

There’s also something else that confuses me here: Removing the call to `not_constexpr()` in `g()` (or just passing `false` to `g()`) causes the evaluation to succeed (and we don’t even complain about `this`; instead we compile the program just fine), and GCC does the same (in fact, GCC also complains about `*(S*)this` not being a constant expression).

CC @cor3ntin Is this some weird consequence of how immediate escalation works? Because to me it really seems that we should be complaining about the call to `not_constexpr()`... not being `constexpr`, considering that we fail evaluation iff that call is reached.

For a more real-world example, if that call to `not_constexpr()` is instead a call to `std::format()`/`std::print()` with a missing format argument (e.g. https://godbolt.org/z/f47d9dfY3), then we never actually tell the user about that, and instead the only diagnostics you get are the ones seen above, which is rather poor QOI. I ran into this exact situation earlier, and it took me a while to figure out what the problem was.

Either way, I still think that `note_constexpr_this` needs to be reworded a bit.

Contributor guide

Open the contributing guide

Research direction

Reproduce the reduced C++ example from the issue and inspect the note_constexpr_this diagnostic in DiagnosticASTKinds.ts. Compare the diagnostics when not_constexpr() is reached versus when evaluation succeeds, then make the wording accurately describe the constant-evaluation failure and add or update coverage for the reported cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.