LLVM STLExtras 中的错误:预期 unqualified-id 在 'const' 之前与 GCC11
Error in LLVM STLExtras: expected unqualified-id before 'const' with GCC11
我刚刚将编译器升级到 GCC 11.1.0,但在尝试编译使用 LLVM 的程序时遇到了问题。
发生的错误如下:
In file included from /usr/include/llvm/IR/DebugInfo.h:19,
from /home/<redacted>/src/sword/format/llvm.hpp:12,
from /home/<redacted>/src/main.cpp:9:
/usr/include/llvm/ADT/STLExtras.h:1793:18: error: expected unqualified-id before ‘const’
1793 | result_pair<R>(const result_pair<R> &Other)
| ^~~~~
/usr/include/llvm/ADT/STLExtras.h:1793:18: error: expected ‘)’ before ‘const’
1793 | result_pair<R>(const result_pair<R> &Other)
| ~^~~~~
| )
/usr/include/llvm/ADT/STLExtras.h:1843:22: error: expected unqualified-id before ‘const’
1843 | enumerator_iter<R>(const enumerator_iter<R> &Other) : Result(Other.Result) {}
| ^~~~~
/usr/include/llvm/ADT/STLExtras.h:1843:22: error: expected ‘)’ before ‘const’
1843 | enumerator_iter<R>(const enumerator_iter<R> &Other) : Result(Other.Result) {}
| ~^~~~~
| )
我查看了源代码,但不确定 LLVM 的代码是 ill-formed,还是 GCC 的错误。
STLExtra.h中第1793行的错误与class的定义有关:
template <typename R> struct result_pair {
...
result_pair<R>(const result_pair<R> &Other)
: Index(Other.Index), Iter(Other.Iter) {}
...
};
通常,当我定义带有模板参数的class时,我不会将模板参数放在构造函数的声明中(即result_pair(...)
)。
事实上,当我将构造函数从 result_pair<R>(...)
修改为 result_pair(...)
时,我的程序编译得很好(对 enumerator_iter
也是如此)。
那么,是不是LLVM的代码错了,而GCC是对的呢?或者这是 GCC 回归?我对 C++ 标准的了解太有限,无法有效地 Google 检查这是否是已知错误...非常感谢任何帮助。
此外,我尝试使用 clang-11 编译我的程序,但它根本无法编译,因为 C++20 功能还不存在(具体来说,它在模板中的某处失败)。所以,我无法通过这种方式缩小罪魁祸首。
P.S。由于它在修改后编译得很好,我想我暂时只保留 header 修改。
您提到您使用的是 C++20。从 C++20 开始,这确实是一个错误:对构造函数使用 simple-template-ids 被认为容易出错且多余,因此被删除。参见 [diff.cpp17.class]/2。
如您所述,您可以使用注入的 class 名称来修复错误:
template <typename R>
struct result_pair {
// ...
result_pair(const result_pair &Other)
: Index(Other.Index), Iter(Other.Iter) {}
// ...
};
特别是,这可以防止在构造函数声明中意外使用错误的模板参数,这显然不应该编译。
根据 N. Shead 的回答,这里有一个补丁文件,可用于修复 LLVM 12.0.1 上的错误:
--- /usr/include/llvm/ADT/STLExtras.h.orig 2021-10-21 10:41:36.706064183 -0400
+++ /usr/include/llvm/ADT/STLExtras.h 2021-10-21 10:41:59.442775225 -0400
@@ -1820,9 +1820,9 @@
result_pair(std::size_t Index, IterOfRange<R> Iter)
: Index(Index), Iter(Iter) {}
- result_pair<R>(const result_pair<R> &Other)
+ result_pair(const result_pair &Other)
: Index(Other.Index), Iter(Other.Iter) {}
- result_pair<R> &operator=(const result_pair<R> &Other) {
+ result_pair &operator=(const result_pair &Other) {
Index = Other.Index;
Iter = Other.Iter;
return *this;
@@ -1856,22 +1856,22 @@
result_type &operator*() { return Result; }
const result_type &operator*() const { return Result; }
- enumerator_iter<R> &operator++() {
+ enumerator_iter &operator++() {
assert(Result.Index != std::numeric_limits<size_t>::max());
++Result.Iter;
++Result.Index;
return *this;
}
- bool operator==(const enumerator_iter<R> &RHS) const {
+ bool operator==(const enumerator_iter &RHS) const {
// Don't compare indices here, only iterators. It's possible for an end
// iterator to have different indices depending on whether it was created
// by calling std::end() versus incrementing a valid iterator.
return Result.Iter == RHS.Result.Iter;
}
- enumerator_iter<R>(const enumerator_iter<R> &Other) : Result(Other.Result) {}
- enumerator_iter<R> &operator=(const enumerator_iter<R> &Other) {
+ enumerator_iter(const enumerator_iter &Other) : Result(Other.Result) {}
+ enumerator_iter &operator=(const enumerator_iter &Other) {
Result = Other.Result;
return *this;
}
将以上内容保存到 ~/STLExtras.h.patch
然后通过以下方式应用补丁:
$ sudo patch --backup /usr/include/llvm/ADT/STLExtras.h ~/STLExtras.h.patch
patching file /usr/include/llvm/ADT/STLExtras.h
原件将保存到 /usr/include/llvm/ADT/STLExtras.h.orig
,您可以保留或删除。
我刚刚将编译器升级到 GCC 11.1.0,但在尝试编译使用 LLVM 的程序时遇到了问题。
发生的错误如下:
In file included from /usr/include/llvm/IR/DebugInfo.h:19,
from /home/<redacted>/src/sword/format/llvm.hpp:12,
from /home/<redacted>/src/main.cpp:9:
/usr/include/llvm/ADT/STLExtras.h:1793:18: error: expected unqualified-id before ‘const’
1793 | result_pair<R>(const result_pair<R> &Other)
| ^~~~~
/usr/include/llvm/ADT/STLExtras.h:1793:18: error: expected ‘)’ before ‘const’
1793 | result_pair<R>(const result_pair<R> &Other)
| ~^~~~~
| )
/usr/include/llvm/ADT/STLExtras.h:1843:22: error: expected unqualified-id before ‘const’
1843 | enumerator_iter<R>(const enumerator_iter<R> &Other) : Result(Other.Result) {}
| ^~~~~
/usr/include/llvm/ADT/STLExtras.h:1843:22: error: expected ‘)’ before ‘const’
1843 | enumerator_iter<R>(const enumerator_iter<R> &Other) : Result(Other.Result) {}
| ~^~~~~
| )
我查看了源代码,但不确定 LLVM 的代码是 ill-formed,还是 GCC 的错误。
STLExtra.h中第1793行的错误与class的定义有关:
template <typename R> struct result_pair {
...
result_pair<R>(const result_pair<R> &Other)
: Index(Other.Index), Iter(Other.Iter) {}
...
};
通常,当我定义带有模板参数的class时,我不会将模板参数放在构造函数的声明中(即result_pair(...)
)。
事实上,当我将构造函数从 result_pair<R>(...)
修改为 result_pair(...)
时,我的程序编译得很好(对 enumerator_iter
也是如此)。
那么,是不是LLVM的代码错了,而GCC是对的呢?或者这是 GCC 回归?我对 C++ 标准的了解太有限,无法有效地 Google 检查这是否是已知错误...非常感谢任何帮助。
此外,我尝试使用 clang-11 编译我的程序,但它根本无法编译,因为 C++20 功能还不存在(具体来说,它在模板中的某处失败)。所以,我无法通过这种方式缩小罪魁祸首。
P.S。由于它在修改后编译得很好,我想我暂时只保留 header 修改。
您提到您使用的是 C++20。从 C++20 开始,这确实是一个错误:对构造函数使用 simple-template-ids 被认为容易出错且多余,因此被删除。参见 [diff.cpp17.class]/2。
如您所述,您可以使用注入的 class 名称来修复错误:
template <typename R>
struct result_pair {
// ...
result_pair(const result_pair &Other)
: Index(Other.Index), Iter(Other.Iter) {}
// ...
};
特别是,这可以防止在构造函数声明中意外使用错误的模板参数,这显然不应该编译。
根据 N. Shead 的回答,这里有一个补丁文件,可用于修复 LLVM 12.0.1 上的错误:
--- /usr/include/llvm/ADT/STLExtras.h.orig 2021-10-21 10:41:36.706064183 -0400
+++ /usr/include/llvm/ADT/STLExtras.h 2021-10-21 10:41:59.442775225 -0400
@@ -1820,9 +1820,9 @@
result_pair(std::size_t Index, IterOfRange<R> Iter)
: Index(Index), Iter(Iter) {}
- result_pair<R>(const result_pair<R> &Other)
+ result_pair(const result_pair &Other)
: Index(Other.Index), Iter(Other.Iter) {}
- result_pair<R> &operator=(const result_pair<R> &Other) {
+ result_pair &operator=(const result_pair &Other) {
Index = Other.Index;
Iter = Other.Iter;
return *this;
@@ -1856,22 +1856,22 @@
result_type &operator*() { return Result; }
const result_type &operator*() const { return Result; }
- enumerator_iter<R> &operator++() {
+ enumerator_iter &operator++() {
assert(Result.Index != std::numeric_limits<size_t>::max());
++Result.Iter;
++Result.Index;
return *this;
}
- bool operator==(const enumerator_iter<R> &RHS) const {
+ bool operator==(const enumerator_iter &RHS) const {
// Don't compare indices here, only iterators. It's possible for an end
// iterator to have different indices depending on whether it was created
// by calling std::end() versus incrementing a valid iterator.
return Result.Iter == RHS.Result.Iter;
}
- enumerator_iter<R>(const enumerator_iter<R> &Other) : Result(Other.Result) {}
- enumerator_iter<R> &operator=(const enumerator_iter<R> &Other) {
+ enumerator_iter(const enumerator_iter &Other) : Result(Other.Result) {}
+ enumerator_iter &operator=(const enumerator_iter &Other) {
Result = Other.Result;
return *this;
}
将以上内容保存到 ~/STLExtras.h.patch
然后通过以下方式应用补丁:
$ sudo patch --backup /usr/include/llvm/ADT/STLExtras.h ~/STLExtras.h.patch
patching file /usr/include/llvm/ADT/STLExtras.h
原件将保存到 /usr/include/llvm/ADT/STLExtras.h.orig
,您可以保留或删除。