Things get complicated when a lambda that capture by reference is capturing things that are not on a single stack frame (or a stack frame at all). Then you have references to references. You could rely on the optimizer, but the capture has ABI implications.
Does ABI really matter when the lambda is always compiled in the same translation unit as the function from which variables are captured? Seems to me that compilers should be free to optimize the simple cases to a single stack frame reference while falling back to whatever for others.
Yes, it does. The lambda still needs to follow the C++ object model in case someone might use it like a regular C++ object. It's possible to change the ABI with escape analysis that proves you know all of the uses of the lambda to change the ABI, but a) that escape analysis is surprisingly easily defeated [1] and b) ABI-changing optimizations tend to be much more common in research papers than production compilers because getting them right on real code is a lot more difficult than it looks.
[1] The lambda function probably has the same linkage as the function the lambda is contained in, which likely isn't "the only copy of this function is in this TU" but rather "this function may appear in several TUs, but all of these copies are equivalent and you can pick whichever one you like as the actual body." Very different opportunities there!
Comments
Things get complicated when a lambda that capture by reference is capturing things that are not on a single stack frame (or a stack frame at all). Then you have references to references. You could rely on the optimizer, but the capture has ABI implications.
Does ABI really matter when the lambda is always compiled in the same translation unit as the function from which variables are captured? Seems to me that compilers should be free to optimize the simple cases to a single stack frame reference while falling back to whatever for others.
Yes, it does. The lambda still needs to follow the C++ object model in case someone might use it like a regular C++ object. It's possible to change the ABI with escape analysis that proves you know all of the uses of the lambda to change the ABI, but a) that escape analysis is surprisingly easily defeated [1] and b) ABI-changing optimizations tend to be much more common in research papers than production compilers because getting them right on real code is a lot more difficult than it looks.
[1] The lambda function probably has the same linkage as the function the lambda is contained in, which likely isn't "the only copy of this function is in this TU" but rather "this function may appear in several TUs, but all of these copies are equivalent and you can pick whichever one you like as the actual body." Very different opportunities there!