[clang] [Clang] Don't give up on an unsuccessful function instantiation (PR #126723)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 19 04:06:24 PST 2025
zyn0217 wrote:
@mizvekov
The nuance is right here, where we tackle local lambdas and member functions separately:
https://github.com/llvm/llvm-project/blob/404f94ac7d8c368fba8ad1f97512c26efd5ec965/clang/lib/Sema/SemaExpr.cpp#L18273-L18282
```cpp
template<typename F> constexpr int visit(F f) { return f(0); }
template <class T> int G(T t);
int main() { return visit([](auto s) -> int { return G(s); }); }
template <class T> int G(T t) {
return 0;
}
```
So basically, we perform the instantiation as follows.
- The lambda case:
1. We instantiate `visit` once we call it because it's constexpr, with a `LocalEagerInstantiationScope` (L1) and `GlobalEagerInstantiationScope` (G1)
2. G1 is disabled because it's called from `MarkFunctionReferenced()`
3. We need to instantiate the lambda expression
4. As the lambda expression is defined *locally*, we fall into the first branch so that the lambda expression is pushed into L1.
5. We try to instantiate anything inside L1 after the instantiation of `visit`, creating a `LocalEagerInstantiationScope` (L2) and `GlobalEagerInstantiationScope` (G2).
6. G2 is enabled because `InstantiateFunctionDefinition` called from `PerformPendingInstantiations` goes with `Recursive=true`
7. We meet `G(s)`, and it isn't constexpr, so we defer its instantiation and track it in `GlobalEagerInstantiationScope`, which is G2.
8. When we finished the lambda body, we try to instantiate `G` in `G2`, which fails because we don't have a definition at the moment.
9. We drop it forever because we assume we're at end of the TU (which isn't the case)
- The member function case
1. We instantiate `visit` with a `LocalEagerInstantiationScope` (L1) and `GlobalEagerInstantiationScope` (G1), with G1 being disabled.
2. We need to instantiate the member function `operator()`
3. As it is a non-local constexpr function, we instantiate it immediately from the second branch I referenced, which creates `LocalEagerInstantiationScope` (L2) and `GlobalEagerInstantiationScope` (G2)
4. G2 is disabled because `Recursive=false` which is called from `MarkFunctionReferenced()`
5. We return back until we reach the end of TU, where we see the body of G, and we instantiate it happily.
https://github.com/llvm/llvm-project/pull/126723
More information about the cfe-commits
mailing list