CLANG 5.0.0 涉及虚函数的 coliru/godbolt 差异

clang 5.0.0 difference on coliru/godbolt involving virtual function

本文关键字:coliru godbolt 差异 CLANG 函数      更新时间:2023-10-16

我真的希望我错过了一些东西,但请考虑以下代码:

struct Base {
virtual void doit() = 0;
};
struct Derived : Base {
void doit_internal(int n);
void doit() {
doit_internal(3);
}
};
int main() {
Derived derived;
}

在 clang (5.0.0-3~16.04.1 (tags/RELEASE_500/final)( 上,我收到链接器错误 (undefined reference to Derived::doit_internal(int)'(。我想知道如果实际上根本没有调用doit_internal,为什么需要它。

此外,在 clang (version 5.0.0 (tags/RELEASE_500/final 334239)(,它可以很好地编译。

哪个叮当声是正确的?标准中是否有技术原因/平台特定的东西/某些东西要求doit_internal定义?

程序格式不正确,无需诊断。在定义doit时,你使用了 odrdoit_internal(你写了一个调用doit_internal的表达式(。您的程序可以优化到return 0;没有区别

该标准明确指出:

[basic.def.odr]

4 每个程序应只包含一个定义 该程序中使用的非内联函数或变量 在丢弃的语句之外;无需诊断。这 定义可以显式出现在程序中,可以在 标准或用户定义的库,或者(在适当时(它是 隐式定义(参见 [class.ctor]、[class.dtor] 和 [class.copy](。 每次翻译中都应定义内联函数或变量 在丢弃语句之外使用 ODR 的单位。

Clang完全有权拒绝它,或者不拒绝它。它甚至可以在版本之间更改其行为,因为您的程序违反了上述要求。

在这两种情况下,程序都可以正确编译。
但是coliru它在链接过程中失败,因为没有定义Derived::doit_internal(int)

Compiler Explorer不运行代码,它只显示为当前翻译单元定义的C++代码的汇编代码。所以它不必做链接。由于未执行链接阶段,因此不会发现问题,也不会报告错误。

doit_internal

是必需的,因为您的一个函数引用了它。虽然该函数本身未被引用,但它是应用程序的基础部分,因此链接器需要其依赖项。

如果启用优化,则 clang 会省略doit的实现,并且您的应用程序链接成功:http://coliru.stacked-crooked.com/a/8496f4e097d2f0ee

Godbolt只是一个编译器,它不链接或运行任何东西,这就是为什么它没有显示任何链接错误。请注意,它在程序集中仍然有call Derived::doit_internal(int),因此如果您采用此程序集并尝试链接它,则最终会出现相同的链接器错误。