Hi!

In OpenMP 4.1, C++ references are allowed in {,first,last}private
and linear clauses (previously it has been only allowed in reduction),
but most of the support code in the middle-end has long been there for
invisible references and fortran already.

2015-05-27  Jakub Jelinek  <ja...@redhat.com>

        * omp-low.c (lower_rec_input_clauses): Unshare new_var
        before passing it to omp_clause_{default,copy}_ctor.
gcc/cp/
        * cp-gimplify.c (cxx_omp_finish_clause): Don't complain about
        reference type here.
        * semantics.c (finish_omp_clauses): Allow references in
        {{,first,last}private,linear} clauses.
gcc/testsuite/
        * g++.dg/gomp/task-1.C: Remove both dg-error directives.
        * g++.dg/gomp/reference-1.C: New test.
libgomp/
        * testsuite/libgomp.c++/ctor-13.C: New test.
        * testsuite/libgomp.c++/simd14.C: New test.
        * testsuite/libgomp.c++/reference-1.C: New test.

--- gcc/omp-low.c.jj    2015-05-21 11:12:09.000000000 +0200
+++ gcc/omp-low.c       2015-05-27 13:25:24.934324632 +0200
@@ -4038,7 +4038,8 @@ lower_rec_input_clauses (tree clauses, g
                x = NULL;
            do_private:
              tree nx;
-             nx = lang_hooks.decls.omp_clause_default_ctor (c, new_var, x);
+             nx = lang_hooks.decls.omp_clause_default_ctor
+                                               (c, unshare_expr (new_var), x);
              if (is_simd)
                {
                  tree y = lang_hooks.decls.omp_clause_dtor (c, new_var);
@@ -4192,7 +4193,8 @@ lower_rec_input_clauses (tree clauses, g
                      break;
                    }
                }
-             x = lang_hooks.decls.omp_clause_copy_ctor (c, new_var, x);
+             x = lang_hooks.decls.omp_clause_copy_ctor
+                                               (c, unshare_expr (new_var), x);
              gimplify_and_add (x, ilist);
              goto do_dtor;
 
--- gcc/cp/cp-gimplify.c.jj     2015-05-26 20:36:41.000000000 +0200
+++ gcc/cp/cp-gimplify.c        2015-05-27 14:33:01.690834022 +0200
@@ -1716,16 +1716,7 @@ cxx_omp_finish_clause (tree c, gimple_se
   if (decl == error_mark_node)
     make_shared = true;
   else if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE)
-    {
-      if (is_invisiref_parm (decl))
-       inner_type = TREE_TYPE (inner_type);
-      else
-       {
-         error ("%qE implicitly determined as %<firstprivate%> has reference 
type",
-                decl);
-         make_shared = true;
-       }
-    }
+    inner_type = TREE_TYPE (inner_type);
 
   /* We're interested in the base element, not arrays.  */
   while (TREE_CODE (inner_type) == ARRAY_TYPE)
--- gcc/cp/semantics.c.jj       2015-05-26 17:07:46.000000000 +0200
+++ gcc/cp/semantics.c  2015-05-27 16:33:16.153576552 +0200
@@ -5330,14 +5330,19 @@ finish_omp_clauses (tree clauses)
          goto check_dup_generic;
        case OMP_CLAUSE_LINEAR:
          t = OMP_CLAUSE_DECL (c);
-         if (!type_dependent_expression_p (t)
-             && !INTEGRAL_TYPE_P (TREE_TYPE (t))
-             && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
+         if (!type_dependent_expression_p (t))
            {
-             error ("linear clause applied to non-integral non-pointer "
-                    "variable with %qT type", TREE_TYPE (t));
-             remove = true;
-             break;
+             tree type = TREE_TYPE (t);
+             if (TREE_CODE (type) == REFERENCE_TYPE)
+               type = TREE_TYPE (type);
+             if (!INTEGRAL_TYPE_P (type)
+                 && TREE_CODE (type) != POINTER_TYPE)
+               {
+                 error ("linear clause applied to non-integral non-pointer "
+                        "variable with %qT type", TREE_TYPE (t));
+                 remove = true;
+                 break;
+               }
            }
          t = OMP_CLAUSE_LINEAR_STEP (c);
          if (t == NULL_TREE)
@@ -5362,14 +5367,16 @@ finish_omp_clauses (tree clauses)
                  if (TREE_CODE (OMP_CLAUSE_DECL (c)) == PARM_DECL)
                    t = maybe_constant_value (t);
                  t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
-                 if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c)))
-                     == POINTER_TYPE)
+                 tree type = TREE_TYPE (OMP_CLAUSE_DECL (c));
+                 if (TREE_CODE (type) == REFERENCE_TYPE)
+                   type = TREE_TYPE (type);
+                 if (TREE_CODE (type) == POINTER_TYPE)
                    {
+                     tree d = convert_from_reference (OMP_CLAUSE_DECL (c));
                      t = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR,
-                                          OMP_CLAUSE_DECL (c), t);
+                                          d, t);
                      t = fold_build2_loc (OMP_CLAUSE_LOCATION (c),
-                                          MINUS_EXPR, sizetype, t,
-                                          OMP_CLAUSE_DECL (c));
+                                          MINUS_EXPR, sizetype, t, d);
                      if (t == error_mark_node)
                        {
                          remove = true;
@@ -5377,7 +5384,7 @@ finish_omp_clauses (tree clauses)
                        }
                    }
                  else
