-
Notifications
You must be signed in to change notification settings - Fork 15.3k
Closed
Labels
clang:modulesC++20 modules and Clang Header ModulesC++20 modules and Clang Header Modules
Description
Summary
When a class template with an inline static data member is defined inside an anonymous namespace within a module interface unit, clang instantiates the specialization twice. As a result, the inline static data member is initialized twice at runtime, leading to duplicated side effects. MSVC does not exhibit this behavior.
Reproducer
main.cpp:
import demo;
int main() { }
demo.ixx:
module;
#include <iostream>
#include <string>
#include <typeindex>
#include <unordered_map>
export module demo;
class Registry {
public:
static Registry& instance() {
static Registry instance;
return instance;
}
template<class Derived> void register_type() {
const std::string type_name = typeid(Derived).name();
if (auto it = m_type_to_typeindex.find(type_name); it != m_type_to_typeindex.end()) {
std::cout << "Trying to re-register class: " << typeid(Derived).name()
<< " (prev: " << it->second
<< ", new: " << std::type_index(typeid(Derived)).hash_code()
<< ")" << std::endl;
return;
}
m_type_to_typeindex[type_name] = std::type_index(typeid(Derived)).hash_code();
}
private:
std::unordered_map<std::string, size_t> m_type_to_typeindex;
};
template<class Derived>
class Registrable {
protected:
Registrable() { (void)registered; }
private:
static void _register() {
Registry::instance().template register_type<Derived>();
}
inline static bool registered = (_register(), true);
};
namespace {
class MyClass : public Registrable<MyClass> {
public:
MyClass() : Registrable() {}
};
}
Steps to reproduce:
clang-cl:
clang++ -std=c++23 -x c++-module demo.ixx --precompile -o demo.pcmclang++ -std=c++23 -x c++-module -c demo.ixx -fmodule-file=demo=demo.pcm -o demo.oclang++ -std=c++23 -c Main.cpp -fmodule-file=demo=demo.pcm -o Main.oclang++ Main.o demo.o -o demo_app
clang:
clang++ -std=c++23 -x c++-module demo.ixx --precompile -o demo.pcmclang++ -std=c++23 -x c++-module -c demo.ixx -fmodule-file=demo=demo.pcm -o demo.oclang++ -std=c++23 -c Main.cpp -fmodule-file=demo=demo.pcm -o Main.oclang++ Main.o demo.o -o demo_app- Run demo_app and observe "Trying to re-register class..." is printed.
Observed behavior (clang-cl):
Registrable<MyClass>is instantiated twice.- Each instantiation has its own
inline static bool registered. - Both
registeredvariables are initialized at startup, so_register()runs twice, producing duplicate registration attempts inRegistry.
Expected behavior:
Its inline static member registered should be initialized once, and _register() should run only once.
Notes:
- Moving
MyClassout of the anonymous namespace prevents the problem. - Replacing the "module import" with a "header include" also prevents the problem.
Version:
clang version 20.1.8 and 21.1.0
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
Metadata
Metadata
Assignees
Labels
clang:modulesC++20 modules and Clang Header ModulesC++20 modules and Clang Header Modules