AnA*_*ons 2 c++ llvm clang c++23
归结为:
#include <memory>
class dummy;
std::unique_ptr<dummy> test;
class dummy {
};
Run Code Online (Sandbox Code Playgroud)
当使用 clang++-14 和 c++2b 编译时:
它简要给出:
clang++ ../bugl.cpp -I /usr/lib/llvm-14/include -std=c++2b
In file included from ../bugl.cpp:1:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/memory:76:
/usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/unique_ptr.h:93:16: error: invalid application of 'sizeof' to an incomplete type 'dummy'
static_assert(sizeof(_Tp)>0,
^~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/unique_ptr.h:396:4: note: in instantiation of member function 'std::default_delete<dummy>::operator()' requested here
get_deleter()(std::move(__ptr));
^
../bugl.cpp:4:24: note: in instantiation of member function 'std::unique_ptr<dummy>::~unique_ptr' requested here
std::unique_ptr<dummy> test;
^
../bugl.cpp:2:7: note: forward declaration of 'dummy'
class dummy;
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)
但一旦我们删除 - 的定义,它就会变得有趣,dummy那么它在任何地方都会失败。
最初我是从 llvm-14 标头中找到的:
#include <memory>
#include <llvm/ADT/APFloat.h>
Run Code Online (Sandbox Code Playgroud)
将 llvm-14 和 libstdc++-12-dev 与 Ubuntu 22.04.1 LTS 中的 clang++-14 一起使用
编译:
clang++ -std=c++2b bugllvm.cpp
Run Code Online (Sandbox Code Playgroud)
使用-std=c++20它可以很好地编译(以及使用 g++ 的 20 和 2b)。
基本上有问题的行是这一行:
class DoubleAPFloat final : public APFloatBase {
// Note: this must be the first data member.
const fltSemantics *Semantics;
std::unique_ptr<APFloat[]> Floats;
Run Code Online (Sandbox Code Playgroud)
APFloat此时已声明但尚未定义:
class APFloat;
Run Code Online (Sandbox Code Playgroud)
我的问题是错误在哪里——编译器、标准库、标准本身?
也许是别的东西。
问题不在于std::unique_ptr作为会员使用。实际问题在operator=第 625 行的实现中的类定义中:
DoubleAPFloat &operator=(DoubleAPFloat &&RHS) {
if (this != &RHS) {
this->~DoubleAPFloat();
new (this) DoubleAPFloat(std::move(RHS));
}
return *this;
}
Run Code Online (Sandbox Code Playgroud)
DoubleAPFloat析构函数调用导致定义析构函数。std::unique_ptr<APFloat[]>这需要实例化 的析构函数。该析构函数的实例化需要 的实例化,而std::default_delete<APFloat[]>s的operator()实例化又要求APFloat完整。
函数模板特化的实例化有两个实例化点。第一个紧跟在需要它的命名空间范围声明之后(或者在需要它的模板实例化点),第二个位于翻译单元的末尾。如果选择其中一个而不是另一个会给程序带来不同的含义,则该程序格式错误,无需诊断。
APFloat稍后在头文件中定义,因此这适用于此处。std::default_delete<APFloat[]>::operator()在 的定义之后立即进行实例化(DoubleAPFloat其中 的析构函数的实例化std::unique_ptr有一个实例化点),但在翻译单元的末尾将是格式良好的。
<llvm/ADT/APFloat.h>所以这是一个编译器不必诊断的错误。
这同样适用于您减少的测试用例。的定义test需要定义析构函数,因为需要析构该变量。同样,隐式实例化可以紧接在变量定义之后或翻译单元的末尾放置。如果没有最后的定义dummy,两个实例化点都是错误的,因此现在需要编译器对其进行诊断。