#include
#include
struct Interface {
virtual void f() = 0;
};
struct Impl1: Interface {
void f() override {
std::puts
If you move the ptr into the main function, the result is very telling and offers a strong hint as to why gcc doesn't want to de-virtualize the pointer.
The disassembly for this shows that if the 'has the static been initialized flag' is false, it initializes the static and then jumps right back to the virtual function call, even though nothing could possibly have happened to it in between.
This tells me that gcc is hard-wired to believe that any kind of globally persistent pointer must always be treated as a pointer to an unknown type.
In fact, it's even worse than this. If you add in a local variable, it matters whether the call to the f on the static pointer occurs between the creation of the local variable and the call to f or not. The assembly showing the f interposed case is here: Another godbolt link; and it is simple to re-arrange it yourself on the site to see how the assembly turns into an inline of f once the other call isn't interposed.
So, gcc must assume that the actual type a pointer refers to may change whenever control flow leaves the function for any reason. And whether or not it's declared const is irrelevant. Nor is it relevant if it's address is ever taken, or any number of other things.
clang does the same thing. This seems overly cautious to me, but I'm not a compiler writer.