【问题标题】:OpenMP + clang sometimes fail with a variable declared from structured bindingOpenMP + clang 有时会因结构化绑定声明的变量而失败
【发布时间】: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++)。

两个问题:

  1. 为什么 clang 的行为如此奇怪?为什么它的解析器似乎依赖于外部,比如libgomp
  2. 除了重写代码之外,有没有办法在不完全禁用“错误:对封闭上下文中声明的本地绑定 '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。

标签: c++ clang c++17 openmp


【解决方案1】:

我无法回答为什么 clang 11.0.1 不喜欢这段代码,尽管可以在 Compiler Explorer 中看到效果 (https://godbolt.org/z/qTTcGf.

然而,你也可以看到为什么添加你认为可以使用libgomp 的反常标志会使代码编译。原因是该标志完全禁用了 OpenMP。您可以看到在 https://godbolt.org/z/o3TaGz 中没有调用 OpenMP 运行时例程。 我不知道为什么该标志没有被拒绝,因为要求 Clang 链接到 libgomp 绝对没有意义,因为 Clang 无法生成对 GCC OpenMP RTL 的调用(这些接口是不同的)。它也没有记录为合理的做法(请参阅 https://clang.llvm.org/docs/UsersManual.html#openmp-features ),它没有显示 -fopenmp 接受任何论点。

您还可以看到(https://godbolt.org/z/7hcdrr)主线 Clang 现在接受您的代码(不禁用 OpenMP)并生成包含对 OpenMP 运行时的调用的代码。

所以,总的来说

  1. Clang 11 有一个已在主线中修复的错误。
  2. 您将不受支持的参数传递给 clang,然后它会关闭 OpenMP 编译。

【讨论】:

    猜你喜欢
    • 2018-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多