https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102698
--- Comment #3 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Just one extra note: !$omp atomic capture x(idx(i), idy(i)) = ior(x(idx(i), idy(i)), fun(i)) o(idx(i), idy(i)) = x(idx(i), idy(i)) !$omp end atomic is really (under the hood): temp_expr = fun(i) !$omp atomic capture x(idx(i), idy(i)) = ior(x(idx(i), idy(i)), temp_expr) temp_v = x(idx(i), idy(i)) !$omp end atomic o(idx(i), idy(i)) = temp_v and if you write it that way, it is more obvious your program is racy. Even the x(idx(i), idy(i)) expression gets its address evaluated once before the construct (if it has some side-effects) and then it is just __atomic_or_fetch on that address.