Windows上的Clang / LLVM 7和8多次初始化内联静态数据成员(同时使用link.exe和lld-link.exe)

时间:2018-06-22 07:01:58

标签: c++ clang c++17 llvm-clang

Windows上的

Clang / LLVM 7和8每TU一次初始化一个内联静态数据成员。据我了解C ++ 17,这是不正确的。

尽管可以在多个TU中定义一个内联变量,但编译器和/或链接器必须确保该变量在程序中仅存在一次,因此仅被初始化一次

以下小程序显示了Clang / LLVM的情况(已在具有LLVM编译器工具链扩展的Visual Studio 2017和2019 RC中测试):

// header.h

#include <iostream>

struct A
{
  A()      { std::cout << "ctor " << this << std::endl; }
  ~A()     { std::cout << "dtor " << this << std::endl; }
  void f() { std::cout << "f " << this << std::endl;  }
};

struct S
{
  inline static A a; // C++17 inline variable, thus also a definition 
};

// TU1.cpp

#include "header.h"

int main()
{
  S::a.f();
}

// TU2.cpp

#include "header.h"

// TU3.cpp

#include "header.h"

// TU4.cpp

#include "header.h"

该程序打印:

ctor 010D4020
ctor 010D4020
ctor 010D4020
ctor 010D4020
f 010D4020
dtor 010D4020
dtor 010D4020
dtor 010D4020
dtor 010D4020

这是A的唯一对象(实际上是每个TU一个)的四个初始化,而不是(C ++ 17要求的)完全一个。 >

程序应打印:

ctor 010D4020
f 010D4020
dtor 010D4020

顺便说一下,这就是MSVC的作用。

这是clang / LLVM中的错误,对吧?

2 个答案:

答案 0 :(得分:7)

inline关键字的主要特征是它以两种方式修改了ODR规则:

  1. 多个定义(有一些限制)为allowed
  2. 结果对象被“折叠”成single instance

      

    具有外部链接的内联函数或变量在所有翻译单元中应具有相同的地址。

C ++ 17中唯一的补充是它还将allowsstatic数据成员声明也定义为。就是这样。

static数据成员仍然具有相同的 linkage (在您的情况下为external),storage durationlifetime,并且对于所有实际情况用途就像全局定义的变量一样。 参见[class.static.data]/6

  

静态数据成员的初始化和销毁​​完全类似于非局部变量

从本质上讲,它应该与此相同:

struct A
{
  A()      { std::cout << "ctor "; }
  ~A()     { std::cout << "dtor "; }
};

A a; // in one of the TU's

extern A a; // in all other TU's

结论:

这是Clang中的错误。 static S::a必须初始化并销毁一次。

答案 1 :(得分:1)

This bug is fixed在基于SVN r361807的当前快照中。