New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Intel C++ Problem with Polymorphic Registration #606
Comments
I have the same problem. Serialization via base pointer(std::unique_ptr in my case) appears broken. (same code work for GNU and CLANG). I appears that CEREAL_REGISTER_TYPE does not register the type. In my case the registration is done in the .cpp file. |
I got the same problem and looked a bit closer, and found that it is because of a bug (probably) of the Intel C++ compiler. Loger versionThe problem is that the constructor of InputBindingCreator/OutputBindingCreator is not called during the initialization of global variables. Cereal uses those classes as a singleton (using StaticObject) and it expects they are initialized when the macro CEREAL_BIND_TO_ARCHIVE is used. The way Cereal uses it is rather implicit. The macro CEREAL_REGISTER_ARCHIVE defines a function the return type of which is polymorphic_serialization_support<Archive,T>::type, that makes CEREAL_BIND_TO_ARCHIVE instantiate polymorphic_serialization_support<Archive,T> for a user type T. As polymorphic_serialization_support<Archive,T> defines the method instantiate(), the instantiation process also expects this function is instantiated albeit not be called elsewhere. The Intel compiler also instantiates this function as expected (by using nm command on the final executable, we could find the name of such functions) thus no problem so far. It turned out the problem is inside of the instantiate(). Inside the method, it uses create_bindings<Archive, T> which also should be instantiated. In create_bindings<Archive, T> class, there are two methods save/load that obtains a reference of a singleton InputBindingCreator<Archive, T>. These methods are also never used but the instantiation is sufficient to call the creator of this class which actually registers archive. This is where the bug appears. The intel compiler does not call such a constructor. This bug is easily reproducible using the following code. It does not print anything when icc is used but gcc prints "Test construct" as expected. I also think this instantiation rule is what the standard guarantees (looks like p. 347 of n3337 says so). #include <iostream>
template<typename T>
struct StaticObject
{
static T& get()
{
static T t;
(void)instance;
return t;
}
static T& instance;
};
template<typename T>
T& StaticObject<T>::instance = StaticObject<T>::get();
struct Test
{
Test()
{
std::cout << "Test construct" << std::endl;
}
void doNothing()
{
}
};
template<typename T>
struct Instantiator
{
static void mustBeInstantiated() __attribute__((used))
{
StaticObject<T>::get().doNothing();
}
static void doSomething()
{
}
};
int main()
{
Instantiator<Test>::doSomething();
return 0;
} I will report this bug to the intel compiler team but ain't sure when they will fix it. |
Thanks for looking into this more deeply, @chaeyeunpark. But I wonder if the behaviour of your example is actually consistent with paragraph (6) on p. 347 of the linked standard: "If the overload resolution process can determine the correct function to call without instantiating a classtemplate definition, it is unspecified whether that instantiation actually takes place." What happens if you remove the So does the difference rely on behaviour of a gcc extension? Is there some other way to force-create the necessary instance, for the cereal application, that does not rely on attribute(used)? To be clear, I have not tried to understand the cereal implementation we're talking about, in detail -- I'm just looking at your minimal example. Thanks again. |
A recent Intel OneAPI compiler with clang backend solves the problem. |
We have been having some trouble with polymorphic types using ICC 19.0.3.199 20190206 (as installed at NERSC on Cori).
Trying to serialize a derived class by pointer-to-base results in an exception about an unregistered polymorphic type.
A very small test case can be found here:
https://github.com/mhasself/cereal_testing (ultra-minimal branch)
The error is "Trying to save an unregistered polymorphic type (MyClass1)", where MyClass1 is a derived type serialized by pointer to MyClass0, its parent. If serialized through a pointer to type MyClass1, everything works fine.
The text was updated successfully, but these errors were encountered: