从 clang c++20 模块导出全局变量

dja*_*abi 9 c++ clang c++20 c++-modules

当使用 clang 12 构建 c++20 模块时(它也使用 clang 10 重现)从模块导出全局变量并在另一个编译单元中从同一个导出类声明全局变量会导致“'vtable for foo'的多重定义” ”。

我的理解是,c++20 模块可以使用单个 cppm 源创建(clang 对模块使用 cppm),并且编译器将从它生成模块声明和定义。在这种情况下,clang++ 似乎确实生成了两次 vtable。

这是设置

foo.cppm:

export module foo;

export struct foo {
   virtual void vf();
};

void foo::vf() {}

export foo module_foo; // variable, exported
Run Code Online (Sandbox Code Playgroud)

主.cpp:

import foo;

foo main_foo;

int main() {
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

构建主可执行文件的编译步骤:

/usr/lib/llvm-12/bin/clang++ -std=c++20 -fmodules --precompile foo.cppm -o foo.pcm
/usr/lib/llvm-12/bin/clang++ -std=c++20 -fmodules --compile foo.cppm -o foo.o
/usr/lib/llvm-12/bin/clang++ -std=c++20 -fmodules -fmodule-file=foo.pcm --compile main.cpp -o main.o
/usr/lib/llvm-12/bin/clang++ -std=c++20 -fmodules foo.o main.o -o main
Run Code Online (Sandbox Code Playgroud)

导致 foo 类的重复 vtable 和类型信息:

/usr/bin/ld: main.o:(.rodata+0x20): multiple definition of `typeinfo for foo'; foo.o:(.rodata+0x20): first defined here
/usr/bin/ld: main.o:(.rodata+0x18): multiple definition of `typeinfo name for foo'; foo.o:(.rodata+0x18): first defined here
/usr/bin/ld: main.o:(.rodata+0x0): multiple definition of `vtable for foo'; foo.o:(.rodata+0x0): first defined here
Run Code Online (Sandbox Code Playgroud)

这是一个 llvm 错误还是我做错了什么,我对模块应该如何工作感到困惑?

小智 1

我可以使用 cmake 3.28 和 clang 17 重现这一点。

我发现如果您在类体内定义虚函数,则构建是固定的:

export struct foo {
   virtual void vf() { ... }
};
Run Code Online (Sandbox Code Playgroud)

非虚函数可以定义在主体下方,但是如果在外部定义任何虚函数,则会导致您发布的错误。不知道为什么,也许是某个地方的错误。