diff mbox

[gomp4.1] Support for OpenMP 4.1 privatization of non-static data members in methods

Message ID 20150602173515.GQ10247@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek June 2, 2015, 5:35 p.m. UTC
Hi!

The OpenMP 4.1 standard is going to allow privatization of non-static data
members separately from the containing class in methods.  The behavior of
access to those members in the OpenMP regions where they are privatized
through this-> is unspecified, I chose to let to privatize only the accesses
not through this->.

Jason on IRC said that he is considering deferring expansion of the
non-static data member accesses into this->field etc. form till
genericization, then of course this patch will need some changes to do the
replacement of such accesses during genericization instead of parsing
and instantiation.

I've only noticed now that reduction clause isn't covered in the tests, will
add that tomorrow.

2015-06-02  Jakub Jelinek  <jakub@redhat.com>

	* gimplify.c (omp_check_private): Handle
	omp_member_access_dummy_var vars.
	(gimplify_scan_omp_clauses): Set DECL_NAME on
	omp_member_access_dummy_var vars.
	* omp-low.c (omp_member_access_dummy_var, unshare_and_remap_1,
	unshare_and_remap): New functions.
	(use_pointer_for_field): omp_member_access_dummy_var vars
	don't need to be made addressable.
	(build_outer_var_ref): Handle omp_member_access_dummy_var vars.
	Handle OMP_CLAUSE_SHARED_FIRSTPRIVATE references.
	(lower_send_clauses): Likewise.
	(scan_sharing_clauses): Handle OMP_CLAUSE_SHARED_FIRSTPRIVATE
	references.
	(lower_send_shared_vars): Handle omp_member_access_dummy_var vars.
	(create_task_copyfn): Fix up handling of
	OMP_CLAUSE_SHARED_FIRSTPRIVATE decls.
	(lower_omp_regimplify_p): Use IS_TYPE_OR_DECL_P macro.
	(struct lower_omp_regimplify_operands_data): New type.
	(lower_omp_regimplify_operands_p, lower_omp_regimplify_operands): New
	functions.
	(lower_omp_1): Use lower_omp_regimplify_operands instead of
	gimple_regimplify_operands.
	* omp-low.h (omp_member_access_dummy_var): New prototype.
gcc/cp/
	* parser.c (cp_parser_lambda_body): Call
	save_omp_privatization_clauses and restore_omp_privatization_clauses
	around lambda body parsing.
	(cp_parser_oacc_all_clauses, cp_parser_omp_all_clauses,
	cp_parser_omp_for_loop, cp_omp_split_clauses, cp_parser_oacc_cache,
	cp_parser_cilk_for): Adjust finish_omp_clauses callers.
	(cp_parser_pragma): Call push_omp_privatization_clauses and
	pop_omp_privatization_clauses around OpenMP pragma parsing.
	* cp-gimplify.c (cxx_omp_disregard_value_expr): New function.
	* pt.c (apply_late_template_attributes): Adjust finish_omp_clauses
	and tsubst_omp_clauses callers.
	(tsubst_omp_clauses): Add ALLOW_FIELDS argument, adjust possible
	non-static data member arguments and pass ALLOW_FIELDS down to
	finish_omp_clauses.
	(tsubst_omp_for_iterator): Adjust finish_omp_clauses caller.
	(tsubst_expr): Adjust tsubst_omp_clauses caller, call
	push_omp_privatization_clauses and pop_omp_privatization_clauses
	around instantiation of the constructs.
	* cp-tree.h (DECL_OMP_PRIVATIZED_MEMBER): Define.
	(finish_omp_clauses): Add ALLOW_FIELDS argument to prototype.
	(push_omp_privatization_clauses, pop_omp_privatization_clauses,
	save_omp_privatization_clauses, restore_omp_privatization_clauses,
	cxx_omp_disregard_value_expr): New prototypes.
	* cp-objcp-common.h (LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR): Redefine.
	* semantics.c (omp_private_member_map, omp_private_member_vec): New
	variables.
	(finish_non_static_data_member): Return dummy decl for privatized
	non-static data members.
	(finish_omp_clauses): Add ALLOW_FIELDS argument.  Handle
	non-static data member privatization in {,first,last,copy}private,
	reduction and linear clauses.  Diagnose linear with predetermined
	decls.
	(push_omp_privatization_clauses, pop_omp_privatization_clauses,
	save_omp_privatization_clauses, restore_omp_privatization_clauses):
	New functions.
	(finish_omp_for): Adjust finish_omp_clauses caller.
gcc/testsuite/
	* g++.dg/gomp/clause-1.C (T::test): Remove dg-error
	on privatization of non-static data members.
	* g++.dg/gomp/member-1.C: New test.
	* g++.dg/gomp/member-2.C: New test.
libgomp/
	* testsuite/libgomp.c++/taskloop-5.C: New test.
	* testsuite/libgomp.c++/member-1.C: New test.
	* testsuite/libgomp.c++/member-2.C: New test.


	Jakub
diff mbox

Patch

--- gcc/gimplify.c.jj	2015-05-21 11:12:09.000000000 +0200
+++ gcc/gimplify.c	2015-05-29 16:01:15.183190752 +0200
@@ -6061,19 +6061,38 @@  omp_check_private (struct gimplify_omp_c
     {
       ctx = ctx->outer_context;
       if (ctx == NULL)
-	return !(is_global_var (decl)
-		 /* References might be private, but might be shared too,
-		    when checking for copyprivate, assume they might be
-		    private, otherwise assume they might be shared.  */
-		 || (!copyprivate
-		     && lang_hooks.decls.omp_privatize_by_reference (decl)));
+	{
+	  if (is_global_var (decl))
+	    return false;
+
+	  /* References might be private, but might be shared too,
+	     when checking for copyprivate, assume they might be
+	     private, otherwise assume they might be shared.  */
+	  if (copyprivate)
+	    return true;
+
+	  if (lang_hooks.decls.omp_privatize_by_reference (decl))
+	    return false;
+
+	  /* Treat C++ privatized non-static data members outside
+	     of the privatization the same.  */
+	  if (omp_member_access_dummy_var (decl))
+	    return false;
+
+	  return true;
+	}
 
       if ((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0)
 	continue;
 
       n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
       if (n != NULL)
-	return (n->value & GOVD_SHARED) == 0;
+	{
+	  if ((n->value & GOVD_LOCAL) != 0
+	      && omp_member_access_dummy_var (decl))
+	    return false;
+	  return (n->value & GOVD_SHARED) == 0;
+	}
     }
   while (ctx->region_type == ORT_WORKSHARE
 	 || ctx->region_type == ORT_SIMD);
@@ -6357,6 +6376,17 @@  gimplify_scan_omp_clauses (tree *list_p,
 	      remove = true;
 	      break;
 	    }
+	  if (DECL_NAME (decl) == NULL_TREE && (flags & GOVD_SHARED) == 0)
+	    {
+	      tree t = omp_member_access_dummy_var (decl);
+	      if (t)
+		{
+		  tree v = DECL_VALUE_EXPR (decl);
+		  DECL_NAME (decl) = DECL_NAME (TREE_OPERAND (v, 1));
+		  if (outer_ctx)
+		    omp_notice_variable (outer_ctx, t, true);
+		}
+	    }
 	  omp_add_variable (ctx, decl, flags);
 	  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
 	      && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
--- gcc/omp-low.c.jj	2015-05-27 13:25:24.000000000 +0200
+++ gcc/omp-low.c	2015-06-02 14:22:19.524712561 +0200
@@ -337,6 +337,73 @@  oacc_max_threads (omp_context *ctx)
   return nthreads;
 }
 
+/* If DECL is the artificial dummy VAR_DECL created for non-static
+   data member privatization, return the underlying "this" parameter,
+   otherwise return NULL.  */
+
+tree
+omp_member_access_dummy_var (tree decl)
+{
+  if (!VAR_P (decl)
+      || !DECL_ARTIFICIAL (decl)
+      || !DECL_IGNORED_P (decl)
+      || !DECL_HAS_VALUE_EXPR_P (decl)
+      || !lang_hooks.decls.omp_disregard_value_expr (decl, false))
+    return NULL_TREE;
+
+  tree v = DECL_VALUE_EXPR (decl);
+  if (TREE_CODE (v) != COMPONENT_REF)
+    return NULL_TREE;
+
+  while (1)
+    switch (TREE_CODE (v))
+      {
+      case COMPONENT_REF:
+      case MEM_REF:
+      case INDIRECT_REF:
+      CASE_CONVERT:
+      case POINTER_PLUS_EXPR:
+	v = TREE_OPERAND (v, 0);
+	continue;
+      case PARM_DECL:
+	if (DECL_CONTEXT (v) == current_function_decl
+	    && DECL_ARTIFICIAL (v)
+	    && TREE_CODE (TREE_TYPE (v)) == POINTER_TYPE)
+	  return v;
+	return NULL_TREE;
+      default:
+	return NULL_TREE;
+      }
+}
+
+/* Helper for unshare_and_remap, called through walk_tree.  */
+
+static tree
+unshare_and_remap_1 (tree *tp, int *walk_subtrees, void *data)
+{
+  tree *pair = (tree *) data;
+  if (*tp == pair[0])
+    {
+      *tp = unshare_expr (pair[1]);
+      *walk_subtrees = 0;
+    }
+  else if (IS_TYPE_OR_DECL_P (*tp))
+    *walk_subtrees = 0;
+  return NULL_TREE;
+}
+
+/* Return unshare_expr (X) with all occurrences of FROM
+   replaced with TO.  */
+
+static tree
+unshare_and_remap (tree x, tree from, tree to)
+{
+  tree pair[2] = { from, to };
+  x = unshare_expr (x);
+  walk_tree (&x, unshare_and_remap_1, pair, NULL);
+  return x;
+}
+
 /* Holds offload tables with decls.  */
 vec<tree, va_gc> *offload_funcs, *offload_vars;
 
@@ -1103,7 +1170,7 @@  use_pointer_for_field (tree decl, omp_co
 	  tree outer;
 	maybe_mark_addressable_and_ret:
 	  outer = maybe_lookup_decl_in_outer_ctx (decl, shared_ctx);
-	  if (is_gimple_reg (outer))
+	  if (is_gimple_reg (outer) && !omp_member_access_dummy_var (outer))
 	    {
 	      /* Taking address of OUTER in lower_send_shared_vars
 		 might need regimplification of everything that uses the
@@ -1241,7 +1308,8 @@  build_outer_var_ref (tree var, omp_conte
 
 	  x = build_simple_mem_ref (ctx->outer->receiver_decl);
 	  x = omp_build_component_ref (x, field);
-	  x = build_simple_mem_ref (x);
+	  if (use_pointer_for_field (var, ctx->outer))
+	    x = build_simple_mem_ref (x);
 	}
     }
   else if (ctx->outer)
@@ -1250,9 +1318,25 @@  build_outer_var_ref (tree var, omp_conte
     /* This can happen with orphaned constructs.  If var is reference, it is
        possible it is shared and as such valid.  */
     x = var;
+  else if (omp_member_access_dummy_var (var))
+    x = var;
   else
     gcc_unreachable ();
 
+  if (x == var)
+    {
+      tree t = omp_member_access_dummy_var (var);
+      if (t)
+	{
+	  x = DECL_VALUE_EXPR (var);
+	  tree o = maybe_lookup_decl_in_outer_ctx (t, ctx);
+	  if (o != t)
+	    x = unshare_and_remap (x, t, o);
+	  else
+	    x = unshare_expr (x);
+	}
+    }
+
   if (is_reference (var))
     x = build_simple_mem_ref (x);
 
@@ -1758,10 +1842,7 @@  scan_sharing_clauses (tree clauses, omp_
 	    break;
 	  by_ref = use_pointer_for_field (decl, ctx);
 	  if (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c))
-	    {
-	      gcc_assert (by_ref);
-	      break;
-	    }
+	    break;
 	  if (! TREE_READONLY (decl)
 	      || TREE_ADDRESSABLE (decl)
 	      || by_ref
@@ -2046,7 +2127,8 @@  scan_sharing_clauses (tree clauses, omp_
 	    break;
 	  if (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c))
 	    {
-	      install_var_field (decl, true, 11, ctx);
+	      bool by_ref = use_pointer_for_field (decl, ctx);
+	      install_var_field (decl, by_ref, 11, ctx);
 	      break;
 	    }
 	  fixup_remapped_decl (decl, ctx, false);
@@ -4843,7 +4925,7 @@  static void
 lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist,
     		    omp_context *ctx)
 {
-  tree c;
+  tree c, t;
   int ignored_looptemp = 0;
 
   /* For taskloop, ignore first two _looptemp_ clauses, those are initialized
@@ -4890,6 +4972,17 @@  lower_send_clauses (tree clauses, gimple
 	  && is_global_var (var))
 	continue;
 
+      t = omp_member_access_dummy_var (var);
+      if (t)
+	{
+	  var = DECL_VALUE_EXPR (var);
+	  tree o = maybe_lookup_decl_in_outer_ctx (t, ctx);
+	  if (o != t)
+	    var = unshare_and_remap (var, t, o);
+	  else
+	    var = unshare_expr (var);
+	}
+
       if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED)
 	{
 	  /* Handle taskloop firstprivate/lastprivate, where the
@@ -4900,9 +4993,9 @@  lower_send_clauses (tree clauses, gimple
 	      splay_tree_lookup (ctx->sfield_map
 				 ? ctx->sfield_map : ctx->field_map,
 				 (splay_tree_key) &DECL_UID (val))->value;
-	  gcc_assert (use_pointer_for_field (val, ctx));
 	  x = omp_build_component_ref (ctx->sender_decl, f);
-	  var = build_fold_addr_expr (var);
+	  if (use_pointer_for_field (val, ctx))
+	    var = build_fold_addr_expr (var);
 	  gimplify_assign (x, var, ilist);
 	  DECL_ABSTRACT_ORIGIN (f) = NULL;
 	  continue;
@@ -4969,7 +5062,7 @@  lower_send_clauses (tree clauses, gimple
 static void
 lower_send_shared_vars (gimple_seq *ilist, gimple_seq *olist, omp_context *ctx)
 {
-  tree var, ovar, nvar, f, x, record_type;
+  tree var, ovar, nvar, t, f, x, record_type;
 
   if (ctx->record_type == NULL)
     return;
@@ -4990,6 +5083,17 @@  lower_send_shared_vars (gimple_seq *ilis
 	 mapping for OVAR.  */
       var = lookup_decl_in_outer_ctx (ovar, ctx);
 
+      t = omp_member_access_dummy_var (var);
+      if (t)
+	{
+	  var = DECL_VALUE_EXPR (var);
+	  tree o = maybe_lookup_decl_in_outer_ctx (t, ctx);
+	  if (o != t)
+	    var = unshare_and_remap (var, t, o);
+	  else
+	    var = unshare_expr (var);
+	}
+
       if (use_pointer_for_field (ovar, ctx))
 	{
 	  x = build_sender_ref (ovar, ctx);
@@ -11615,22 +11719,19 @@  create_task_copyfn (gomp_task *task_stmt
   for (c = gimple_omp_task_clauses (task_stmt); c; c = OMP_CLAUSE_CHAIN (c))
     switch (OMP_CLAUSE_CODE (c))
       {
+	splay_tree_key key;
       case OMP_CLAUSE_SHARED:
 	decl = OMP_CLAUSE_DECL (c);
-	n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl);
+	key = (splay_tree_key) decl;
+	if (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c))
+	  key = (splay_tree_key) &DECL_UID (decl);
+	n = splay_tree_lookup (ctx->field_map, key);
 	if (n == NULL)
 	  break;
-	if (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c))
-	  {
-	    decl = (tree) n->value;
-	    n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl);
-	    if (n == NULL)
-	      break;
-	  }
 	f = (tree) n->value;
 	if (tcctx.cb.decl_map)
 	  f = *tcctx.cb.decl_map->get (f);
-	n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl);
+	n = splay_tree_lookup (ctx->sfield_map, key);
 	sf = (tree) n->value;
 	if (tcctx.cb.decl_map)
 	  sf = *tcctx.cb.decl_map->get (sf);
@@ -12424,10 +12525,73 @@  lower_omp_regimplify_p (tree *tp, int *w
   if (data == NULL && TREE_CODE (t) == ADDR_EXPR)
     recompute_tree_invariant_for_addr_expr (t);
 
-  *walk_subtrees = !TYPE_P (t) && !DECL_P (t);
+  *walk_subtrees = !IS_TYPE_OR_DECL_P (t);
+  return NULL_TREE;
+}
+
+/* Data to be communicated between lower_omp_regimplify_operands and
+   lower_omp_regimplify_operands_p.  */
+
+struct lower_omp_regimplify_operands_data
+{
+  omp_context *ctx;
+  vec<tree> *decls;
+};
+
+/* Helper function for lower_omp_regimplify_operands.  Find
+   omp_member_access_dummy_var vars and adjust temporarily their
+   DECL_VALUE_EXPRs if needed.  */
+
+static tree
+lower_omp_regimplify_operands_p (tree *tp, int *walk_subtrees,
+				 void *data)
+{
+  tree t = omp_member_access_dummy_var (*tp);
+  if (t)
+    {
+      struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
+      lower_omp_regimplify_operands_data *ldata
+	= (lower_omp_regimplify_operands_data *) wi->info;
+      tree o = maybe_lookup_decl (t, ldata->ctx);
+      if (o != t)
+	{
+	  ldata->decls->safe_push (DECL_VALUE_EXPR (*tp));
+	  ldata->decls->safe_push (*tp);
+	  tree v = unshare_and_remap (DECL_VALUE_EXPR (*tp), t, o);
+	  SET_DECL_VALUE_EXPR (*tp, v);
+	}
+    }
+  *walk_subtrees = !IS_TYPE_OR_DECL_P (*tp);
   return NULL_TREE;
 }
 
+/* Wrapper around gimple_regimplify_operands that adjusts DECL_VALUE_EXPRs
+   of omp_member_access_dummy_var vars during regimplification.  */
+
+static void
+lower_omp_regimplify_operands (omp_context *ctx, gimple stmt,
+			       gimple_stmt_iterator *gsi_p)
+{
+  auto_vec<tree, 10> decls;
+  if (ctx)
+    {
+      struct walk_stmt_info wi;
+      memset (&wi, '\0', sizeof (wi));
+      struct lower_omp_regimplify_operands_data data;
+      data.ctx = ctx;
+      data.decls = &decls;
+      wi.info = &data;
+      walk_gimple_op (stmt, lower_omp_regimplify_operands_p, &wi);
+    }
+  gimple_regimplify_operands (stmt, gsi_p);
+  while (!decls.is_empty ())
+    {
+      tree t = decls.pop ();
+      tree v = decls.pop ();
+      SET_DECL_VALUE_EXPR (t, v);
+    }
+}
+
 static void
 lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 {
@@ -12462,7 +12626,7 @@  lower_omp_1 (gimple_stmt_iterator *gsi_p
 		|| walk_tree (gimple_cond_rhs_ptr (cond_stmt),
 			      lower_omp_regimplify_p,
 			      ctx ? NULL : &wi, NULL)))
-	  gimple_regimplify_operands (cond_stmt, gsi_p);
+	  lower_omp_regimplify_operands (ctx, cond_stmt, gsi_p);
       }
       break;
     case GIMPLE_CATCH:
@@ -12535,7 +12699,7 @@  lower_omp_1 (gimple_stmt_iterator *gsi_p
 	  && walk_tree (gimple_omp_atomic_load_rhs_ptr (
 			  as_a <gomp_atomic_load *> (stmt)),
 			lower_omp_regimplify_p, ctx ? NULL : &wi, NULL))
-	gimple_regimplify_operands (stmt, gsi_p);
+	lower_omp_regimplify_operands (ctx, stmt, gsi_p);
       break;
     case GIMPLE_OMP_TARGET:
       ctx = maybe_lookup_ctx (stmt);
@@ -12616,7 +12780,7 @@  lower_omp_1 (gimple_stmt_iterator *gsi_p
 	      gsi_replace (gsi_p, gimple_build_nop (), true);
 	      break;
 	    }
-	  gimple_regimplify_operands (stmt, gsi_p);
+	  lower_omp_regimplify_operands (ctx, stmt, gsi_p);
 	}
       break;
     }
