【发布时间】:2021-01-20 23:49:23
【问题描述】:
这是一个最小的、可重现的示例:
#include <tuple>
int main()
{
std::pair<int, int> pair {1, 2};
int sum = 0;
#pragma omp parallel for
for (int i = 1; i < 10; i++)
{
auto [a, b] = pair;
#pragma omp critical
sum += a + b;
}
}
现在,g++ (10.2.0) 编译干净
g++ 1.cpp -std=c++17 -fopenmp -pedantic
将 g++ 替换为 clang++ (11.0.0) 会导致:
> clang++ 1.cpp -std=c++17 -fopenmp -pedantic
1.cpp:12:14: error: reference to local binding 'a' declared in enclosing context
sum += a + b;
^
1.cpp:10:13: note: 'a' declared here
auto [a, b] = pair;
^
1.cpp:12:18: error: reference to local binding 'b' declared in enclosing context
sum += a + b;
^
1.cpp:10:16: note: 'b' declared here
auto [a, b] = pair;
^
2 errors generated.
现在来了一个真正的惊喜。在我的 Linux (Manjaro) 中,我需要将 clang++ 与 libgomp 链接以使用 OpenMP,
clang++ 1.cpp -std=c++17 -fopenmp=libgomp -pedantic
并且现在程序编译没有错误,没有警告。
我在一个用 QtCreator 编写的更大的程序中找到了它。问题是现在 QtCreator 显示一个红色项目符号来警告我出错,但程序编译时没有警告(g++)。
两个问题:
- 为什么 clang 的行为如此奇怪?为什么它的解析器似乎依赖于外部库,比如
libgomp? - 除了重写代码之外,有没有办法在不完全禁用“错误:对封闭上下文中声明的本地绑定 'XXX' 的引用”的情况下使 QtCreator 中的错误警告静音?
另请参阅(类似的问题,但使用 lambdas 而不是 OpenMP):Lambda implicit capture fails with variable declared from structured binding
编辑:
用-v完整输出clang:
> clang++ 1.cpp -fopenmp -std=c++17 -v -pedantic
clang version 11.0.0
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-pc-linux-gnu/10.2.0
Found candidate GCC installation: /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0
Found candidate GCC installation: /usr/lib64/gcc/x86_64-pc-linux-gnu/10.2.0
Selected GCC installation: /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Selected multilib: .;@m64
"/usr/bin/clang-11" -cc1 -triple x86_64-pc-linux-gnu -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name 1.cpp -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -v -resource-dir /usr/lib/clang/11.0.0 -internal-isystem /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0 -internal-isystem /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0/x86_64-pc-linux-gnu -internal-isystem /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -pedantic -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/zkoza/so -ferror-limit 19 -fopenmp -fopenmp-cuda-parallel-target-regions -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -fcolor-diagnostics -faddrsig -o /tmp/1-45b8f4.o -x c++ 1.cpp
clang -cc1 version 11.0.0 based upon LLVM 11.0.0 default target x86_64-pc-linux-gnu
ignoring nonexistent directory "/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0/x86_64-pc-linux-gnu
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0/backward
/usr/local/include
/usr/lib/clang/11.0.0/include
/usr/include
End of search list.
1.cpp:12:14: error: reference to local binding 'a' declared in enclosing context
sum += a + b;
^
1.cpp:10:13: note: 'a' declared here
auto [a, b] = pair;
^
1.cpp:12:18: error: reference to local binding 'b' declared in enclosing context
sum += a + b;
^
1.cpp:10:16: note: 'b' declared here
auto [a, b] = pair;
^
2 errors generated.
编辑 2: 如果我注释掉关键部分,错误就会消失。显然,clang 11 的模块控制程序名称与 OpenMP 必须实现的类似模块有点冲突(以决定并行区域内的哪些变量是线程本地的,哪些是共享的)。
【问题讨论】:
-
请在 clang++ 命令中添加 -v 以便我们可以看到实际运行的内容。目前尚不完全清楚你有哪个clang,因为当我尝试这个时(诚然使用主线clang,所以12.0但还没有:-))-fopenmp标志不接受参数......(并编译你的代码没有投诉)。
-
@JimCownie 我已经添加了 clang +
-v的输出 -
您是否还没有为重组变量的定义进行数据竞争,在您的最小。可重现的例子?
-
@M.A “数据竞赛”是什么意思?该程序无法使用
-fopenmp编译。 -
@zkoza 两个线程可以顺序覆盖变量a&b,然后按任意顺序,可以累加(相同的值)成sum。