Reputation: 2869
Here's a minimal, reproducible example:
#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;
}
}
Now, g++ (10.2.0) compiles clean
g++ 1.cpp -std=c++17 -fopenmp -pedantic
Replacing g++ with clang++ (11.0.0) results in:
> 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.
Now comes a real surprise. In my Linux (Manjaro) I need to link clang++ with libgomp
to use OpenMP,
clang++ 1.cpp -std=c++17 -fopenmp=libgomp -pedantic
and now the program compiles with no error, no warning.
I found it in a larger program written in QtCreator. The problem is that now QtCreator shows a red bullet to warn me against an error, but the program compiles without warning (g++).
Two questions:
libgomp
?See also (similar question, but with lambdas instead OpenMP): Lambda implicit capture fails with variable declared from structured binding
EDIT:
Full output of clang with -v
:
> 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.
EDIT 2: The error disappears if I comment out the critical section. Apparently clang 11's module controlling program names is a bit in conflict with a similar module that must be implemented for OpenMP (to decide which variables inside parallel regions are thread-local and which are shared).
Upvotes: 1
Views: 724
Reputation: 2869
I cannot answer why clang 11.0.1 does not like this code, though one can see the effect in Compiler Explorer (https://godbolt.org/z/qTTcGf.
However, one can also see there why adding the perverse flag which you think is enabling use of libgomp
makes the code compile. The reason is that that flag is disabling OpenMP completely. You can see that there are no calls to OpenMP runtime routines in https://godbolt.org/z/o3TaGz .
I have no idea why that flag is not rejected, since it makes absolutely no sense to ask Clang to link against libgomp, as Clang cannot generate the calls into the GCC OpenMP RTL (these interfaces are different). It is also not documented as a reasonable thing to do (see https://clang.llvm.org/docs/UsersManual.html#openmp-features ) which does not show -fopenmp
taking any argument.
You can also see (at https://godbolt.org/z/7hcdrr) that the mainline Clang now accepts your code (without disabling OpenMP) and generates code that includes calls into the OpenMP runtime.
So, overall
Upvotes: 3