[clang-tidy] Determining constexpr evaluation time

Hello all,

Is it possible to determine if a CallExpr will be evaluated
at compile time from clang-tidy? I notice some references to
InConstantContext in the EvaluateAs* functions in ExprConstant.cpp,
but I'm not sure if that is applicable/usable from clang-tidy.

Connor Davis

There is Expr::isCXX11ConstantExpr(const ASTContext &C, …), which returns e.g.:

constexpr int f(int i) {
return i + 42;

int g(int i) {
f(i); // isCXX11ConstantExpr = false

int main() {
int j =
g(3); // isCXX11ConstantExpr = false

int k =
f(g(3)); // isCXX11ConstantExpr = false (both CallExprs)

int l =
f(3); // isCXX11ConstantExpr = true

It is defined in terms of EvaluateAsRValue FWIW. Note that all the EvaluateAs* methods refer to evaluating at compile time, regardless of the InConstantContext argument, and (I think) all will return false whenever the expression cannot fully “fold” (i.e. if there will necessarily be run-time dependencies remaining in the expression, or there was an error during evaluation).

Hope that helps,


Hi Dave,

That makes sense, however I'm looking for a way to determine if an actual
call instruction will be emitted. Using your example in godbolt (using x86-64
trunk with -std=c++17) there are four call instructions in main. But using
```constexpr int l = f(3);``` results in only three calls in main. And passing
-O2 removes all of them. Is there some way to statically determine that the
call instruction will be omitted?

For context, I have a patch for misc-no-recursion that does not warn when an
SCC is found in the call graph where each node is marked consteval, and I thought
that the "every node is constexpr but evaluated at compile time" is another case
where recursion would be OK. Although now that I type it out it's really "every
node is inlined".


‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐

I’m stumped — I am kind of surprised that `f(3)` is not always evaluated away before CodeGen, but even disregarding that, I am not sure how to determine which CallExprs are ultimately emitted as calls given the possibility of additional optimizations.

Does anyone else have insight?