Skip to content

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

@Sirraide

Description

@Sirraide

Consider (https://godbolt.org/z/e1qnxsMeY):

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:

<source>:4:9: error: call to immediate function 'f()::(anonymous class)::operator()' is not a constant expression
    4 |         visitor(value);
      |         ^
<source>:15:7: note: in instantiation of function template specialization 'S::f<(lambda at <source>:15:9)>' requested here
   15 |     s.f([](int value) { g(true); });
      |       ^
<source>: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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang:diagnosticsNew/improved warning or error message in Clang, but not in clang-tidy or static analyzer

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions