// { dg-do run } extern "C" void abort (); void dblinit (double *p) { *p = 2.0; } namespace NS { template struct U { void foo (U &, bool); U (); }; template struct S { int s; #pragma omp declare reduction (foo : U<0>, S : omp_out.foo (omp_in, false)) #pragma omp declare reduction (foo : int : omp_out += omp_in) \ initializer (omp_priv = N + 2) #pragma omp declare reduction (foo : double : omp_out += omp_in) \ initializer (dblinit (&omp_priv)) void baz (int v) { S s; int q = 0; if (s.s != 6 || v != 0) abort (); s.s = 20; double d = 4.0; #pragma omp parallel num_threads (4) reduction (foo : s, v, d) \ reduction (::NS::U::operator + : q) { if (s.s != 6 || q != 0 || v != N + 2 || d != 2.0) abort (); asm volatile ("" : "+m" (s.s), "+r" (q), "+r" (v)); s.s++; q++; v++; } if (s.s != 20 + q * 7 || (N + 3) * q != v || d != 4.0 + 2.0 * q) abort (); } void foo (S &x) { s += x.s; } void foo (S &x, bool y) { s += x.s; if (y) abort (); } S (const S &x) { s = x.s + 1; } S (const S &x, bool y) { s = x.s + 2; if (y) abort (); } S () { s = 6; } S (int x) { s = x; } ~S (); }; #pragma omp declare reduction (bar : S<1> : omp_out.foo (omp_in)) \ initializer (omp_priv (8)) } template NS::S::~S () { if (s < 6) abort (); s = -1; /* Ensure the above store is not DSEd. */ asm volatile ("" : : "r" (&s) : "memory"); } template struct T : public NS::S { void baz () { NS::S s; int q = 0; if (s.s != 6) abort (); #pragma omp parallel num_threads (4) reduction (foo:s) \ reduction (+: q) { if (s.s != 6 || q != 0) abort (); asm volatile ("" : "+m" (s.s), "+r" (q)); s.s += 2; q++; } if (s.s != 6 + q * 8) abort (); } }; struct W { int v; W () : v (6) {} ~W () {} }; template struct V { #pragma omp declare reduction (baz: T: omp_out.s += omp_in.s) \ initializer (omp_priv (11)) #pragma omp declare reduction (baz: D: omp_out += omp_in) \ initializer (dblinit (&omp_priv)) static void dblinit (D *x) { *x = 3.0; } void baz () { T t; V v; int q = 0; D d = 4.0; if (t.s != 6 || v.v != 4) abort (); #pragma omp declare reduction (+ : V, W : omp_out.v -= omp_in.v) \ initializer (omp_priv (12)) { #pragma omp declare reduction (+ : W, V : omp_out.v += omp_in.v) \ initializer (omp_priv (9)) #pragma omp parallel num_threads (4) reduction (+: v, q) \ reduction (baz: t, d) { if (t.s != 11 || v.v != 9 || q != 0 || d != 3.0) abort (); asm volatile ("" : "+m" (t.s), "+m" (v.v), "+r" (q)); t.s += 2; v.v += 3; q++; } if (t.s != 6 + 13 * q || v.v != 4 + 12 * q || d != 4.0 + 3.0 * q) abort (); } } int v; V () : v (4) {} V (int x) : v (x) {} ~V () {} }; int main () { NS::S<0> u; u.baz (0); T<2> t; t.baz (); NS::S<1> s; int q = 0; if (s.s != 6) abort (); // Test ADL #pragma omp parallel num_threads (4) reduction (bar:s) reduction (+:q) { if (s.s != 8 || q != 0) abort (); asm volatile ("" : "+m" (s.s), "+r" (q)); s.s += 4; q++; } if (s.s != 6 + q * 12) abort (); V , double> v; v.baz (); }