We’re hitting an issue on Fuchsia which seems to be the result of two problems in clang. The first one should be easy to reproduce. Simply build libcxx with the latest clang on/for any non-mac system. I had to use LIBCXX_ABI_VERSION=2 to make the symbol table show this symbol at all for some reason but the issue exists regardless. If you now run
readelf -Ws libc++.so.2 | grep _ZNSt3__213basic_ostreamIcNS_11char_traitsIcEEElsEPFRS3_S4_E you can see that
std::ostream::operator<<(std::ostream& (*)(std::ostream&)) is local/hidden. This appears to result from
-fvisibility-inlines-hidden being used and causing that operator to be marked as hidden. However, there is an extern explicit template instantiation at the bottom of (which is actually used on non-mac systems). So the compiler should be allowed to not inline the call if it so desires. However since libc++ does not provide a global definition of this symbol, the linker fails if the compiler chooses to do this.
The second issue is why the compiler is ever choosing to do this in the first place. This is harder to reproduce and I don’t have as much information on it. When you build Fuchsia in debug mode (-Og as the optimization level) it inlines the call to this operator in all translation units as we would expect from any sane compiler on any optimization level above -O0. However on non-debug builds (-O3 as the optimization level) it does not inline this call. This seems absurd however because one would think its just adding an extra call, passing more arguments, and increasing code size for no good reason. I’m not an optimization person though so I can only speculate. So -Og is somehow making a better inlining choice that -O3 it would appear. This issue just appears to be a regression in how well clang makes inlining decisions.
Does anyone more familiar with the compiler know where the code that handles this is? It’s currently blocking us from rolling a new toolchain on Fuchsia.