具有包含对静态对象的引用的外部链接的内联函数定义

Inline function definition with external linkage containing reference to a static object

有约束条件6.7.4(p3):

An inline definition of a function with external linkage shall not contain a definition of a modifiable object with static or thread storage duration, and shall not contain a reference to an identifier with internal linkage.

考虑以下示例:

static const int i = 10;

void do_print(void);

inline void do_print(void){
    printf("%d/n", i); //Reference to an identifier with internal linkage
                       //constraint violation
}

DEMO

此处具有外部链接的函数的内联定义使用具有内部链接的标识符。所以根据 5.1.1.3(p1):

A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined.

我预计编译器会以某种方式报告违反此约束的情况(一些警告)。但是代码编译得很好,没有警告或产生其他一些消息。

问题是:为什么在违反上述约束的情况下没有产生诊断信息?

cppreference 有一段解释其背后的基本原理:

If a function is declared inline in some translation units, it does not need to be declared inline everywhere: at most one translation unit may also provide a regular, non-inline non-static function, or a function declared extern inline. This one translation unit is said to provide the external definition. One external definition must exist in the program if the name of the function with external linkage is used in an expression, see one definition rule.

If the external definition exists in the program, the address of the function is always the address of the external function, but when this address is used to make a function call, it's unspecified whether the inline definition (if present in the translation unit) or the external definition is called.

一条注释还说(强调我的):

The inline keyword was adopted from C++, but in C++, if a function is declared inline, it must be declared inline in every translation unit, and also every definition of an inline function must be exactly the same (in C, the definitions may be different, as long as the behavior of the program does not depend on the differences). On the other hand, C++ allows non-const function-local statics and all function-local statics from different definitions of an inline function are the same in C++ but distinct in C.

这意味着如果本地内联函数在一个翻译单元中使用 static const value,则可以在具有不同静态常量变量值的不同翻译单元中定义具有相同名称的非内联函数,导致显式UB,因为未指定编译器是否使用全局非内联版本的本地内联。

The question is: Why is no diagnostic message produced in case of the constraint violation above?

因为你的编译器在这方面non-conforming。

仅此而已。您已正确分析了标准的文本,并将其正确应用于所提供的代码。符合规范的实现必须发出关于 do_print 的内联实现对变量 i 的引用的诊断。因此,没有实现的是 non-conforming.

我注意到,在这一点上,一些编译器在默认情况下以这种一般方式 non-conforming 省略必需的诊断,同时提供用于打开这些强制诊断的选项。例如,这是 GCC 中 -pedantic 选项的功能。但是,我发现即使指定了 -pedantic,我的(有点过时的)GCC 版本也不会警告您的代码。