静态不可达调用会导致未定义的引用错误吗?
Can statically unreachable calls cause undefined reference errors?
考虑以下代码,其中有一个无法到达的调用 undefinedFunction
。
void undefinedFunction();
template <bool b = false>
void foo()
{
static_assert(b == false);
if (b)
undefinedFunction();
}
int main()
{
foo();
}
GCC 毫无怨言地编译和链接它。使用 static_assert
,很难看出编译器如何做任何不同的事情,但是标准对此有什么要说的吗?如果删除 static_assert
会怎样?编译器是否完全有义务删除分支,或者它实际上可以发出无法访问的调用指令,这将导致链接器抱怨?
正如其他人评论的那样,两个独立的步骤促成了这一点。优化器可能会删除无法访问的代码,因此永远不会请求 undefinedFunction()
的 link。
编译步骤不关心 symbols that are not defined
(有关编译的更多信息在 this community answer)。
这独立于static_assert
。您可以在从未初始化的模板代码中使用未定义的引用,并且编译成功,因为编译器从不考虑代码,它从不发出 link.
的要求
如果符号通过,并在后面的某个步骤中被请求,linkage 将失败。这与使用模板 classes 编译库时发生的情况相同,然后尝试使用具有未显式初始化 class 的参数类型的模板,您将获得对类型的未定义引用使用自己编译良好的库。
如果您想检查编译器是否真的消除了死代码,this answer 有关在 GCC 中分析死代码的详细信息。
通常情况下,调用一个函数 odr-使用它,但有两个例外:如果它是纯虚拟的,或者如果它没有被潜在地评估 ([basic.def.odr]/5)。表达式可能被求值,除非它是未求值的操作数或其子表达式 ([basic.def.odr]/2)。未评估的操作数出现在 typeid
、sizeof
、noexcept
和 decltype
、none 中,其中适用于此处。因此,只要 foo
被实例化,就会使用 undefinedFunction
,事实就是如此。 "statically unreachable"码也不例外。
根据C++标准§3.2/p4一定义规则[basic.def.odr](强调我的):
Every program shall contain exactly one definition of every non-inline
function or variable that is odr-used in that program; no diagnostic
required. The definition can appear explicitly in the program, it can
be found in the standard or a user-defined library, or (when
appropriate) it is implicitly defined (see 12.1, 12.4 and 12.8). An
inline function shall be defined in every translation unit in which it
is odr-used.
模板函数 foo
已实例化 undefinedFunction
已被 ODR 使用(即需要 undefinedFunction
的定义)。 if
子句是否未被评估并不重要。因此,该程序格式错误,并且由于不需要诊断,它可能 link 也可能不会。
考虑以下代码,其中有一个无法到达的调用 undefinedFunction
。
void undefinedFunction();
template <bool b = false>
void foo()
{
static_assert(b == false);
if (b)
undefinedFunction();
}
int main()
{
foo();
}
GCC 毫无怨言地编译和链接它。使用 static_assert
,很难看出编译器如何做任何不同的事情,但是标准对此有什么要说的吗?如果删除 static_assert
会怎样?编译器是否完全有义务删除分支,或者它实际上可以发出无法访问的调用指令,这将导致链接器抱怨?
正如其他人评论的那样,两个独立的步骤促成了这一点。优化器可能会删除无法访问的代码,因此永远不会请求 undefinedFunction()
的 link。
编译步骤不关心 symbols that are not defined
(有关编译的更多信息在 this community answer)。
这独立于static_assert
。您可以在从未初始化的模板代码中使用未定义的引用,并且编译成功,因为编译器从不考虑代码,它从不发出 link.
如果符号通过,并在后面的某个步骤中被请求,linkage 将失败。这与使用模板 classes 编译库时发生的情况相同,然后尝试使用具有未显式初始化 class 的参数类型的模板,您将获得对类型的未定义引用使用自己编译良好的库。
如果您想检查编译器是否真的消除了死代码,this answer 有关在 GCC 中分析死代码的详细信息。
通常情况下,调用一个函数 odr-使用它,但有两个例外:如果它是纯虚拟的,或者如果它没有被潜在地评估 ([basic.def.odr]/5)。表达式可能被求值,除非它是未求值的操作数或其子表达式 ([basic.def.odr]/2)。未评估的操作数出现在 typeid
、sizeof
、noexcept
和 decltype
、none 中,其中适用于此处。因此,只要 foo
被实例化,就会使用 undefinedFunction
,事实就是如此。 "statically unreachable"码也不例外。
根据C++标准§3.2/p4一定义规则[basic.def.odr](强调我的):
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and 12.8). An inline function shall be defined in every translation unit in which it is odr-used.
模板函数 foo
已实例化 undefinedFunction
已被 ODR 使用(即需要 undefinedFunction
的定义)。 if
子句是否未被评估并不重要。因此,该程序格式错误,并且由于不需要诊断,它可能 link 也可能不会。