-                   t = fold_convert (TREE_TYPE (OMP_CLAUSE_DECL (c)), t);
+                   t = fold_convert (type, t);
                }
              OMP_CLAUSE_LINEAR_STEP (c) = t;
            }
@@ -6019,7 +6026,7 @@ finish_omp_clauses (tree clauses)
     {
       enum omp_clause_code c_kind = OMP_CLAUSE_CODE (c);
       bool remove = false;
-      bool need_complete_non_reference = false;
+      bool need_complete_type = false;
       bool need_default_ctor = false;
       bool need_copy_ctor = false;
       bool need_copy_assignment = false;
@@ -6033,19 +6040,19 @@ finish_omp_clauses (tree clauses)
          need_implicitly_determined = true;
          break;
        case OMP_CLAUSE_PRIVATE:
-         need_complete_non_reference = true;
+         need_complete_type = true;
          need_default_ctor = true;
          need_dtor = true;
          need_implicitly_determined = true;
          break;
        case OMP_CLAUSE_FIRSTPRIVATE:
-         need_complete_non_reference = true;
+         need_complete_type = true;
          need_copy_ctor = true;
          need_dtor = true;
          need_implicitly_determined = true;
          break;
        case OMP_CLAUSE_LASTPRIVATE:
-         need_complete_non_reference = true;
+         need_complete_type = true;
          need_copy_assignment = true;
          need_implicitly_determined = true;
          break;
@@ -6125,18 +6132,14 @@ finish_omp_clauses (tree clauses)
          break;
        }
 
