1202437Strasz// { dg-do run }
2202437Strasz
3202437Straszextern "C" void abort ();
4202437Strasz
5202437Strasznamespace NS
6202437Strasz{
7202437Strasz  struct U
8202437Strasz  {
9202437Strasz    void foo (U &, bool);
10202437Strasz    U ();
11202437Strasz  };
12202437Strasz  struct S
13202437Strasz  {
14202437Strasz    int s;
15202437Strasz    #pragma omp declare reduction (foo : U, S : omp_out.foo (omp_in, false))
16202437Strasz    #pragma omp declare reduction (foo : int : omp_out += omp_in) \
17202437Strasz	initializer (omp_priv = int ())
18202437Strasz    void baz (int v)
19202437Strasz    {
20202437Strasz      S s;
21202437Strasz      int q = 0;
22202437Strasz      if (s.s != 6 || v != 0) abort ();
23202437Strasz      s.s = 20;
24202437Strasz      #pragma omp parallel num_threads (4) reduction (foo : s, v) \
25202437Strasz	reduction (::NS::U::operator + : q)
26202437Strasz      {
27202437Strasz	if (s.s != 6 || q != 0 || v != 0) abort ();
28202437Strasz	asm volatile ("" : "+m" (s.s), "+r" (q), "+r" (v));
29202437Strasz	s.s++; q++; v++;
30202437Strasz      }
31202437Strasz      if (s.s != 20 + q * 7 || q != v) abort ();
32202437Strasz    }
33202437Strasz    void foo (S &x) { s += x.s; }
34202437Strasz    void foo (S &x, bool y) { s += x.s; if (y) abort (); }
35202437Strasz    S (const S &x) { s = x.s + 1; }
36202437Strasz    S (const S &x, bool y) { s = x.s + 2; if (y) abort (); }
37202437Strasz    S () { s = 6; }
38202437Strasz    S (int x) { s = x; }
39230643Sattilio    ~S ();
40223921Sae  };
41202437Strasz  #pragma omp declare reduction (bar : S : omp_out.foo (omp_in)) \
42202437Strasz	initializer (omp_priv (8))
43202437Strasz}
44202437Strasz
45202437StraszNS::S::~S ()
46202437Strasz{
47202437Strasz  if (s < 6) abort ();
48202437Strasz  s = -1;
49227309Sed  /* Ensure the above store is not DSEd.  */
50202437Strasz  asm volatile ("" : : "r" (&s) : "memory");
51202437Strasz}
52202437Strasz
53202437Straszstruct T : public NS::S
54202437Strasz{
55202437Strasz  void baz ()
56202437Strasz  {
57202437Strasz    S s;
58202437Strasz    int q = 0;
59202437Strasz    if (s.s != 6) abort ();
60202437Strasz    #pragma omp parallel num_threads (4) reduction (foo:s) \
61202437Strasz	reduction (+: q)
62238218Strasz    {
63202437Strasz      if (s.s != 6 || q != 0) abort ();
64202437Strasz      asm volatile ("" : "+m" (s.s), "+r" (q));
65202437Strasz      s.s += 2; q++;
66202437Strasz    }
67202437Strasz    if (s.s != 6 + q * 8) abort ();
68202437Strasz  }
69202437Strasz};
70202437Strasz
71202437Straszint
72202437Straszmain ()
73202437Strasz{
74202437Strasz  NS::S s;
75202437Strasz  s.baz (0);
76202437Strasz  T t;
77202437Strasz  t.baz ();
78202437Strasz  int q = 0;
79202437Strasz  if (s.s != 6) abort ();
80202437Strasz  // Test ADL
81202437Strasz  #pragma omp parallel num_threads (4) reduction (bar:s) reduction (+:q)
82202437Strasz  {
83202437Strasz    if (s.s != 8 || q != 0) abort ();
84202437Strasz    asm volatile ("" : "+m" (s.s), "+r" (q));
85202437Strasz    s.s += 4; q++;
86202437Strasz  }
87202437Strasz  if (s.s != 6 + q * 12) abort ();
88202437Strasz}
89202437Strasz