First, just to avoid XY problem: this issue comes from https://github.com/cnjinhao/nana/issues/445#issuecomment-502080177. The library code should probably not do such thing (reliance on construction of unused global object) but the question is more about whether it's valid LTO behaviour rather than code quality issues.
Minimal code that showcases the same problem (untested, just to make example smaller):
// main.cpp
#include <lib/font.hpp>
int main()
{
lib::font f;
}
// lib/font.hpp
namespace lib
{
struct font
{
font();
int font_id;
};
}
// lib/font.cpp
#include <lib/font.hpp>
#include <lib/font_abstraction.hpp>
namespace lib
{
font::font()
{
font_id = get_default_font_id();
}
}
// lib/font_abstraction.hpp
namespace lib
{
int get_default_font_id();
void initialize_font();
}
// lib/font_abstraction.cpp
#include <lib/font_abstraction.hpp>
namespace lib
{
static int* default_font_id;
int get_default_font_id()
{
return *default_font_id;
}
void initialize_font()
{
default_font_id = new int(1);
}
}
// lib/platform_abstraction.hpp
namespace lib
{
struct platform_abstraction
{
platform_abstraction();
};
}
// lib/platform_abstraction.cpp
#include <lib/platform_abstraction.hpp>
#include <lib/font_abstraction.hpp>
namespace lib
{
platform_abstraction::platform_abstraction()
{
initialize_font();
}
static platform_abstraction object;
}
The construction of font object in main.cpp relies on the initialization of the pointer. The only thing that initializes the pointer is global object object but it's unsued - in the case of linked issue that object was removed by LTO. Is such optimization allowed? (See C++ draft 6.6.5.1.2)
Some notes:
- The library was build as a static library and linked with main file using
-flto -fno-fat-lto-objectsand dynamic C++ standard library. - This example can be build without compiling
lib/platform_abstraction.cppat all - in such scenario the pointer will not be initialized for sure.
VTT's answer gives a GCC answer, but the question is tagged language-lawyer.
The ISO C++ reason is that objects defined in a Translation must be initialized before the first call to a function defined in the same Translation Unit. That means
platform_abstraction::objectmust be initialized beforeplatform_abstraction::platform_abstraction()is called. As the linker correctly figured out, there are no otherplatform_abstractionobjects, soplatform_abstraction::platform_abstractionis never called, soobject's initialization can be postponed indefinitely. A conforming program cannot detect this.