-      if (need_complete_non_reference || need_copy_assignment)
+      if (need_complete_type || need_copy_assignment)
        {
          t = require_complete_type (t);
          if (t == error_mark_node)
            remove = true;
          else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE
-                  && need_complete_non_reference)
-           {
-             error ("%qE has reference type for %qs", t,
-                    omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
-             remove = true;
-           }
+                  && !complete_type_or_else (TREE_TYPE (TREE_TYPE (t)), t))
+           remove = true;
        }
       if (need_implicitly_determined)
        {
@@ -6171,12 +6174,13 @@ finish_omp_clauses (tree clauses)
 
       /* We're interested in the base element, not arrays.  */
       inner_type = type = TREE_TYPE (t);
-      while (TREE_CODE (inner_type) == ARRAY_TYPE)
-       inner_type = TREE_TYPE (inner_type);
-
-      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+      if ((need_complete_type
+          || need_copy_assignment
+          || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
          && TREE_CODE (inner_type) == REFERENCE_TYPE)
        inner_type = TREE_TYPE (inner_type);
+      while (TREE_CODE (inner_type) == ARRAY_TYPE)
+       inner_type = TREE_TYPE (inner_type);
 
       /* Check for special function availability by building a call to one.
         Save the results, because later we won't be in the right context
--- gcc/testsuite/g++.dg/gomp/task-1.C.jj       2015-04-24 12:31:59.000000000 
+0200
+++ gcc/testsuite/g++.dg/gomp/task-1.C  2015-05-27 15:27:12.060612616 +0200
@@ -10,8 +10,8 @@ const A a;
 void foo (A &p)
 {
   const A &q = a;
-#pragma omp task       // { dg-error "has reference type" }
+#pragma omp task
   bar (p);
-#pragma omp task       // { dg-error "has reference type" }
+#pragma omp task
   bar (q);
 }
--- gcc/testsuite/g++.dg/gomp/reference-1.C.jj  2015-05-27 16:40:39.208545177 
+0200
+++ gcc/testsuite/g++.dg/gomp/reference-1.C     2015-05-27 16:40:06.000000000 
+0200
@@ -0,0 +1,26 @@
+// { dg-do compile }
+
+struct S;      // { dg-message "forward declaration" }
+void foo (S &);
+
+void
+f1 (S &x)      // { dg-error "has incomplete type" }
+{
+#pragma omp parallel private (x)
+  foo (x);
+}
+
+void
+f2 (S &x)      // { dg-error "has incomplete type" }
+{
+#pragma omp parallel firstprivate (x)
+  foo (x);
+}
+
+void
+f3 (S &x)      // { dg-error "has incomplete type" }
+{
+#pragma omp parallel for lastprivate (x)
+  for (int i = 0; i < 10; i++)
+    foo (x);
+}
--- libgomp/testsuite/libgomp.c++/ctor-13.C.jj  2015-05-27 13:26:38.375175340 
+0200
+++ libgomp/testsuite/libgomp.c++/ctor-13.C     2015-05-27 13:34:05.000000000 
+0200
@@ -0,0 +1,242 @@
+// { dg-do run }
+
+#include <omp.h>
+#include <assert.h>
+
+struct B
+{
+  static int ic, dc, xc, ac, cc;
+
+  B();
+  B(const B &);
+  ~B();
+  B& operator=(const B &);
+  void doit();
+  static void clear();
+};
+
+int B::ic;
+int B::dc;
+int B::xc;
+int B::cc;
+int B::ac;
+
+B::B()
+{
+  #pragma omp atomic 
+    ic++;
+}
+
+B::~B()
+{
+  #pragma omp atomic
+    dc++;
+}
+
+B::B(const B &)
+{
+  #pragma omp atomic
+    cc++;
+}
+
+B& B::operator=(const B &)
+{
+  #pragma omp atomic
+    ac++;
+  return *this;
+}
+
+void B::doit()
+{
+  #pragma omp atomic
+    xc++;
+}
+
+void B::clear()
+{
+  ic = 0;
+  dc = 0;
+  cc = 0;
+  ac = 0;
+  xc = 0;
+}
+
+static int n;
+
+void f1(B &a)
+{
+  B b;
+  B &c = b;
+  #pragma omp parallel default(none) private(a, c) shared (n)
+    {
+      #pragma omp master
+       n = omp_get_num_threads ();
+      a.doit();
+      c.doit();
+    }
+}
+
+void f2(B &a)
+{
+  B b;
+  B &c = b;
+  #pragma omp parallel default(none) firstprivate(a, c) shared(n)
+    {
+      #pragma omp master
+       n = omp_get_num_threads ();
+      a.doit();
+      c.doit();
+    }
+}
+
+void f3(B &a)
+{
+  B b;
+  B &c = b;
+  #pragma omp parallel default(none) shared(n, a, c)
+    {
+      #pragma omp master
+       n = omp_get_num_threads ();
+      #pragma omp for lastprivate (a, c)
+      for (int i = 0; i < omp_get_num_threads (); i++)
+       {
+         a.doit();
+         c.doit();
+       }
+    }
+}
+
+void f4()
+{
+  B b;
+  B &c = b;
+  #pragma omp parallel default(none) private (c) shared (n)
+    {
+      B d;
+      B &e = d;
+      #pragma omp single copyprivate (c, e)
+      {
+       c.doit();
+       e.doit();
+      }
+      c.doit();
+      e.doit();
+    }
+}
+
+void f5(B (&a)[2])
+{
+  B b[2];
+  B (&c)[2] = b;
+  #pragma omp parallel default(none) private(a, c) shared (n)
+    {
+      #pragma omp master
+       n = omp_get_num_threads ();
+      a[0].doit();
+      a[1].doit();
+      c[0].doit();
+      c[1].doit();
+    }
+}
+
+void f6(B (&a)[2])
+{
+  B b[2];
+  B (&c)[2] = b;
+  #pragma omp parallel default(none) firstprivate(a, c) shared (n)
+    {
+      #pragma omp master
+       n = omp_get_num_threads ();
+      a[0].doit();
+      a[1].doit();
+      c[0].doit();
+      c[1].doit();
+    }
+}
+
+void f7(B (&a)[2])
+{
+  B b[2];
+  B (&c)[2] = b;
+  #pragma omp parallel default(none) shared(n, a, c)
+    {
+      #pragma omp master
+       n = omp_get_num_threads ();
+      #pragma omp for lastprivate (a, c)
+      for (int i = 0; i < omp_get_num_threads (); i++)
+       {
+         a[0].doit();
+         a[1].doit();
+         c[0].doit();
+         c[1].doit();
+       }
+    }
+}
+
+void f8()
+{
+  B b[2];
+  B (&c)[2] = b;
+  #pragma omp parallel default(none) private (c) shared (n)
+    {
+      B d[2];
+      B (&e)[2] = d;
+      #pragma omp single copyprivate (c, e)
+      {
+       c[0].doit();
+       c[1].doit();
+       e[0].doit();
+       e[1].doit();
+      }
+      c[0].doit();
+      c[1].doit();
+      e[0].doit();
+      e[1].doit();
+    }
+}
+
+int main()
+{
+  {
+    B a;
+    f1(a);
+  }
+  assert (B::xc == 2*n && B::ic == 2*n+2 && B::dc == 2*n+2 && B::ac == 0 && 
B::cc == 0);
+  B::clear();
+  {
+    B a;
+    f2(a);
+  }
+  assert (B::xc == 2*n && B::ic == 2 && B::dc == 2*n+2 && B::ac == 0 && B::cc 
== 2*n);
+  B::clear();
+  {
+    B a;
+    f3(a);
+  }
+  assert (B::xc == 2*n && B::ic == 2*n+2 && B::dc == 2*n+2 && B::ac == 2 && 
B::cc == 0);
+  B::clear();
+  f4();
+  assert (B::xc == 2*n+2 && B::ic == 2*n+1 && B::dc == 2*n+1 && B::ac == 2*n-2 
&& B::cc == 0);
+  B::clear();
+  {
+    B a[2];
+    f5(a);
+  }
+  assert (B::xc == 4*n && B::ic == 4*n+4 && B::dc == 4*n+4 && B::ac == 0 && 
B::cc == 0);
+  B::clear();
+  {
+    B a[2];
+    f6(a);
+  }
+  assert (B::xc == 4*n && B::ic == 4 && B::dc == 4*n+4 && B::ac == 0 && B::cc 
== 4*n);
+  B::clear();
+  {
+    B a[2];
+    f7(a);
+  }
+  assert (B::xc == 4*n && B::ic == 4*n+4 && B::dc == 4*n+4 && B::ac == 4 && 
B::cc == 0);
+  B::clear();
+  f8();
+  assert (B::xc == 4*n+4 && B::ic == 4*n+2 && B::dc == 4*n+2 && B::ac == 4*n-4 
&& B::cc == 0);
+  return 0;
+}
--- libgomp/testsuite/libgomp.c++/simd14.C.jj   2015-05-27 14:57:53.683724066 
+0200
+++ libgomp/testsuite/libgomp.c++/simd14.C      2015-05-27 14:58:53.270765657 
+0200
@@ -0,0 +1,43 @@
+// { dg-do run }
+// { dg-options "-O2" }
+// { dg-additional-options "-msse2" { target sse2_runtime } }
+// { dg-additional-options "-mavx" { target avx_runtime } }
+
+int a[1024];
+short b[2048];
+
+static inline void
+bar (int &x, unsigned long long &y, short *&z)
+{
+  a[x] = x + y + *z;
+  x++;
+  y += 17;
+  z += 2;
+}
+
+__attribute__((noinline, noclone)) int
+foo (unsigned long long &s, short *&t)
+{
+  int i, j = 0;
+  int &r = j;
+#pragma omp parallel for simd linear(r) linear(s:17ULL) linear(t:2)
+  for (i = 0; i < 1024; i++)
+    bar (r, s, t);
+  return j;
+}
+
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 2048; i++)
+    b[i] = 3 * i;
+  unsigned long long s = 12;
+  short *t = b;
+  int j = foo (s, t);
+  for (i = 0; i < 1024; i++)
+    if (a[i] != 12 + 24 * i)
+      __builtin_abort ();
+  if (j != 1024 || s != 12 + 1024 * 17ULL || t != &b[2048])
+    __builtin_abort ();
+}
--- libgomp/testsuite/libgomp.c++/reference-1.C.jj      2015-05-27 
14:59:53.711797319 +0200
+++ libgomp/testsuite/libgomp.c++/reference-1.C 2015-05-27 15:11:27.286685406 
+0200
@@ -0,0 +1,57 @@
+// { dg-do run }
+
+#include <omp.h>
+
+__attribute__((noinline, noclone)) void
+foo (int &a, short &d, char &g)
+{
+  unsigned long b = 12;
+  unsigned long &c = b;
+  long long e = 21;
+  long long &f = e;
+  unsigned int h = 12;
+  unsigned int &k = h;
+  #pragma omp parallel default(none) private(a, c) firstprivate(d, f) 
shared(g, k)
+    {
+      int i = omp_get_thread_num ();
+      a = i;
+      c = 2 * i;
+      if (d != 27 || f != 21)
+       __builtin_abort ();
+      d = 3 * (i & 0xfff);
+      f = 4 * i;
+      #pragma omp barrier
+      if (a != i || c != 2 * i || d != 3 * (i & 0xfff) || f != 4 * i)
+       __builtin_abort ();
+      #pragma omp for lastprivate(g, k)
+      for (int j = 0; j < 32; j++)
+       {
+         g = j;
+         k = 3 * j;
+       }
+    }
+  if (g != 31 || k != 31 * 3)
+    __builtin_abort ();
+  #pragma omp parallel for firstprivate (g, k) lastprivate (g, k)
+  for (int j = 0; j < 32; j++)
+    {
+      if (g != 31 || k != 31 * 3)
+       __builtin_abort ();
+      if (j == 31)
+       {
+         g = 29;
+         k = 138;
+       }
+    }
+  if (g != 29 || k != 138)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  int a = 5;
+  short d = 27;
+  char g = ' ';
+  foo (a, d, g);
+}

        Jakub

Reply via email to