--- gcc/omp-low.h.jj	2015-04-24 12:31:31.000000000 +0200
+++ gcc/omp-low.h	2015-05-29 15:53:36.731258690 +0200
@@ -28,6 +28,7 @@  extern void free_omp_regions (void);
 extern tree omp_reduction_init (tree, tree);
 extern bool make_gimple_omp_edges (basic_block, struct omp_region **, int *);
 extern void omp_finish_file (void);
+extern tree omp_member_access_dummy_var (tree);
 
 extern GTY(()) vec<tree, va_gc> *offload_funcs;
 extern GTY(()) vec<tree, va_gc> *offload_vars;
--- gcc/cp/parser.c.jj	2015-05-26 19:11:13.000000000 +0200
+++ gcc/cp/parser.c	2015-06-02 19:02:27.531147296 +0200
@@ -9483,6 +9483,8 @@  cp_parser_lambda_body (cp_parser* parser
     /* Still increment function_depth so that we don't GC in the
        middle of an expression.  */
     ++function_depth;
+  vec<tree> omp_privatization_save;
+  save_omp_privatization_clauses (omp_privatization_save);
   /* Clear this in case we're in the middle of a default argument.  */
   parser->local_variables_forbidden_p = false;
 
@@ -9584,6 +9586,7 @@  cp_parser_lambda_body (cp_parser* parser
       expand_or_defer_fn (fn);
   }
 
+  restore_omp_privatization_clauses (omp_privatization_save);
   parser->local_variables_forbidden_p = local_variables_forbidden_p;
   if (nested)
     pop_function_context();
@@ -29520,7 +29523,7 @@  cp_parser_oacc_all_clauses (cp_parser *p
   cp_parser_skip_to_pragma_eol (parser, pragma_tok);
 
   if (finish_p)
-    return finish_omp_clauses (clauses);
+    return finish_omp_clauses (clauses, false);
 
   return clauses;
 }
@@ -29805,7 +29808,7 @@  cp_parser_omp_all_clauses (cp_parser *pa
   if (!(flag_cilkplus && pragma_tok == NULL))
     cp_parser_skip_to_pragma_eol (parser, pragma_tok);
   if (finish_p)
-    return finish_omp_clauses (clauses);
+    return finish_omp_clauses (clauses, true);
   return clauses;
 }
 
@@ -30795,7 +30798,7 @@  cp_parser_omp_for_loop (cp_parser *parse
 	    {
 	      c = build_omp_clause (loc, OMP_CLAUSE_PRIVATE);
 	      OMP_CLAUSE_DECL (c) = decl;
-	      c = finish_omp_clauses (c);
+	      c = finish_omp_clauses (c, false);
 	      if (c)
 		{
 		  OMP_CLAUSE_CHAIN (c) = clauses;
@@ -30934,7 +30937,7 @@  cp_omp_split_clauses (location_t loc, en
   c_omp_split_clauses (loc, code, mask, clauses, cclauses);
   for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
     if (cclauses[i])
-      cclauses[i] = finish_omp_clauses (cclauses[i]);
+      cclauses[i] = finish_omp_clauses (cclauses[i], true);
 }
 
 /* OpenMP 4.0:
@@ -32027,7 +32030,7 @@  cp_parser_oacc_cache (cp_parser *parser,
   tree stmt, clauses;
 
   clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE__CACHE_, NULL_TREE);
-  clauses = finish_omp_clauses (clauses);
+  clauses = finish_omp_clauses (clauses, false);
 
   cp_parser_require_pragma_eol (parser, cp_lexer_peek_token (parser->lexer));
 
@@ -33529,6 +33532,8 @@  cp_parser_pragma (cp_parser *parser, enu
 {
   cp_token *pragma_tok;
   unsigned int id;
+  tree stmt;
+  bool ret;
 
   pragma_tok = cp_lexer_consume_token (parser->lexer);
   gcc_assert (pragma_tok->type == CPP_PRAGMA);
@@ -33670,14 +33675,22 @@  cp_parser_pragma (cp_parser *parser, enu
     case PRAGMA_OMP_TEAMS:
       if (context != pragma_stmt && context != pragma_compound)
 	goto bad_stmt;
+      stmt = push_omp_privatization_clauses ();
       cp_parser_omp_construct (parser, pragma_tok);
+      pop_omp_privatization_clauses (stmt);
       return true;
 
     case PRAGMA_OMP_ORDERED:
-      return cp_parser_omp_ordered (parser, pragma_tok, context);
+      stmt = push_omp_privatization_clauses ();
+      ret = cp_parser_omp_ordered (parser, pragma_tok, context);
+      pop_omp_privatization_clauses (stmt);
+      return ret;
 
     case PRAGMA_OMP_TARGET:
-      return cp_parser_omp_target (parser, pragma_tok, context);
+      stmt = push_omp_privatization_clauses ();
+      ret = cp_parser_omp_target (parser, pragma_tok, context);
+      pop_omp_privatization_clauses (stmt);
+      return ret;
 
     case PRAGMA_OMP_END_DECLARE_TARGET:
       cp_parser_omp_end_declare_target (parser, pragma_tok);
@@ -33718,7 +33731,9 @@  cp_parser_pragma (cp_parser *parser, enu
 		    "%<#pragma simd%> must be inside a function");
 	  break;
 	}
+      stmt = push_omp_privatization_clauses ();
       cp_parser_cilk_simd (parser, pragma_tok);
+      pop_omp_privatization_clauses (stmt);
       return true;
 
     case PRAGMA_CILK_GRAINSIZE:
@@ -34099,7 +34114,7 @@  cp_parser_cilk_for (cp_parser *parser, t
   tree clauses = build_omp_clause (EXPR_LOCATION (grain), OMP_CLAUSE_SCHEDULE);
   OMP_CLAUSE_SCHEDULE_KIND (clauses) = OMP_CLAUSE_SCHEDULE_CILKFOR;
   OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clauses) = grain;
-  clauses = finish_omp_clauses (clauses);
+  clauses = finish_omp_clauses (clauses, false);
 
   tree ret = cp_parser_omp_for_loop (parser, CILK_FOR, clauses, NULL);
   if (ret)
--- gcc/cp/cp-gimplify.c.jj	2015-05-27 14:33:01.000000000 +0200
+++ gcc/cp/cp-gimplify.c	2015-05-28 18:51:03.904953463 +0200
@@ -1733,3 +1733,19 @@  cxx_omp_finish_clause (tree c, gimple_se
   if (make_shared)
     OMP_CLAUSE_CODE (c) = OMP_CLAUSE_SHARED;
 }
+
+/* Return true if DECL's DECL_VALUE_EXPR (if any) should be
+   disregarded in OpenMP construct, because it is going to be
+   remapped during OpenMP lowering.  SHARED is true if DECL
+   is going to be shared, false if it is going to be privatized.  */
+
+bool
+cxx_omp_disregard_value_expr (tree decl, bool shared)
+{
+  return !shared
+	 && VAR_P (decl)
+	 && DECL_HAS_VALUE_EXPR_P (decl)
+	 && DECL_ARTIFICIAL (decl)
+	 && DECL_LANG_SPECIFIC (decl)
+	 && DECL_OMP_PRIVATIZED_MEMBER (decl);
+}
--- gcc/cp/pt.c.jj	2015-05-26 20:35:55.000000000 +0200
+++ gcc/cp/pt.c	2015-06-02 18:19:13.374986425 +0200
@@ -8949,7 +8949,7 @@  can_complete_type_without_circularity (t
     return 1;
 }
 
-static tree tsubst_omp_clauses (tree, bool, tree, tsubst_flags_t, tree);
+static tree tsubst_omp_clauses (tree, bool, bool, tree, tsubst_flags_t, tree);
 
 /* Apply any attributes which had to be deferred until instantiation
    time.  DECL_P, ATTRIBUTES and ATTR_FLAGS are as cplus_decl_attributes;
@@ -8998,10 +8998,10 @@  apply_late_template_attributes (tree *de
 		  && TREE_VALUE (t))
 		{
 		  tree clauses = TREE_VALUE (TREE_VALUE (t));
-		  clauses = tsubst_omp_clauses (clauses, true, args,
+		  clauses = tsubst_omp_clauses (clauses, true, false, args,
 						complain, in_decl);
 		  c_omp_declare_simd_clauses_to_decls (*decl_p, clauses);
-		  clauses = finish_omp_clauses (clauses);
+		  clauses = finish_omp_clauses (clauses, false);
 		  tree parms = DECL_ARGUMENTS (*decl_p);
 		  clauses
 		    = c_omp_declare_simd_clauses_to_numbers (parms, clauses);
@@ -13432,7 +13432,7 @@  tsubst_copy (tree t, tree args, tsubst_f
 /* Like tsubst_copy, but specifically for OpenMP clauses.  */
 
 static tree
-tsubst_omp_clauses (tree clauses, bool declare_simd,
+tsubst_omp_clauses (tree clauses, bool declare_simd, bool allow_fields,
 		    tree args, tsubst_flags_t complain, tree in_decl)
 {
   tree new_clauses = NULL, nc, oc;
@@ -13532,11 +13532,80 @@  tsubst_omp_clauses (tree clauses, bool d
 	default:
 	  gcc_unreachable ();
 	}
+      if (allow_fields)
+	switch (OMP_CLAUSE_CODE (nc))
+	  {
+	  case OMP_CLAUSE_PRIVATE:
+	  case OMP_CLAUSE_FIRSTPRIVATE:
+	  case OMP_CLAUSE_LASTPRIVATE:
+	  case OMP_CLAUSE_COPYPRIVATE:
+	  case OMP_CLAUSE_LINEAR:
+	  case OMP_CLAUSE_REDUCTION:
+	    /* tsubst_expr on SCOPE_REF results in returning
+	       finish_non_static_data_member result.  Undo that here.  */
+	    if (TREE_CODE (OMP_CLAUSE_DECL (oc)) == SCOPE_REF
+		&& (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (oc), 1))
+		    == IDENTIFIER_NODE))
+	      {
+		tree t = OMP_CLAUSE_DECL (nc);
+		if (TREE_CODE (t) == INDIRECT_REF)
+		  t = TREE_OPERAND (t, 0);
+		if (TREE_CODE (t) != COMPONENT_REF)
+		  {
+		    if (VAR_P (t)
+			&& DECL_LANG_SPECIFIC (t)
+			&& DECL_OMP_PRIVATIZED_MEMBER (t))
+		      OMP_CLAUSE_DECL (nc) = t;
+		    break;
+		  }
+		tree v = t;
+		while (v)
+		  switch (TREE_CODE (v))
+		    {
+		    case COMPONENT_REF:
+		    case MEM_REF:
+		    case INDIRECT_REF:
+		    CASE_CONVERT:
+		    case POINTER_PLUS_EXPR:
+		      v = TREE_OPERAND (v, 0);
+		      continue;
+		    case PARM_DECL:
+		      if (DECL_CONTEXT (v) == current_function_decl
+			  && DECL_ARTIFICIAL (v)
+			  && DECL_NAME (v) == this_identifier)
+			OMP_CLAUSE_DECL (nc) = TREE_OPERAND (t, 1);
+		      /* FALLTHRU */
+		    default:
+		      v = NULL_TREE;
+		      break;
+		    }
+	      }
+	    else if (VAR_P (OMP_CLAUSE_DECL (oc))
+		     && DECL_HAS_VALUE_EXPR_P (OMP_CLAUSE_DECL (oc))
+		     && DECL_ARTIFICIAL (OMP_CLAUSE_DECL (oc))
+		     && DECL_LANG_SPECIFIC (OMP_CLAUSE_DECL (oc))
+		     && DECL_OMP_PRIVATIZED_MEMBER (OMP_CLAUSE_DECL (oc)))
+	      {
+		tree decl = OMP_CLAUSE_DECL (nc);
+		if (TREE_CODE (decl) == INDIRECT_REF)
+		  decl = TREE_OPERAND (decl, 0);
+		if (VAR_P (decl))
+		  {
+		    if (!DECL_LANG_SPECIFIC (decl))
+		      retrofit_lang_decl (decl);
+		    DECL_OMP_PRIVATIZED_MEMBER (decl) = 1;
+		    OMP_CLAUSE_DECL (nc) = decl;
+		  }
+	      }
+	    break;
+	  default:
+	    break;
+	  }
     }
 
   new_clauses = nreverse (new_clauses);
   if (!declare_simd)
-    new_clauses = finish_omp_clauses (new_clauses);
+    new_clauses = finish_omp_clauses (new_clauses, allow_fields);
   return new_clauses;
 }
 
@@ -13676,7 +13745,7 @@  tsubst_omp_for_iterator (tree t, int i,
 	{
 	  c = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE);
 	  OMP_CLAUSE_DECL (c) = decl;
-	  c = finish_omp_clauses (c);
+	  c = finish_omp_clauses (c, false);
 	  if (c)
 	    {
 	      OMP_CLAUSE_CHAIN (c) = *clauses;
@@ -14137,20 +14206,24 @@  tsubst_expr (tree t, tree args, tsubst_f
       break;
 
     case OMP_PARALLEL:
-      tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false,
+      r = push_omp_privatization_clauses ();
+      tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false, true,
 				args, complain, in_decl);
       stmt = begin_omp_parallel ();
       RECUR (OMP_PARALLEL_BODY (t));
       OMP_PARALLEL_COMBINED (finish_omp_parallel (tmp, stmt))
 	= OMP_PARALLEL_COMBINED (t);
+      pop_omp_privatization_clauses (r);
       break;
 
     case OMP_TASK:
-      tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false,
+      r = push_omp_privatization_clauses ();
+      tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false, true,
 				args, complain, in_decl);
       stmt = begin_omp_task ();
       RECUR (OMP_TASK_BODY (t));
       finish_omp_task (tmp, stmt);
+      pop_omp_privatization_clauses (r);
       break;
 
     case OMP_FOR:
@@ -14165,7 +14238,8 @@  tsubst_expr (tree t, tree args, tsubst_f
 	tree incrv = NULL_TREE;
 	int i;
 
-	clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false,
+	r = push_omp_privatization_clauses ();
+	clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false, true,
 				      args, complain, in_decl);
 	if (OMP_FOR_INIT (t) != NULL_TREE)
 	  {
@@ -14206,13 +14280,15 @@  tsubst_expr (tree t, tree args, tsubst_f
 	  }
 
 	add_stmt (finish_omp_structured_block (stmt));
+	pop_omp_privatization_clauses (r);
       }
       break;
 
     case OMP_SECTIONS:
     case OMP_SINGLE:
     case OMP_TEAMS:
-      tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false,
+      r = push_omp_privatization_clauses ();
+      tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, true,
 				args, complain, in_decl);
       stmt = push_stmt_list ();
       RECUR (OMP_BODY (t));
@@ -14222,11 +14298,12 @@  tsubst_expr (tree t, tree args, tsubst_f
       OMP_BODY (t) = stmt;
       OMP_CLAUSES (t) = tmp;
       add_stmt (t);
+      pop_omp_privatization_clauses (r);
       break;
 
     case OMP_TARGET_DATA:
     case OMP_TARGET:
-      tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false,
+      tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, false,
 				args, complain, in_decl);
       keep_next_level (true);
       stmt = begin_omp_structured_block ();
@@ -14241,7 +14318,7 @@  tsubst_expr (tree t, tree args, tsubst_f
       break;
 
     case OMP_TARGET_UPDATE:
-      tmp = tsubst_omp_clauses (OMP_TARGET_UPDATE_CLAUSES (t), false,
+      tmp = tsubst_omp_clauses (OMP_TARGET_UPDATE_CLAUSES (t), false, false,
 				args, complain, in_decl);
       t = copy_node (t);
       OMP_TARGET_UPDATE_CLAUSES (t) = tmp;
--- gcc/cp/cp-tree.h.jj	2015-05-26 20:38:50.000000000 +0200
+++ gcc/cp/cp-tree.h	2015-05-29 17:59:07.503038164 +0200
@@ -2023,6 +2023,7 @@  struct GTY(()) lang_decl_base {
   unsigned repo_available_p : 1;	   /* var or fn */
   unsigned threadprivate_or_deleted_p : 1; /* var or fn */
   unsigned anticipated_p : 1;		   /* fn, type or template */
+  /* Reused as DECL_OMP_PRIVATIZED_MEMBER in  var */
   unsigned friend_attr : 1;		   /* fn, type or template */
   unsigned template_conv_p : 1;		   /* var or template */
   unsigned odr_used : 1;		   /* var or fn */
@@ -3307,6 +3308,11 @@  more_aggr_init_expr_args_p (const aggr_i
   (DECL_LANG_SPECIFIC (TYPE_FUNCTION_OR_TEMPLATE_DECL_CHECK (NODE)) \
    ->u.base.anticipated_p)
 
+/* True for artificial decls added for OpenMP privatized non-static
+   data members.  */
+#define DECL_OMP_PRIVATIZED_MEMBER(NODE) \
+  (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.anticipated_p)
+
 /* Nonzero if NODE is a FUNCTION_DECL which was declared as a friend
    within a class but has not been declared in the surrounding scope.
    The function is invisible except via argument dependent lookup.  */
@@ -5988,7 +5994,11 @@  extern void note_decl_for_pch			(tree);
 extern tree omp_reduction_id			(enum tree_code, tree, tree);
 extern tree cp_remove_omp_priv_cleanup_stmt	(tree *, int *, void *);
 extern void cp_check_omp_declare_reduction	(tree);
-extern tree finish_omp_clauses			(tree);
+extern tree finish_omp_clauses			(tree, bool);
+extern tree push_omp_privatization_clauses	(void);
+extern void pop_omp_privatization_clauses	(tree);
+extern void save_omp_privatization_clauses	(vec<tree> &);
+extern void restore_omp_privatization_clauses	(vec<tree> &);
 extern void finish_omp_threadprivate		(tree);
 extern tree begin_omp_structured_block		(void);
 extern tree finish_omp_structured_block		(tree);
@@ -6372,6 +6382,7 @@  extern tree cxx_omp_clause_assign_op		(t
 extern tree cxx_omp_clause_dtor			(tree, tree);
 extern void cxx_omp_finish_clause		(tree, gimple_seq *);
 extern bool cxx_omp_privatize_by_reference	(const_tree);
+extern bool cxx_omp_disregard_value_expr	(tree, bool);
 
 /* in name-lookup.c */
 extern void suggest_alternatives_for            (location_t, tree);
--- gcc/cp/cp-objcp-common.h.jj	2015-04-24 12:32:02.000000000 +0200
+++ gcc/cp/cp-objcp-common.h	2015-05-28 18:53:08.820029943 +0200
@@ -150,6 +150,8 @@  extern void cp_common_init_ts (void);
 #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE cxx_omp_privatize_by_reference
 #undef LANG_HOOKS_OMP_MAPPABLE_TYPE
 #define LANG_HOOKS_OMP_MAPPABLE_TYPE cp_omp_mappable_type
+#undef LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR
+#define LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR cxx_omp_disregard_value_expr
 
 #undef LANG_HOOKS_EH_USE_CXA_END_CLEANUP
 #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP true
--- gcc/cp/semantics.c.jj	2015-05-27 16:33:16.000000000 +0200
+++ gcc/cp/semantics.c	2015-06-02 18:36:34.211477608 +0200
@@ -77,6 +77,11 @@  static tree maybe_convert_cond (tree);
 static tree finalize_nrv_r (tree *, int *, void *);
 static tree capture_decltype (tree);
 
+/* Used for OpenMP non-static data member privatization.  */
+
+static hash_map<tree, tree> *omp_private_member_map;
+static vec<tree> omp_private_member_vec;
+
 
 /* Deferred Access Checking Overview
    ---------------------------------
@@ -1716,6 +1721,8 @@  tree
 finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
 {
   gcc_assert (TREE_CODE (decl) == FIELD_DECL);
+  bool try_omp_private = !object && omp_private_member_map;
+  tree ret;
 
   if (!object)
     {
@@ -1767,17 +1774,17 @@  finish_non_static_data_member (tree decl
 	  type = cp_build_qualified_type (type, quals);
 	}
 
-      return (convert_from_reference
+      ret = (convert_from_reference
 	      (build_min (COMPONENT_REF, type, object, decl, NULL_TREE)));
     }
   /* If PROCESSING_TEMPLATE_DECL is nonzero here, then
      QUALIFYING_SCOPE is also non-null.  Wrap this in a SCOPE_REF
      for now.  */
   else if (processing_template_decl)
-    return build_qualified_name (TREE_TYPE (decl),
-				 qualifying_scope,
-				 decl,
-				 /*template_p=*/false);
+    ret = build_qualified_name (TREE_TYPE (decl),
+				qualifying_scope,
+				decl,
+				/*template_p=*/false);
   else
     {
       tree access_type = TREE_TYPE (object);
@@ -1794,11 +1801,18 @@  finish_non_static_data_member (tree decl
 				     &binfo);
 	}
 
-      return build_class_member_access_expr (object, decl,
-					     /*access_path=*/NULL_TREE,
-					     /*preserve_reference=*/false,
-					     tf_warning_or_error);
+      ret = build_class_member_access_expr (object, decl,
+					    /*access_path=*/NULL_TREE,
+					    /*preserve_reference=*/false,
+					    tf_warning_or_error);
+    }
+  if (try_omp_private)
+    {
+      tree *v = omp_private_member_map->get (decl);
+      if (v)
+	ret = convert_from_reference (*v);
     }
+  return ret;
 }
 
 /* If we are currently parsing a template and we encountered a typedef
@@ -5296,7 +5310,7 @@  finish_omp_reduction_clause (tree c, boo
    Remove any elements from the list that are invalid.  */
 
 tree
-finish_omp_clauses (tree clauses)
+finish_omp_clauses (tree clauses, bool allow_fields)
 {
   bitmap_head generic_head, firstprivate_head, lastprivate_head;
   bitmap_head aligned_head;
@@ -5314,21 +5328,26 @@  finish_omp_clauses (tree clauses)
   for (pc = &clauses, c = clauses; c ; c = *pc)
     {
       bool remove = false;
+      bool field_ok = false;
 
       switch (OMP_CLAUSE_CODE (c))
 	{
 	case OMP_CLAUSE_SHARED:
 	  goto check_dup_generic;
 	case OMP_CLAUSE_PRIVATE:
+	  field_ok = allow_fields;
 	  goto check_dup_generic;
 	case OMP_CLAUSE_REDUCTION:
+	  field_ok = allow_fields;
 	  goto check_dup_generic;
 	case OMP_CLAUSE_COPYPRIVATE:
 	  copyprivate_seen = true;
+	  field_ok = allow_fields;
 	  goto check_dup_generic;
 	case OMP_CLAUSE_COPYIN:
 	  goto check_dup_generic;
 	case OMP_CLAUSE_LINEAR:
+	  field_ok = allow_fields;
 	  t = OMP_CLAUSE_DECL (c);
 	  if (!type_dependent_expression_p (t))
 	    {
@@ -5391,7 +5410,8 @@  finish_omp_clauses (tree clauses)
 	  goto check_dup_generic;
 	check_dup_generic:
 	  t = OMP_CLAUSE_DECL (c);
-	  if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL)
+	  if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL
+	      && (!field_ok || TREE_CODE (t) != FIELD_DECL))
 	    {
 	      if (processing_template_decl)
 		break;
@@ -5412,11 +5432,70 @@  finish_omp_clauses (tree clauses)
 	    }
 	  else
 	    bitmap_set_bit (&generic_head, DECL_UID (t));
+	  if (!field_ok)
+	    break;
+	handle_field_decl:
+	  if (!remove && TREE_CODE (t) == FIELD_DECL)
+	    {
+	      tree m = finish_non_static_data_member (t, NULL_TREE, NULL_TREE);
+	      if (m == error_mark_node)
+		{
+		  remove = true;
+		  break;
+		}
+	      if (!omp_private_member_map)
+		omp_private_member_map = new hash_map<tree, tree>;
+	      if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+		{
+		  gcc_assert (TREE_CODE (m) == INDIRECT_REF);
+		  m = TREE_OPERAND (m, 0);
+		}
+	      tree &v = omp_private_member_map->get_or_insert (t);
+	      if (v == NULL_TREE)
+		{
+		  v = create_temporary_var (TREE_TYPE (m));
+		  if (!DECL_LANG_SPECIFIC (v))
+		    retrofit_lang_decl (v);
+		  DECL_OMP_PRIVATIZED_MEMBER (v) = 1;
+		  SET_DECL_VALUE_EXPR (v, m);
+		  DECL_HAS_VALUE_EXPR_P (v) = 1;
+		  omp_private_member_vec.safe_push (t);
+		}
+	      OMP_CLAUSE_DECL (c) = v;
+	    }
+	  else if (!remove
+		   && VAR_P (t)
+		   && DECL_HAS_VALUE_EXPR_P (t)
+		   && DECL_ARTIFICIAL (t)
+		   && DECL_LANG_SPECIFIC (t)
+		   && DECL_OMP_PRIVATIZED_MEMBER (t))
+	    {
+	      tree f = DECL_VALUE_EXPR (t);
+	      if (TREE_CODE (f) == INDIRECT_REF)
+		f = TREE_OPERAND (f, 0);
+	      if (TREE_CODE (f) == COMPONENT_REF)
+		{
+		  f = TREE_OPERAND (f, 1);
+		  gcc_assert (TREE_CODE (f) == FIELD_DECL);
+		  if (!omp_private_member_map)
+		    omp_private_member_map = new hash_map<tree, tree>;
+		  tree &v = omp_private_member_map->get_or_insert (f);
+		  if (v == NULL_TREE)
+		    {
+		      v = t;
+		      omp_private_member_vec.safe_push (f);
+		      /* Signal that we don't want to create
+			 DECL_EXPR for this dummy var.  */
+		      omp_private_member_vec.safe_push (integer_zero_node);
+		    }
+		}
+	    }
 	  break;
 
 	case OMP_CLAUSE_FIRSTPRIVATE:
 	  t = OMP_CLAUSE_DECL (c);
-	  if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL)
+	  if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL
+	      && (!allow_fields || TREE_CODE (t) != FIELD_DECL))
 	    {
 	      if (processing_template_decl)
 		break;
@@ -5434,11 +5513,12 @@  finish_omp_clauses (tree clauses)
 	    }
 	  else
 	    bitmap_set_bit (&firstprivate_head, DECL_UID (t));
-	  break;
+	  goto handle_field_decl;
 
 	case OMP_CLAUSE_LASTPRIVATE:
 	  t = OMP_CLAUSE_DECL (c);
-	  if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL)
+	  if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL
+	      && (!allow_fields || TREE_CODE (t) != FIELD_DECL))
 	    {
 	      if (processing_template_decl)
 		break;
@@ -5456,7 +5536,7 @@  finish_omp_clauses (tree clauses)
 	    }
 	  else
 	    bitmap_set_bit (&lastprivate_head, DECL_UID (t));
-	  break;
+	  goto handle_field_decl;
 
 	case OMP_CLAUSE_IF:
 	  t = OMP_CLAUSE_IF_EXPR (c);
@@ -6057,6 +6137,7 @@  finish_omp_clauses (tree clauses)
 	  need_implicitly_determined = true;
 	  break;
 	case OMP_CLAUSE_REDUCTION:
+	case OMP_CLAUSE_LINEAR:
 	  need_implicitly_determined = true;
 	  break;
 	case OMP_CLAUSE_COPYPRIVATE:
@@ -6166,8 +6247,25 @@  finish_omp_clauses (tree clauses)
 	    }
 	  if (share_name)
 	    {
-	      error ("%qE is predetermined %qs for %qs",
-		     t, share_name, omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+	      tree pt = t;
+	      if (VAR_P (t)
+		  && DECL_HAS_VALUE_EXPR_P (t)
+		  && DECL_ARTIFICIAL (t)
+		  && DECL_LANG_SPECIFIC (t)
+		  && DECL_OMP_PRIVATIZED_MEMBER (t))
+		{
+		  tree f = DECL_VALUE_EXPR (t);
+		  if (TREE_CODE (f) == INDIRECT_REF)
+		    f = TREE_OPERAND (f, 0);
+		  if (TREE_CODE (f) == COMPONENT_REF)
+		    {
+		      f = TREE_OPERAND (f, 1);
+		      gcc_assert (TREE_CODE (f) == FIELD_DECL);
+		      pt = f;
+		    }
+		}
+	      error ("%qE is predetermined %qs for %qs", pt, share_name,
+		     omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
 	      remove = true;
 	    }
 	}
@@ -6205,6 +6303,108 @@  finish_omp_clauses (tree clauses)
   return clauses;
 }
 
+/* Start processing OpenMP clauses that can include any
+   privatization clauses for non-static data members.  */
+
+tree
+push_omp_privatization_clauses (void)
+{
+  if (omp_private_member_map)
+    omp_private_member_vec.safe_push (error_mark_node);
+  return push_stmt_list ();
+}
+
+/* Revert remapping of any non-static data members since
+   the last push_omp_privatization_clauses () call.  */
+
+void
+pop_omp_privatization_clauses (tree stmt)
+{
+  stmt = pop_stmt_list (stmt);
+  if (omp_private_member_map)
+    {
+      while (!omp_private_member_vec.is_empty ())
+	{
+	  tree t = omp_private_member_vec.pop ();
+	  if (t == error_mark_node)
+	    {
+	      add_stmt (stmt);
+	      return;
+	    }
+	  bool no_decl_expr = t == integer_zero_node;
+	  if (no_decl_expr)
+	    t = omp_private_member_vec.pop ();
+	  tree *v = omp_private_member_map->get (t);
+	  gcc_assert (v);
+	  if (!no_decl_expr)
+	    add_decl_expr (*v);
+	  omp_private_member_map->remove (t);
+	}
+      delete omp_private_member_map;
+      omp_private_member_map = NULL;
+    }
+  add_stmt (stmt);
+}
+
+/* Remember OpenMP privatization clauses mapping and clear it.
+   Used for lambdas.  */
+
+void
+save_omp_privatization_clauses (vec<tree> &save)
+{
+  save = vNULL;
+  if (!omp_private_member_map)
+    return;
+  while (!omp_private_member_vec.is_empty ())
+    {
+      tree t = omp_private_member_vec.pop ();
+      if (t == error_mark_node)
+	{
+	  save.safe_push (t);
+	  continue;
+	}
+      tree n = t;
+      if (t == integer_zero_node)
+	t = omp_private_member_vec.pop ();
+      tree *v = omp_private_member_map->get (t);
+      gcc_assert (v);
+      save.safe_push (*v);
+      save.safe_push (t);
+      if (n != t)
+	save.safe_push (n);
+    }
+  delete omp_private_member_map;
+  omp_private_member_map = NULL;
+}
+
+/* Restore OpenMP privatization clauses mapping saved by the
+   above function.  */
+
+void
+restore_omp_privatization_clauses (vec<tree> &save)
+{
+  gcc_assert (omp_private_member_vec.is_empty ());
+  if (save.is_empty ())
+    return;
+  omp_private_member_map = new hash_map <tree, tree>;
+  while (!save.is_empty ())
+    {
+      tree t = save.pop ();
+      tree n = t;
+      if (t != error_mark_node)
+	{
+	  if (t == integer_zero_node)
+	    t = save.pop ();
+	  tree &v = omp_private_member_map->get_or_insert (t);
+	  v = save.pop ();
+	}
+      omp_private_member_vec.safe_push (t);
+      if (n != t)
+	omp_private_member_vec.safe_push (n);
+    }
+  save.release ();
+}
+
 /* For all variables in the tree_list VARS, mark them as thread local.  */
 
 void
@@ -6954,7 +7154,7 @@  finish_omp_for (location_t locus, enum t
       OMP_CLAUSE_OPERAND (c, 0)
 	= cilk_for_number_of_iterations (omp_for);
       OMP_CLAUSE_CHAIN (c) = clauses;
-      OMP_PARALLEL_CLAUSES (omp_par) = finish_omp_clauses (c);
+      OMP_PARALLEL_CLAUSES (omp_par) = finish_omp_clauses (c, false);
       add_stmt (omp_par);
       return omp_par;
     }
--- gcc/testsuite/g++.dg/gomp/clause-1.C.jj	2015-04-24 12:31:59.000000000 +0200
+++ gcc/testsuite/g++.dg/gomp/clause-1.C	2015-05-29 19:54:42.816300190 +0200
@@ -9,22 +9,22 @@  struct T
 
 void T::test()
 {
-  #pragma omp parallel private(n)	// { dg-error "T::n" }
+  #pragma omp parallel private(n)
     n = 1;
 
   #pragma omp parallel shared(n)	// { dg-error "T::n" }
     n = 1;
 
-  #pragma omp parallel firstprivate(n)	// { dg-error "T::n" }
+  #pragma omp parallel firstprivate(n)
     n = 1;
 
-  #pragma omp sections lastprivate(n)	// { dg-error "T::n" }
+  #pragma omp sections lastprivate(n)
     { n = 1; }
 
-  #pragma omp parallel reduction(+:n)	// { dg-error "T::n" }
+  #pragma omp parallel reduction(+:n)
     n = 1;
 
-  #pragma omp single copyprivate(n)	// { dg-error "T::n" }
+  #pragma omp single copyprivate(n)
     n = 1;
 
   #pragma omp parallel copyin(n)	// { dg-error "T::n" }
--- gcc/testsuite/g++.dg/gomp/member-1.C.jj	2015-06-01 17:48:36.239267537 +0200
+++ gcc/testsuite/g++.dg/gomp/member-1.C	2015-06-01 12:44:20.000000000 +0200
@@ -0,0 +1,214 @@ 
+struct T { T () {}; virtual ~T () {}; int t; };
+struct S : virtual public T { int a; void foo (); };
+template <typename T>
+struct U { U () {}; virtual ~U () {}; T t; };
+template <typename T>
+struct V : virtual public U<T> { T a; void foo (); };
+
+void
+S::foo ()
+{
+#pragma omp parallel firstprivate (a, t)
+  {
+    int *q1 = &a;
+    int *q2 = &this->a;
+    int q3 = a;
+    int q4 = this->a;
+    int *q5 = &t;
+    int *q6 = &this->t;
+    int q7 = t;
+    int q8 = this->t;
+    int q9 = T::t;
+    int q10 = this->T::t;
+    int &q11 = a;
+    int &q12 = this->a;
+    int &q13 = t;
+    int &q14 = this->t;
+    int &q15 = S::a;
+    int &q16 = this->S::a;
+    int &q17 = T::t;
+    int &q18 = this->T::t;
+  }
+#pragma omp parallel private (a, t)
+  {
+    a = 7;
+    S::a += 9;
+    t = 10;
+    T::t += 11;
+  }
+#pragma omp parallel
+  {
+  #pragma omp sections lastprivate (S::a, T::t)
+    {
+    #pragma omp section
+      {
+	S::a = 6;
+	T::t = 8;
+      }
+    }
+  }
+#pragma omp parallel
+  {
+  #pragma omp for firstprivate (a, t) lastprivate (a, t)
+    for (int i = 0; i < 10; i++)
+      {
+	int q19 = a + t;
+	if (i == 9)
+	  {
+	    a = i;
+	    T::t = i + 2;
+	  }
+      }
+  }
+#pragma omp sections lastprivate (a, t)
+  {
+  #pragma omp section
+    {
+      a = 5;
+      t = 6;
+    }
+  }
+#pragma omp for firstprivate (a, t) lastprivate (a, t)
+  for (int i = 0; i < 10; i++)
+    {
+      int q20 = a + t;
+      if (i == 9)
+	{
+	  a = i;
+	  T::t = i + 2;
+	}
+    }
+#pragma omp parallel sections lastprivate (a, t)
+  {
+  #pragma omp section
+    {
+      a = 5;
+      t = 6;
+    }
+  }
+#pragma omp parallel
+  {
+    #pragma omp task firstprivate (a, t)
+    {
+      S::a++;
+      t++;
+    }
+  }
+#pragma omp parallel
+  {
+    #pragma omp taskloop firstprivate (a, t) lastprivate (t)
+    for (int i = 0; i < a; i++)
+      t++;
+  }
+#pragma omp taskloop firstprivate (a, t) lastprivate (t)
+  for (int i = 0; i < a; i++)
+    t++;
+}
+
+template <typename T>
+void
+V<T>::foo ()
+{
+#pragma omp parallel firstprivate (a, U<T>::t)
+  {
+    int *q1 = &a;
+    int *q2 = &this->a;
+    int q3 = a;
+    int q4 = this->a;
+    int *q5 = &(U<T>::t);
+    int *q6 = &this->U<T>::t;
+    int q7 = U<T>::t;
+    int q8 = this->U<T>::t;
+    int q9 = U<T>::t;
+    int q10 = this->U<T>::t;
+    int &q11 = a;
+    int &q12 = this->a;
+    int &q13 = U<T>::t;
+    int &q14 = this->U<T>::t;
+    int &q15 = V::a;
+    int &q16 = this->V::a;
+    int &q17 = U<T>::t;
+    int &q18 = this->U<T>::t;
+  }
+#pragma omp parallel private (a, U<T>::t)
+  {
+    a = 7;
+    V::a += 9;
+    U<T>::t = 10;
+    U<T>::t += 11;
+  }
+#pragma omp parallel
+  {
+  #pragma omp sections lastprivate (V::a, U<T>::t)
+    {
+    #pragma omp section
+      {
+	V::a = 6;
+	U<T>::t = 8;
+      }
+    }
+  }
+#pragma omp parallel
+  {
+  #pragma omp for firstprivate (a, U<T>::t) lastprivate (a, U<T>::t)
+    for (int i = 0; i < 10; i++)
+      {
+	int q19 = a + U<T>::t;
+	if (i == 9)
+	  {
+	    a = i;
+	    U<T>::t = i + 2;
+	  }
+      }
+  }
+#pragma omp sections lastprivate (a, U<T>::t)
+  {
+  #pragma omp section
+    {
+      a = 5;
+      U<T>::t = 6;
+    }
+  }
+#pragma omp for firstprivate (a, U<T>::t) lastprivate (a, U<T>::t)
+  for (int i = 0; i < 10; i++)
+    {
+      int q20 = a + U<T>::t;
+      if (i == 9)
+	{
+	  a = i;
+	  U<T>::t = i + 2;
+	}
+    }
+#pragma omp parallel sections lastprivate (a, U<T>::t)
+  {
+  #pragma omp section
+    {
+      a = 5;
+      U<T>::t = 6;
+    }
+  }
+#pragma omp parallel
+  {
+    #pragma omp task firstprivate (a, U<T>::t)
+    {
+      V::a++;
+      U<T>::t++;
+    }
+  }
+#pragma omp parallel
+  {
+    #pragma omp taskloop firstprivate (a, U<T>::t) lastprivate (U<T>::t)
+    for (int i = 0; i < a; i++)
+      U<T>::t++;
+  }
+#pragma omp taskloop firstprivate (a, U<T>::t) lastprivate (U<T>::t)
+  for (int i = 0; i < a; i++)
+    U<T>::t++;
+}
+
+void
+bar ()
+{
+  V<int> v;
+  v.foo ();
+}
--- gcc/testsuite/g++.dg/gomp/member-2.C.jj	2015-06-02 17:54:10.243463528 +0200
+++ gcc/testsuite/g++.dg/gomp/member-2.C	2015-06-02 17:46:48.000000000 +0200
@@ -0,0 +1,139 @@ 
+// { dg-do compile }
+// { dg-options "-fopenmp" }
+
+int d;
+
+struct A
+{
+  A () : a(2), b(3), c(d) {}
+  int a;
+  A (const A &);
+  A &operator= (const A &);
+  const A &operator= (const A &) const;
+  mutable int b;
+  int &c;
+};
+
+struct B : public A
+{
+  B () : h(5) {}
+  ~B ();
+  B (const B &);
+  A e;
+  mutable A f;
+  const A g;
+  const int h;
+  int m1 ();
+  int m2 ();
+  int m3 () const;
+  int m4 () const;
+};
+
+int
+B::m1 ()
+{
+  #pragma omp parallel private (a, b, c, e, f, g)
+    ;
+  #pragma omp parallel firstprivate (a, b, c, e, f, g)
+    ;
+  #pragma omp parallel for lastprivate (a, b, c, e, f, g)
+    for (int i = 0; i < 10; i++)
+      ;
+  #pragma omp simd linear (a, b, c : 1)
+    for (int i = 0; i < 10; i++)
+      {
+	a++;
+	b++;
+	c++;
+      }
+  return 0;
+}
+
+int
+B::m2 ()
+{
+  #pragma omp parallel private (h)	// { dg-error "is predetermined .shared. for .private." }
+    ;
+  #pragma omp parallel firstprivate (h)
+    ;
+  #pragma omp parallel for lastprivate (h)	// { dg-error "is predetermined .shared. for .lastprivate." }
+    for (int i = 0; i < 10; i++)
+      ;
+  #pragma omp simd linear (h : 1)	// { dg-error "is predetermined .shared. for .linear." }
+    for (int i = 0; i < 10; i++)
+      ;
+  #pragma omp parallel shared (a)	// { dg-error "is not a variable in clause" }
+    ;
+  #pragma omp parallel shared (b)	// { dg-error "is not a variable in clause" }
+    ;
+  #pragma omp parallel shared (c)	// { dg-error "is not a variable in clause" }
+    ;
+  #pragma omp parallel shared (e)	// { dg-error "is not a variable in clause" }
+    ;
+  #pragma omp parallel shared (f)	// { dg-error "is not a variable in clause" }
+    ;
+  #pragma omp parallel shared (g)	// { dg-error "is not a variable in clause" }
+    ;
+  #pragma omp parallel shared (h)	// { dg-error "is not a variable in clause" }
+    ;
+  return 0;
+}
+
+int
+B::m3 () const
+{
+  #pragma omp parallel private (b, c, e, f, g)
+    ;
+  #pragma omp parallel firstprivate (b, c, e, f, g)
+    ;
+  #pragma omp parallel for lastprivate (b, c, e, f, g)
+    for (int i = 0; i < 10; i++)
+      ;
+  #pragma omp simd linear (b, c : 1)
+    for (int i = 0; i < 10; i++)
+      {
+	b++;
+	c++;
+      }
+  return 0;
+}
+
+int
+B::m4 () const
+{
+  #pragma omp parallel private (a)	// { dg-error "is predetermined .shared. for .private." }
+    ;
+  #pragma omp parallel firstprivate (a)
+    ;
+  #pragma omp parallel for lastprivate (a)	// { dg-error "is predetermined .shared. for .lastprivate." }
+    for (int i = 0; i < 10; i++)
+      ;
+  #pragma omp simd linear (a : 1)	// { dg-error "is predetermined .shared. for .linear." }
+    for (int i = 0; i < 10; i++)
+      ;
+  #pragma omp parallel private (h)	// { dg-error "is predetermined .shared. for .private." }
+    ;
+  #pragma omp parallel firstprivate (h)
+    ;
+  #pragma omp parallel for lastprivate (h)	// { dg-error "is predetermined .shared. for .lastprivate." }
+    for (int i = 0; i < 10; i++)
+      ;
+  #pragma omp simd linear (h : 1)	// { dg-error "is predetermined .shared. for .linear." }
+    for (int i = 0; i < 10; i++)
+      ;
+  #pragma omp parallel shared (a)	// { dg-error "is not a variable in clause" }
+    ;
+  #pragma omp parallel shared (b)	// { dg-error "is not a variable in clause" }
+    ;
+  #pragma omp parallel shared (c)	// { dg-error "is not a variable in clause" }
+    ;
+  #pragma omp parallel shared (e)	// { dg-error "is not a variable in clause" }
+    ;
+  #pragma omp parallel shared (f)	// { dg-error "is not a variable in clause" }
+    ;
+  #pragma omp parallel shared (g)	// { dg-error "is not a variable in clause" }
+    ;
+  #pragma omp parallel shared (h)	// { dg-error "is not a variable in clause" }
+    ;
+  return 0;
+}
--- libgomp/testsuite/libgomp.c++/taskloop-5.C.jj	2015-06-02 10:47:17.084575371 +0200
+++ libgomp/testsuite/libgomp.c++/taskloop-5.C	2015-06-02 11:32:01.695508086 +0200
@@ -0,0 +1,70 @@ 
+#include <omp.h>
+
+__attribute__((noinline, noclone)) void
+foo (int &b)
+{
+#pragma omp parallel
+  {
+    bool f = false;
+  #pragma omp taskloop firstprivate (b, f)
+    for (int i = 0; i < 30; i++)
+      {
+	int q = omp_get_thread_num ();
+	if (!f)
+	  {
+	    if (b != 2)
+	      __builtin_abort ();
+	  }
+	else if (b != 8 * q)
+	  __builtin_abort ();
+	b = 8 * q;
+	f = true;
+      }
+  }
+  int n;
+#pragma omp parallel
+  {
+    bool f = false;
+  #pragma omp taskloop firstprivate (f) lastprivate (b, n)
+    for (int i = 0; i < 30; i++)
+      {
+	int q = omp_get_thread_num ();
+	if (f && b != 8 * q)
+	  __builtin_abort ();
+	b = 8 * q;
+	n = q;
+	f = true;
+      }
+  }
+  if (b != 8 * n)
+    __builtin_abort ();
+  b = 9;
+#pragma omp parallel
+  {
+    bool f = false;
+  #pragma omp taskloop firstprivate (b, f) lastprivate (b, n)
+    for (int i = 0; i < 30; i++)
+      {
+	int q = omp_get_thread_num ();
+	if (!f)
+	  {
+	    if (b != 9)
+	      __builtin_abort ();
+	  }
+	else if (b != 11 * q)
+	  __builtin_abort ();
+	b = 11 * q;
+	n = q;
+	f = true;
+      }
+  }
+  if (b != 11 * n)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  int b = 2;
+  foo (b);
+}
--- libgomp/testsuite/libgomp.c++/member-1.C.jj	2015-06-02 09:22:41.257908605 +0200
+++ libgomp/testsuite/libgomp.c++/member-1.C	2015-06-02 14:53:42.000000000 +0200
@@ -0,0 +1,192 @@ 
+// { dg-do run }
+// { dg-options "-O2 -fopenmp" }
+
+#include <omp.h>
+
+struct R { R () {}; ~R () {}; int r; };
+struct T { T () {}; virtual ~T () {}; int t; };
+int c;
+struct A : public R, virtual public T { A () : b(c) {} int a; int &b; void m1 (); };
+
+void
+take (int &a, int &b, int &c, int &d)
+{
+  asm volatile ("" : : "g" (&a), "g" (&b), "g" (&c), "g" (&d) : "memory");
+}
+
+void
+A::m1 ()
+{
+  #pragma omp parallel private (a, r, T::t, A::b)
+  {
+    int q = omp_get_thread_num ();
+    a = q;
+    r = 2 * q;
+    t = 3 * q;
+    b = 4 * q;
+    take (a, r, t, b);
+    #pragma omp barrier
+    if (A::a != q || R::r != 2 * q || T::t != 3 * q || A::b != 4 * q)
+      __builtin_abort ();
+  }
+  a = 7;
+  r = 8;
+  t = 9;
+  b = 10;
+  #pragma omp parallel firstprivate (A::a, R::r, t, b)
+  {
+    int q = omp_get_thread_num ();
+    take (A::a, R::r, T::t, A::b);
+    if (a != 7 || r != 8 || t != 9 || b != 10)
+      __builtin_abort ();
+    A::a = 5 * q;
+    R::r = 6 * q;
+    T::t = 7 * q;
+    A::b = 8 * q;
+    take (a, r, t, b);
+    #pragma omp barrier
+    if (a != 5 * q || r != 6 * q || t != 7 * q || b != 8 * q)
+      __builtin_abort ();
+  }
+  bool f = false;
+  a = -5;
+  b = -4;
+  r = -3;
+  t = -2;
+  int n;
+  #pragma omp parallel for firstprivate (a, T::t, b, f) lastprivate (A::a, r, t, n)
+  for (int i = 0; i < omp_get_num_threads (); i++)
+    {
+      int q = omp_get_thread_num ();
+      if (!f)
+	{
+	  if (A::a != -5 || A::b != -4 || T::t != -2)
+	    __builtin_abort ();
+	}
+      else if (a != q || b != 2 * q || r != 3 * q || t != 4 * q)
+	__builtin_abort ();
+      take (a, r, t, b);
+      A::a = q;
+      A::b = 2 * q;
+      R::r = 3 * q;
+      T::t = 4 * q;
+      n = q;
+      f = true;
+    }
+  if (a != n || r != 3 * n || T::t != 4 * n)
+    __builtin_abort ();
+  b = 8;
+  #pragma omp parallel
+    #pragma omp single
+      for (int i = 0; i < 5; i++)
+	#pragma omp task firstprivate (t, b, n) private (a, R::r)
+	  {
+	    if (t != 4 * n || b != 8)
+	      __builtin_abort ();
+	    a = 9;
+	    r = 8;
+	    t = 12;
+	    b = 18;
+	    take (a, r, t, b);
+	    if (a != 9 || r != 8 || t != 12 || b != 18)
+	      __builtin_abort ();
+	  }
+  a = 1;
+  b = 2;
+  R::r = 3;
+  t = 4;
+  #pragma omp parallel private (f)
+    {
+      f = false;
+    #pragma omp single
+    #pragma omp taskloop firstprivate (r, T::t, b, f) lastprivate (a, t, b, n)
+      for (int i = 0; i < 30; i++)
+	{
+	  int q = omp_get_thread_num ();
+	  if (!f)
+	    {
+	      if (R::r != 3 || A::b != 2 || T::t != 4)
+		__builtin_abort ();
+	    }
+	  else if (a != 7 * q || b != 8 * q || r != 9 * q || t != 10 * q)
+	    __builtin_abort ();
+	  take (a, r, t, b);
+	  A::a = 7 * q;
+	  A::b = 8 * q;
+	  R::r = 9 * q;
+	  T::t = 10 * q;
+	  n = q;
+	  f = true;
+	}
+    }
+  if (a != 7 * n || b != 8 * n || t != 10 * n)
+    __builtin_abort ();
+  a = 1;
+  b = 2;
+  R::r = 3;
+  t = 4;
+  #pragma omp parallel private (f)
+    {
+      f = false;
+    #pragma omp single
+    #pragma omp taskloop firstprivate (r, T::t, b, A::a, f)
+      for (int i = 0; i < 30; i++)
+	{
+	  int q = omp_get_thread_num ();
+	  if (!f)
+	    {
+	      if (A::a != 1 || R::r != 3 || A::b != 2 || T::t != 4)
+		__builtin_abort ();
+	    }
+	  else if (a != 7 * q || b != 8 * q || r != 9 * q || t != 10 * q)
+	    __builtin_abort ();
+	  take (a, r, t, b);
+	  A::a = 7 * q;
+	  A::b = 8 * q;
+	  R::r = 9 * q;
+	  T::t = 10 * q;
+	  f = true;
+	}
+    }
+  #pragma omp parallel private (f)
+    {
+      f = false;
+    #pragma omp single
+    #pragma omp taskloop lastprivate (a, t, b, n)
+      for (int i = 0; i < 30; i++)
+	{
+	  int q = omp_get_thread_num ();
+	  if (f && (a != 7 * q || b != 8 * q || r != 9 * q || t != 10 * q))
+	    __builtin_abort ();
+	  take (a, r, t, b);
+	  A::a = 7 * q;
+	  A::b = 8 * q;
+	  R::r = 9 * q;
+	  T::t = 10 * q;
+	  n = q;
+	  f = true;
+	}
+    }
+  if (a != 7 * n || b != 8 * n || t != 10 * n)
+    __builtin_abort ();
+  #pragma omp parallel private (a, T::t, A::b, r)
+    {
+      int q = omp_get_thread_num ();
+      a = q;
+      b = 2 * q;
+      r = 3 * q;
+      t = 4 * q;
+      take (a, b, r, t);
+      #pragma omp single copyprivate (A::a, t, b, R::r)
+	n = q;
+      if (a != n || b != 2 * n || r != 3 * n || t != 4 * n)
+	__builtin_abort ();
+    }
+}
+
+int
+main ()
+{
+  A a;
+  a.m1 ();
+}
--- libgomp/testsuite/libgomp.c++/member-2.C.jj	2015-06-02 18:20:32.673808249 +0200
+++ libgomp/testsuite/libgomp.c++/member-2.C	2015-06-02 18:00:58.000000000 +0200
@@ -0,0 +1,197 @@ 
+// { dg-do run }
+// { dg-options "-O2 -fopenmp" }
+
+#include <omp.h>
+
+int c, d, e;
+struct R { R () {}; ~R () {}; int r; };
+template <typename Q>
+struct T { T () : t(d) {}; virtual ~T () {}; Q t; };
+template <typename Q>
+struct A : public R, virtual public T<Q> { A () : b(c), a(e) {} Q a; int &b; void m1 (); };
+
+void
+take (int &a, int &b, int &c, int &d)
+{
+  asm volatile ("" : : "g" (&a), "g" (&b), "g" (&c), "g" (&d) : "memory");
+}
+
+template <typename Q>
+void
+A<Q>::m1 ()
+{
+  #pragma omp parallel private (a, r, T<Q>::t, A::b)
+  {
+    int q = omp_get_thread_num ();
+    a = q;
+    r = 2 * q;
+    T<Q>::t = 3 * q;
+    b = 4 * q;
+    take (a, r, T<Q>::t, b);
+    #pragma omp barrier
+    if (A::a != q || R::r != 2 * q || T<Q>::t != 3 * q || A::b != 4 * q)
+      __builtin_abort ();
+  }
+  a = 7;
+  r = 8;
+  T<Q>::t = 9;
+  b = 10;
+  #pragma omp parallel firstprivate (A::a, R::r, T<Q>::t, b)
+  {
+    int q = omp_get_thread_num ();
+    take (A::a, R::r, T<Q>::t, A::b);
+    if (a != 7 || r != 8 || T<Q>::t != 9 || b != 10)
+      __builtin_abort ();
+    A::a = 5 * q;
+    R::r = 6 * q;
+    T<Q>::t = 7 * q;
+    A::b = 8 * q;
+    take (a, r, T<Q>::t, b);
+    #pragma omp barrier
+    if (a != 5 * q || r != 6 * q || T<Q>::t != 7 * q || b != 8 * q)
+      __builtin_abort ();
+  }
+  bool f = false;
+  a = -5;
+  b = -4;
+  r = -3;
+  T<Q>::t = -2;
+  int n;
+  #pragma omp parallel for firstprivate (a, T<Q>::t, b, f) lastprivate (A::a, r, T<Q>::t, n)
+  for (int i = 0; i < omp_get_num_threads (); i++)
+    {
+      int q = omp_get_thread_num ();
+      if (!f)
+	{
+	  if (A::a != -5 || A::b != -4 || T<Q>::t != -2)
+	    __builtin_abort ();
+	}
+      else if (a != q || b != 2 * q || r != 3 * q || T<Q>::t != 4 * q)
+	__builtin_abort ();
+      take (a, r, T<Q>::t, b);
+      A::a = q;
+      A::b = 2 * q;
+      R::r = 3 * q;
+      T<Q>::t = 4 * q;
+      n = q;
+      f = true;
+    }
+  if (a != n || r != 3 * n || T<Q>::t != 4 * n)
+    __builtin_abort ();
+  b = 8;
+  #pragma omp parallel
+    #pragma omp single
+      for (int i = 0; i < 5; i++)
+	#pragma omp task firstprivate (T<Q>::t, b, n) private (a, R::r)
+	  {
+	    if (T<Q>::t != 4 * n || b != 8)
+	      __builtin_abort ();
+	    a = 9;
+	    r = 8;
+	    T<Q>::t = 12;
+	    b = 18;
+	    take (a, r, T<Q>::t, b);
+	    if (a != 9 || r != 8 || T<Q>::t != 12 || b != 18)
+	      __builtin_abort ();
+	  }
+  a = 1;
+  b = 2;
+  R::r = 3;
+  T<Q>::t = 4;
+  #pragma omp parallel private (f)
+    {
+      f = false;
+    #pragma omp single
+    #pragma omp taskloop firstprivate (r, T<Q>::t, b, f) lastprivate (a, T<Q>::t, b, n)
+      for (int i = 0; i < 30; i++)
+	{
+	  int q = omp_get_thread_num ();
+	  if (!f)
+	    {
+	      if (R::r != 3 || A::b != 2 || T<Q>::t != 4)
+		__builtin_abort ();
+	    }
+	  else if (a != 7 * q || b != 8 * q || r != 9 * q || T<Q>::t != 10 * q)
+	    __builtin_abort ();
+	  take (a, r, T<Q>::t, b);
+	  A::a = 7 * q;
+	  A::b = 8 * q;
+	  R::r = 9 * q;
+	  T<Q>::t = 10 * q;
+	  n = q;
+	  f = true;
+	}
+    }
+  if (a != 7 * n || b != 8 * n || T<Q>::t != 10 * n)
+    __builtin_abort ();
+  a = 1;
+  b = 2;
+  R::r = 3;
+  T<Q>::t = 4;
+  #pragma omp parallel private (f)
+    {
+      f = false;
+    #pragma omp single
+    #pragma omp taskloop firstprivate (r, T<Q>::t, b, A::a, f)
+      for (int i = 0; i < 30; i++)
+	{
+	  int q = omp_get_thread_num ();
+	  if (!f)
+	    {
+	      if (A::a != 1 || R::r != 3 || A::b != 2 || T<Q>::t != 4)
+		__builtin_abort ();
+	    }
+	  else if (a != 7 * q || b != 8 * q || r != 9 * q || T<Q>::t != 10 * q)
+	    __builtin_abort ();
+	  take (a, r, T<Q>::t, b);
+	  A::a = 7 * q;
+	  A::b = 8 * q;
+	  R::r = 9 * q;
+	  T<Q>::t = 10 * q;
+	  f = true;
+	}
+    }
+  #pragma omp parallel private (f)
+    {
+      f = false;
+    #pragma omp single
+    #pragma omp taskloop lastprivate (a, T<Q>::t, b, n)
+      for (int i = 0; i < 30; i++)
+	{
+	  int q = omp_get_thread_num ();
+	  if (f && (a != 7 * q || b != 8 * q || r != 9 * q || T<Q>::t != 10 * q))
+	    __builtin_abort ();
+	  take (a, r, T<Q>::t, b);
+	  A::a = 7 * q;
+	  A::b = 8 * q;
+	  R::r = 9 * q;
+	  T<Q>::t = 10 * q;
+	  n = q;
+	  f = true;
+	}
+    }
+  if (a != 7 * n || b != 8 * n || T<Q>::t != 10 * n)
+    __builtin_abort ();
+  #pragma omp parallel private (a, T<Q>::t, A::b, r)
+    {
+      int q = omp_get_thread_num ();
+      a = q;
+      b = 2 * q;
+      r = 3 * q;
+      T<Q>::t = 4 * q;
+      take (a, b, r, T<Q>::t);
+      #pragma omp single copyprivate (A::a, T<Q>::t, b, R::r)
+	n = q;
+      if (a != n || b != 2 * n || r != 3 * n || T<Q>::t != 4 * n)
+	__builtin_abort ();
+    }
+}
+
+int
+main ()
+{
+  A<int> a;
+  a.m1 ();
+  A<int &> b;
+  b.m1 ();
+}