This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gomp] c++ ctors, dtors, and op=


Wherein basic stuff is shown to work.


r~



gcc/
        * gimplify.c (GOVD_SPECIALPRIVATE, GOVD_GLOBAL): Remove.
        (GOVD_LASTPRIVATE, GOVD_REDUCTION): New.
        (gimplify_deconstruct_omp_clauses): Use them.
        (omp_add_variable): Don't elide decls with constructors.
        (omp_notice_variable): Restrict SEEN propagation block to PRIVATE.
        (gimplify_reconstruct_omp_clauses_1): Rebuild LASTPRIVATE clauses.
        * hooks.h, hooks.c (hook_tree_tree_null): New.
        * langhooks-def.h (lhd_omp_assignment): Declare.
        (LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR): New.
        (LANG_HOOKS_OMP_CLAUSE_COPY_CTOR): New.
        (LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP): New.
        (LANG_HOOKS_OMP_CLAUSE_DTOR): New.
        (LANG_HOOKS_DECLS): Add them.
        * langhooks.c (lhd_omp_assignment): New.
        * langhooks.h (struct lang_hooks_for_decls): Add omp_clause_dtor,
        omp_clause_default_ctor, omp_clause_assign_op, omp_clause_copy_ctor.
        * omp-low.c (build_outer_var_ref): Remap the type to the inner context.
        (scan_sharing_clauses): Use OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE.
        (build_modify_expr): Remove.
        (expand_rec_input_clauses): Use new langhooks; return a dtor sequence;
        avoid copyin sequence for the master.
        (expand_lastprivate_clauses): Use omp_clause_assign_op.
        (expand_copyprivate_clauses): Likewise.
        (expand_send_clauses): USe OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE.
        (expand_omp_parallel): Emit dtor sequence.
        (expand_omp_for_1, expand_omp_sections): Likewise.
        (expand_omp_single_copy): Move expand_rec_input_clauses call ...
        (expand_omp_single): ... here.  Emit dtor sequence.
        * tree.h (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE): New.
gcc/cp/
        * cp-objcp-common.h (LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR): New.
        (LANG_HOOKS_OMP_CLAUSE_COPY_CTOR): New.
        (LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP): New.
        (LANG_HOOKS_OMP_CLAUSE_DTOR): New.
        * semantics.c (finish_omp_clauses): Look through arrays when
        looking up special member calls.  Also remove FIRSTPRIVATE when
        LASTPRIVATE fails.
        (cxx_omp_clause_default_ctor, cxx_omp_clause_copy_ctor): New.
        (cxx_omp_clause_assign_op): New.
        * cp-tree.h: Declare them.
gcc/testsuite/
        * g++.dg/gomp/clause-2.C: New.
libgomp/
        * testsuite/libgomp.c++/ctor-1.C: New.
        * testsuite/libgomp.c++/ctor-2.C: New.
        * testsuite/libgomp.c++/ctor-3.C: New.
        * testsuite/libgomp.c++/ctor-4.C: New.
        * testsuite/libgomp.c++/ctor-5.C: New.

Index: gcc/gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.135.4.36
diff -u -p -d -r2.135.4.36 gimplify.c
--- gcc/gimplify.c	22 Oct 2005 01:53:56 -0000	2.135.4.36
+++ gcc/gimplify.c	24 Oct 2005 03:47:49 -0000
@@ -56,9 +56,9 @@ enum gimplify_omp_var_data
   GOVD_SHARED = 2,
   GOVD_PRIVATE = 4,
   GOVD_FIRSTPRIVATE = 8,
-  GOVD_SPECIALPRIVATE = 16,
-  GOVD_LOCAL = 32,
-  GOVD_GLOBAL = 64
+  GOVD_LASTPRIVATE = 16,
+  GOVD_REDUCTION = 32,
+  GOVD_LOCAL = 64
 };
 
 struct gimplify_omp_ctx
@@ -4207,6 +4207,12 @@ omp_add_variable (struct gimplify_omp_ct
   unsigned int nflags;
   tree t;
 
+  /* Never elide decls whose type has TREE_ADDRESSABLE set.  This means
+     there are constructors involved somewhere.  */
+  if (TREE_ADDRESSABLE (TREE_TYPE (decl))
+      || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
+    flags |= GOVD_SEEN;
+
   n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
   if (n != NULL)
     {
@@ -4217,7 +4223,7 @@ omp_add_variable (struct gimplify_omp_ct
 	 FIRSTPRIVATE and LASTPRIVATE.  */
       nflags = n->value | flags;
       gcc_assert ((nflags & ~GOVD_SEEN)
-		  == (GOVD_FIRSTPRIVATE | GOVD_SPECIALPRIVATE));
+		  == (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE));
       n->value = nflags;
       return;
     }
@@ -4341,10 +4347,8 @@ omp_notice_variable (struct gimplify_omp
 
  do_outer:
   /* If the variable is private in the current context, then we don't
-     need to propagate anything to an outer context.  Note that FIRSTPRIVATE
-     isn't listed here because we want to propagate the SEEN bit back to
-     the outer context.  */
-  if (flags & (GOVD_PRIVATE | GOVD_SPECIALPRIVATE))
+     need to propagate anything to an outer context.  */
+  if (flags & GOVD_PRIVATE)
     return;
   if (ctx->outer_context)
     omp_notice_variable (ctx->outer_context, decl, in_code);
@@ -4420,8 +4424,16 @@ gimplify_deconstruct_omp_clauses (tree *
 	  break;
 
 	case OMP_CLAUSE_LASTPRIVATE:
+	  omp_add_variable (ctx, OMP_CLAUSE_DECL (clause),
+			    GOVD_LASTPRIVATE | GOVD_SEEN);
+	  if (outer_ctx)
+	    omp_notice_variable (outer_ctx, OMP_CLAUSE_DECL (clause), true);
+	  remove = true;
+	  break;
+
 	case OMP_CLAUSE_REDUCTION:
-	  omp_add_variable (ctx, OMP_CLAUSE_DECL (clause), GOVD_SPECIALPRIVATE);
+	  omp_add_variable (ctx, OMP_CLAUSE_DECL (clause),
+			    GOVD_REDUCTION | GOVD_SEEN);
 	  if (outer_ctx)
 	    omp_notice_variable (outer_ctx, OMP_CLAUSE_DECL (clause), true);
 	  break;
@@ -4484,7 +4496,18 @@ gimplify_reconstruct_omp_clauses_1 (spla
   else if (flags & GOVD_PRIVATE)
     code = OMP_CLAUSE_PRIVATE;
   else if (flags & GOVD_FIRSTPRIVATE)
-    code = OMP_CLAUSE_FIRSTPRIVATE;
+    {
+      if (flags & GOVD_LASTPRIVATE)
+	{
+	  clause = build1 (OMP_CLAUSE_LASTPRIVATE, void_type_node, decl);
+	  OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (clause) = 1;
+	  OMP_CLAUSE_CHAIN (clause) = *list_p;
+	  *list_p = clause;
+	}
+      code = OMP_CLAUSE_FIRSTPRIVATE;
+    }
+  else if (flags & GOVD_LASTPRIVATE)
+    code = OMP_CLAUSE_LASTPRIVATE;
   else
     return 0;
 
Index: gcc/hooks.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/hooks.c,v
retrieving revision 1.41.4.2
diff -u -p -d -r1.41.4.2 hooks.c
--- gcc/hooks.c	12 Jul 2005 14:20:19 -0000	1.41.4.2
+++ gcc/hooks.c	24 Oct 2005 03:47:50 -0000
@@ -256,6 +256,12 @@ hook_tree_tree_tree_bool_null (tree t0 A
   return NULL;
 }
 
+tree
+hook_tree_tree_null (tree t ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}
+
 /* Generic hook that takes a rtx and returns a NULL string.  */
 const char *
 hook_constcharptr_rtx_null (rtx r ATTRIBUTE_UNUSED)
Index: gcc/hooks.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/hooks.h,v
retrieving revision 1.41.4.2
diff -u -p -d -r1.41.4.2 hooks.h
--- gcc/hooks.h	12 Jul 2005 14:20:19 -0000	1.41.4.2
+++ gcc/hooks.h	24 Oct 2005 03:47:50 -0000
@@ -40,6 +40,7 @@ extern bool hook_bool_uintp_uintp_false 
 extern bool hook_bool_rtx_int_int_intp_false (rtx, int, int, int *);
 extern bool hook_bool_constcharptr_size_t_false (const char *, size_t);
 extern bool hook_bool_size_t_constcharptr_int_true (size_t, const char *, int);
+extern bool hook_bool_tree_tree_false (tree, tree);
 
 extern void hook_void_void (void);
 extern void hook_void_constcharptr (const char *);
@@ -53,19 +54,20 @@ extern int hook_int_rtx_0 (rtx);
 extern int hook_int_size_t_constcharptr_int_0 (size_t, const char *, int);
 extern int hook_int_void_no_regs (void);
 
+extern tree hook_tree_tree_null (tree);
+extern tree hook_tree_tree_tree_tree_3rd_identity (tree, tree, tree);
+extern tree hook_tree_tree_tree_bool_null (tree, tree, bool);
+
 extern unsigned hook_uint_uint_constcharptrptr_0 (unsigned, const char **);
 
 extern bool default_can_output_mi_thunk_no_vcall (tree, HOST_WIDE_INT,
 					   HOST_WIDE_INT, tree);
 
-extern bool hook_bool_tree_tree_false (tree, tree);
-
 extern rtx hook_rtx_rtx_identity (rtx);
 extern rtx hook_rtx_rtx_null (rtx);
 extern rtx hook_rtx_tree_int_null (tree, int);
-extern tree hook_tree_tree_tree_tree_3rd_identity (tree, tree, tree);
+
 extern const char *hook_constcharptr_tree_null (tree);
-extern tree hook_tree_tree_tree_bool_null (tree, tree, bool);
 extern const char *hook_constcharptr_rtx_null (rtx);
 extern const char *hook_constcharptr_tree_tree_null (tree, tree);
 extern const char *hook_constcharptr_int_tree_null (int, tree);
Index: gcc/langhooks-def.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/langhooks-def.h,v
retrieving revision 1.98.6.5
diff -u -p -d -r1.98.6.5 langhooks-def.h
--- gcc/langhooks-def.h	18 Oct 2005 19:06:57 -0000	1.98.6.5
+++ gcc/langhooks-def.h	24 Oct 2005 03:47:50 -0000
@@ -89,6 +89,7 @@ extern tree lhd_callgraph_analyze_expr (
 /* Declarations for tree gimplification hooks.  */
 extern int lhd_gimplify_expr (tree *, tree *, tree *);
 extern enum omp_clause_default_kind lhd_omp_predetermined_sharing (tree);
+extern tree lhd_omp_assignment (tree, tree);
 
 #define LANG_HOOKS_NAME			"GNU unknown"
 #define LANG_HOOKS_IDENTIFIER_SIZE	sizeof (struct lang_identifier)
@@ -242,6 +243,10 @@ extern tree lhd_make_node (enum tree_cod
 #define LANG_HOOKS_COMDAT_GROUP lhd_comdat_group
 #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE hook_bool_tree_false
 #define LANG_HOOKS_OMP_PREDETERMINED_SHARING lhd_omp_predetermined_sharing
+#define LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR hook_tree_tree_null
+#define LANG_HOOKS_OMP_CLAUSE_COPY_CTOR lhd_omp_assignment
+#define LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP lhd_omp_assignment
+#define LANG_HOOKS_OMP_CLAUSE_DTOR hook_tree_tree_null
 
 #define LANG_HOOKS_DECLS { \
   LANG_HOOKS_GLOBAL_BINDINGS_P, \
@@ -254,7 +259,11 @@ extern tree lhd_make_node (enum tree_cod
   LANG_HOOKS_DECL_OK_FOR_SIBCALL, \
   LANG_HOOKS_COMDAT_GROUP, \
   LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE, \
-  LANG_HOOKS_OMP_PREDETERMINED_SHARING \
+  LANG_HOOKS_OMP_PREDETERMINED_SHARING, \
+  LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR, \
+  LANG_HOOKS_OMP_CLAUSE_COPY_CTOR, \
+  LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP, \
+  LANG_HOOKS_OMP_CLAUSE_DTOR \
 }
 
 /* The whole thing.  The structure is defined in langhooks.h.  */
Index: gcc/langhooks.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/langhooks.c,v
retrieving revision 1.82.4.5
diff -u -p -d -r1.82.4.5 langhooks.c
--- gcc/langhooks.c	18 Oct 2005 19:06:57 -0000	1.82.4.5
+++ gcc/langhooks.c	24 Oct 2005 03:47:50 -0000
@@ -559,3 +559,11 @@ lhd_omp_predetermined_sharing (tree decl
 {
   return OMP_CLAUSE_DEFAULT_UNSPECIFIED;
 }
+
+/* Generate code to copy SRC to DST.  */
+
+tree
+lhd_omp_assignment (tree dst, tree src)
+{
+  return build2 (MODIFY_EXPR, void_type_node, dst, src);
+}
Index: gcc/langhooks.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/langhooks.h,v
retrieving revision 1.106.4.4
diff -u -p -d -r1.106.4.4 langhooks.h
--- gcc/langhooks.h	18 Oct 2005 19:06:57 -0000	1.106.4.4
+++ gcc/langhooks.h	24 Oct 2005 03:47:50 -0000
@@ -200,6 +200,20 @@ struct lang_hooks_for_decls
   /* Return sharing kind if OpenMP sharing attribute of DECL is
      predetermined, OMP_CLAUSE_DEFAULT_UNSPECIFIED otherwise.  */
   enum omp_clause_default_kind (*omp_predetermined_sharing) (tree);
+
+  /* Build and return code for a default constructor for DECL.  Return
+     NULL if nothing to be done.  */
+  tree (*omp_clause_default_ctor) (tree decl);
+
+  /* Build and return code for a copy constructor from SRC to DST.  */
+  tree (*omp_clause_copy_ctor) (tree dst, tree src);
+
+  /* Similarly, except use an assignment operator instead.  */
+  tree (*omp_clause_assign_op) (tree dst, tree src);
+
+  /* Build and return code destructing DECL.  Return NULL if nothing
+     to be done.  */
+  tree (*omp_clause_dtor) (tree decl);
 };
 
 /* Language-specific hooks.  See langhooks-def.h for defaults.  */
Index: gcc/omp-low.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/omp-low.c,v
retrieving revision 1.1.2.36
diff -u -p -d -r1.1.2.36 omp-low.c
--- gcc/omp-low.c	22 Oct 2005 01:53:56 -0000	1.1.2.36
+++ gcc/omp-low.c	24 Oct 2005 03:47:50 -0000
@@ -263,6 +263,8 @@ build_outer_var_ref (tree var, omp_conte
     {
       x = TREE_OPERAND (DECL_VALUE_EXPR (var), 0);
       x = build_outer_var_ref (x, ctx);
+      if (is_parallel_ctx (ctx))
+	x = fold_convert (remap_type (TREE_TYPE (x), &ctx->cb), x);
       x = build_fold_indirect_ref (x);
     }
   else if (is_parallel_ctx (ctx))
@@ -544,19 +546,20 @@ scan_sharing_clauses (tree clauses, omp_
 	      install_var_shared (decl, by_ref, ctx);
 	      break;
 	    }
-	  else
-	    /* We don't need to copy const scalar vars back.  */
-	    TREE_SET_CODE (c, OMP_CLAUSE_FIRSTPRIVATE);
+	  /* We don't need to copy const scalar vars back.  */
+	  TREE_SET_CODE (c, OMP_CLAUSE_FIRSTPRIVATE);
+	  goto do_private;
+
+	case OMP_CLAUSE_LASTPRIVATE:
+	  /* Let the corresponding firstprivate clause create the variable.  */
+	  if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
+	    break;
 	  /* FALLTHRU */
 
 	case OMP_CLAUSE_FIRSTPRIVATE:
-	case OMP_CLAUSE_LASTPRIVATE:
 	case OMP_CLAUSE_REDUCTION:
 	  decl = OMP_CLAUSE_DECL (c);
-	  /* Variables can be both firstprivate and lastprivate.
-	     Don't create duplicate fields or private variables.  */
-	  if (maybe_lookup_decl (decl, ctx))
-	    break;
+	do_private:
 	  if (is_variable_sized (decl))
 	    saw_var_sized = true;
 	  else if (is_parallel_ctx (ctx))
@@ -608,10 +611,12 @@ scan_sharing_clauses (tree clauses, omp_
 	  {
 	  case OMP_CLAUSE_PRIVATE:
 	  case OMP_CLAUSE_FIRSTPRIVATE:
-	  case OMP_CLAUSE_LASTPRIVATE:
 	  case OMP_CLAUSE_REDUCTION:
 	  case OMP_CLAUSE_SHARED:
 	    break;
+	  case OMP_CLAUSE_LASTPRIVATE:
+	    if (!OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
+	      break;
 	  default:
 	    continue;
 	  }
@@ -1019,33 +1024,6 @@ build_reduction_init (tree clause, tree 
     }
 }
 
-/* Generate code to copy SRC to DST.  In the case of variable sized types,
-   if we were to just build a MODIFY_EXPR the gimplifier would choose one
-   of the operands at random from which to draw the type size.  We can't
-   have that, since only one of them will be local.  */
-
-static tree
-build_modify_expr (tree dst, tree src, bool dst_local)
-{
-  tree t, args;
-
-  if (is_variable_sized (dst_local ? dst : src))
-    {
-      t = TYPE_SIZE_UNIT (TREE_TYPE (dst_local ? dst : src));
-      args = tree_cons (NULL_TREE, t, NULL_TREE);
-      t = build_fold_addr_expr (src);
-      args = tree_cons (NULL_TREE, t, args);
-      t = build_fold_addr_expr (dst);
-      args = tree_cons (NULL_TREE, t, args);
-      t = implicit_built_in_decls[BUILT_IN_MEMCPY];
-      t = build_function_call_expr (t, args);
-    }
-  else
-    t = build2 (MODIFY_EXPR, void_type_node, dst, src);
-
-  return t;
-}
-
 /* Initialize all entries of array VAR to value X.  */
 
 static void
@@ -1101,23 +1079,32 @@ array_reduction_init (tree var, tree x, 
 
 /* Generate code to implement the input clauses, FIRSTPRIVATE and COPYIN,
    from the receiver (aka child) side and initializers for REFERENCE_TYPE
-   private variables.  */
+   private variables.  Initialization statements go in ILIST, while calls
+   to destructors go in DLIST.  */
 
 static void
-expand_rec_input_clauses (tree clauses, tree *stmt_list, omp_context *ctx)
+expand_rec_input_clauses (tree clauses, tree *ilist, tree *dlist,
+			  omp_context *ctx)
 {
-  tree c;
+  tree_stmt_iterator diter;
+  tree c, dtor, copyin_seq, x;
   int pass;
 
+  /* Resolve private references for Fortran.  Note that C++ disallows
+     private references, so there's no need to worry about CTORs.  */
   for (c = ctx->block_vars; c; c = TREE_CHAIN (c))
     if (DECL_INITIAL (c))
       {
 	tree init = DECL_INITIAL (c);
 	DECL_INITIAL (c) = NULL;
 	init = build (MODIFY_EXPR, void_type_node, c, init);
-	gimplify_and_add (init, stmt_list);
+	gimplify_and_add (init, ilist);
       }
 
+  *dlist = alloc_stmt_list ();
+  diter = tsi_start (*dlist);
+  copyin_seq = NULL;
+
   /* Do all the fixed sized types in the first pass, and the variable sized
      types in the second pass.  This makes sure that the scalar arguments to
      the variable sized types are processed before we use them in the 
@@ -1127,14 +1114,14 @@ expand_rec_input_clauses (tree clauses, 
       for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
 	{
 	  enum tree_code c_kind = TREE_CODE (c);
-	  tree var, new_var, x;
+	  tree var, new_var;
 	  bool by_ref;
 
 	  switch (c_kind)
 	    {
 	    case OMP_CLAUSE_PRIVATE:
-	    case OMP_CLAUSE_LASTPRIVATE:
 	    case OMP_CLAUSE_FIRSTPRIVATE:
+	    case OMP_CLAUSE_LASTPRIVATE:
 	    case OMP_CLAUSE_COPYIN:
 	    case OMP_CLAUSE_REDUCTION:
 	      break;
@@ -1164,7 +1151,7 @@ expand_rec_input_clauses (tree clauses, 
 	      t = build_function_call_expr (t, args);
 	      t = fold_convert (TREE_TYPE (ptr), t);
 	      t = build2 (MODIFY_EXPR, void_type_node, ptr, t);
-	      gimplify_and_add (t, stmt_list);
+	      gimplify_and_add (t, ilist);
 	    }
 	  else if (pass != 0)
 	    continue;
@@ -1173,32 +1160,70 @@ expand_rec_input_clauses (tree clauses, 
 
 	  switch (TREE_CODE (c))
 	    {
+	    case OMP_CLAUSE_LASTPRIVATE:
+	      if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
+		break;
+	      /* FALLTHRU */
+
+	    case OMP_CLAUSE_PRIVATE:
+	      x = lang_hooks.decls.omp_clause_default_ctor (new_var);
+	      if (x)
+		gimplify_and_add (x, ilist);
+	      /* FALLTHRU */
+
+	    do_dtor:
+	      x = lang_hooks.decls.omp_clause_dtor (new_var);
+	      if (x)
+		{
+		  dtor = x;
+		  gimplify_stmt (&dtor);
+		  tsi_link_before (&diter, dtor, TSI_SAME_STMT);
+		}
+	      break;
+
 	    case OMP_CLAUSE_FIRSTPRIVATE:
 	      x = build_outer_var_ref (var, ctx);
+	      x = lang_hooks.decls.omp_clause_copy_ctor (new_var, x);
+	      gimplify_and_add (x, ilist);
+	      goto do_dtor;
 	      break;
 
 	    case OMP_CLAUSE_COPYIN:
 	      by_ref = use_pointer_for_field (var, false);
 	      x = build_receiver_ref (var, by_ref, ctx);
+	      x = lang_hooks.decls.omp_clause_assign_op (new_var, x);
+	      append_to_statement_list (x, &copyin_seq);
 	      break;
 
 	    case OMP_CLAUSE_REDUCTION:
 	      x = build_reduction_init (c, TREE_TYPE (new_var));
 	      if (TREE_CODE (TREE_TYPE (new_var)) == ARRAY_TYPE)
+		array_reduction_init (new_var, x, ilist);
+	      else
 		{
-		  array_reduction_init (new_var, x, stmt_list);
-		  continue;
+		  x = build2 (MODIFY_EXPR, void_type_node, new_var, x);
+		  gimplify_and_add (x, ilist);
 		}
 	      break;
 
 	    default:
-	      continue;
+	      gcc_unreachable ();
 	    }
-
-	  x = build_modify_expr (new_var, x, true);
-	  gimplify_and_add (x, stmt_list);
 	}
     }
+
+  /* The copyin sequence is not to be executed by the main thread, since
+     that would result in self-copies.  Perhaps not visible to scalars,
+     but it certainly is to C++ operator=.  */
+  if (copyin_seq)
+    {
+      x = built_in_decls[BUILT_IN_OMP_GET_THREAD_NUM];
+      x = build_function_call_expr (x, NULL);
+      x = build2 (NE_EXPR, boolean_type_node, x,
+		  build_int_cst (TREE_TYPE (x), 0));
+      x = build3 (COND_EXPR, void_type_node, x, copyin_seq, NULL);
+      gimplify_and_add (x, ilist);
+    }
 }
 
 /* Generate code to implement the LASTPRIVATE clauses.  This is used for
@@ -1244,7 +1269,7 @@ expand_lastprivate_clauses (tree clauses
       new_var = lookup_decl (var, ctx);
 
       x = build_outer_var_ref (var, ctx);
-      x = build_modify_expr (x, new_var, false);
+      x = lang_hooks.decls.omp_clause_assign_op (x, new_var);
       append_to_statement_list (x, &sub_list);
     }
 
@@ -1435,7 +1460,7 @@ expand_copyprivate_clauses (tree clauses
 	  ref = build_fold_indirect_ref (ref);
 	  var = build_fold_indirect_ref (var);
 	}
-      x = build2 (MODIFY_EXPR, void_type_node, var, ref);
+      x = lang_hooks.decls.omp_clause_assign_op (var, ref);
       gimplify_and_add (x, rlist);
     }
 }
@@ -1478,7 +1503,11 @@ expand_send_clauses (tree clauses, tree 
 
 	case OMP_CLAUSE_LASTPRIVATE:
 	  if (by_ref || is_reference (val))
-	    do_in = true;
+	    {
+	      if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
+		continue;
+	      do_in = true;
+	    }
 	  else
 	    do_out = true;
 	  break;
@@ -1660,9 +1689,10 @@ expand_omp_parallel (tree *stmt_p, omp_c
   body = BIND_EXPR_BODY (bind);
   BIND_EXPR_BODY (bind) = alloc_stmt_list ();
 
-  expand_rec_input_clauses (clauses, &BIND_EXPR_BODY (bind), ctx);
+  expand_rec_input_clauses (clauses, &BIND_EXPR_BODY (bind), &olist, ctx);
   append_to_statement_list (body, &BIND_EXPR_BODY (bind));
   expand_reduction_clauses (clauses, &BIND_EXPR_BODY (bind), ctx);
+  append_to_statement_list (olist, &BIND_EXPR_BODY (bind));
   maybe_catch_exception (&BIND_EXPR_BODY (bind));
 
   pop_gimplify_context (bind);
@@ -2140,7 +2170,7 @@ expand_omp_for_1 (tree *stmt_p, omp_cont
   struct expand_omp_for_data fd;
   bool have_nowait, have_ordered;
   enum omp_clause_schedule_kind sched_kind;
-  tree t;
+  tree t, dlist;
 
   fd.for_stmt = *stmt_p;
   fd.pre = NULL;
@@ -2215,7 +2245,8 @@ expand_omp_for_1 (tree *stmt_p, omp_cont
 	break;
       }
 
-  expand_rec_input_clauses (OMP_FOR_CLAUSES (fd.for_stmt), &fd.pre, ctx);
+  expand_rec_input_clauses (OMP_FOR_CLAUSES (fd.for_stmt),
+			    &fd.pre, &dlist, ctx);
 
   expand_omp (&OMP_FOR_PRE_BODY (fd.for_stmt), ctx);
   append_to_statement_list (OMP_FOR_PRE_BODY (fd.for_stmt), &fd.pre);
@@ -2244,6 +2275,7 @@ expand_omp_for_1 (tree *stmt_p, omp_cont
     }
 
   expand_reduction_clauses (OMP_FOR_CLAUSES (fd.for_stmt), &fd.pre, ctx);
+  append_to_statement_list (dlist, &fd.pre);
 
   if (!have_nowait)
     build_omp_barrier (&fd.pre);
@@ -2305,6 +2337,7 @@ expand_omp_sections (tree *stmt_p, omp_c
 {
   tree sec_stmt, label_vec, bind, block, stmt_list, l0, l1, l2, t, u, v;
   tree_stmt_iterator tsi;
+  tree dlist;
   unsigned i, len;
 
   sec_stmt = *stmt_p;
@@ -2312,7 +2345,8 @@ expand_omp_sections (tree *stmt_p, omp_c
 
   push_gimplify_context ();
 
-  expand_rec_input_clauses (OMP_SECTIONS_CLAUSES (sec_stmt), &stmt_list, ctx);
+  expand_rec_input_clauses (OMP_SECTIONS_CLAUSES (sec_stmt),
+			    &stmt_list, &dlist, ctx);
 
   tsi = tsi_start (OMP_SECTIONS_BODY (sec_stmt));
   for (len = 0; !tsi_end_p (tsi); len++, tsi_next (&tsi))
@@ -2392,6 +2426,7 @@ expand_omp_sections (tree *stmt_p, omp_c
   gimplify_and_add (t, &stmt_list);
 
   expand_reduction_clauses (OMP_SECTIONS_CLAUSES (sec_stmt), &stmt_list, ctx);
+  append_to_statement_list (dlist, &stmt_list);
 
   /* Unless there's a nowait clause, add a barrier afterward.  */
   if (!find_omp_clause (OMP_SECTIONS_CLAUSES (sec_stmt), OMP_CLAUSE_NOWAIT))
@@ -2470,9 +2505,6 @@ expand_omp_single_copy (tree single_stmt
   l1 = create_artificial_label ();
   l2 = create_artificial_label ();
 
-  /* Handle firstprivate clauses.  */
-  expand_rec_input_clauses (OMP_SINGLE_CLAUSES (single_stmt), pre_p, ctx);
-
   t = built_in_decls[BUILT_IN_GOMP_SINGLE_COPY_START];
   t = build_function_call_expr (t, NULL);
   t = fold_convert (ptr_type, t);
@@ -2519,7 +2551,7 @@ expand_omp_single_copy (tree single_stmt
 static void
 expand_omp_single (tree *stmt_p, omp_context *ctx)
 {
-  tree bind, block, single_stmt = *stmt_p;
+  tree bind, block, single_stmt = *stmt_p, dlist;
 
   push_gimplify_context ();
 
@@ -2529,11 +2561,16 @@ expand_omp_single (tree *stmt_p, omp_con
   bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, block);
   *stmt_p = bind;
 
+  expand_rec_input_clauses (OMP_SINGLE_CLAUSES (single_stmt),
+			    &BIND_EXPR_BODY (bind), &dlist, ctx);
+
   if (ctx->record_type)
     expand_omp_single_copy (single_stmt, &BIND_EXPR_BODY (bind), ctx);
   else
     expand_omp_single_simple (single_stmt, &BIND_EXPR_BODY (bind));
 
+  append_to_statement_list (dlist, &BIND_EXPR_BODY (bind));
+
   maybe_catch_exception (&BIND_EXPR_BODY (bind));
   pop_gimplify_context (bind);
   BIND_EXPR_VARS (bind) = chainon (BIND_EXPR_VARS (bind), ctx->block_vars);
Index: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.735.4.24
diff -u -p -d -r1.735.4.24 tree.h
--- gcc/tree.h	22 Oct 2005 00:30:05 -0000	1.735.4.24
+++ gcc/tree.h	24 Oct 2005 03:47:51 -0000
@@ -341,6 +341,8 @@ struct tree_common GTY(())
           ..._TYPE
        SAVE_EXPR_RESOLVED_P in
 	  SAVE_EXPR
+       OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE in
+	  OMP_CLAUSE_LASTPRIVATE
 
    private_flag:
 
@@ -1427,6 +1429,11 @@ struct tree_constructor GTY(())
   TREE_OPERAND (TREE_RANGE_CHECK (NODE, OMP_CLAUSE_PRIVATE, \
 				  OMP_CLAUSE_COPYPRIVATE), 0)
 
+/* True on a LASTPRIVATE clause if a FIRSTPRIVATE clause for the same
+   decl is present in the chain.  */
+#define OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE(NODE) \
+  TREE_PUBLIC (OMP_CLAUSE_LASTPRIVATE_CHECK (NODE))
+
 #define OMP_CLAUSE_IF_EXPR(NODE) \
   TREE_OPERAND (OMP_CLAUSE_IF_CHECK (NODE), 0)
 #define OMP_CLAUSE_NUM_THREADS_EXPR(NODE) \
Index: gcc/cp/cp-objcp-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-objcp-common.h,v
retrieving revision 1.9.4.2
diff -u -p -d -r1.9.4.2 cp-objcp-common.h
--- gcc/cp/cp-objcp-common.h	18 Oct 2005 19:06:59 -0000	1.9.4.2
+++ gcc/cp/cp-objcp-common.h	24 Oct 2005 03:47:51 -0000
@@ -153,5 +153,13 @@ extern tree objcp_tsubst_copy_and_build 
 #define LANG_HOOKS_GIMPLIFY_EXPR cp_gimplify_expr
 #undef LANG_HOOKS_OMP_PREDETERMINED_SHARING
 #define LANG_HOOKS_OMP_PREDETERMINED_SHARING cxx_omp_predetermined_sharing
+#undef LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR
+#define LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR cxx_omp_clause_default_ctor
+#undef LANG_HOOKS_OMP_CLAUSE_COPY_CTOR
+#define LANG_HOOKS_OMP_CLAUSE_COPY_CTOR cxx_omp_clause_copy_ctor
+#undef LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP
+#define LANG_HOOKS_OMP_CLAUSE_ASSIGN_OP cxx_omp_clause_assign_op
+#undef LANG_HOOKS_OMP_CLAUSE_DTOR
+#define LANG_HOOKS_OMP_CLAUSE_DTOR cxx_maybe_build_cleanup
 
 #endif /* GCC_CP_OBJCP_COMMON */
Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.1144.4.16
diff -u -p -d -r1.1144.4.16 cp-tree.h
--- gcc/cp/cp-tree.h	21 Oct 2005 22:06:51 -0000	1.1144.4.16
+++ gcc/cp/cp-tree.h	24 Oct 2005 03:47:52 -0000
@@ -4255,6 +4255,9 @@ extern tree finish_omp_for			(location_t
 						 tree, tree, tree);
 extern void finish_omp_atomic			(enum tree_code, tree, tree);
 extern enum omp_clause_default_kind cxx_omp_predetermined_sharing (tree);
+extern tree cxx_omp_clause_default_ctor		(tree);
+extern tree cxx_omp_clause_copy_ctor		(tree, tree);
+extern tree cxx_omp_clause_assign_op		(tree, tree);
 
 /* in tree.c */
 extern void lang_check_failed			(const char *, int,
Index: gcc/cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.475.4.17
diff -u -p -d -r1.475.4.17 semantics.c
--- gcc/cp/semantics.c	22 Oct 2005 00:54:03 -0000	1.475.4.17
+++ gcc/cp/semantics.c	24 Oct 2005 03:47:53 -0000
@@ -3371,6 +3371,7 @@ finish_omp_clauses (tree clauses)
       bool need_copy_ctor = false;
       bool need_copy_assignment = false;
       bool need_implicitly_determined = false;
+      tree type;
 
       switch (c_kind)
 	{
@@ -3510,13 +3511,61 @@ finish_omp_clauses (tree clauses)
 	      remove = true;
 	    }
 	}
-      if (need_default_ctor | need_copy_ctor | need_copy_assignment)
+
+      /* We're interested in the base element, not arrays.  */
+      type = TREE_TYPE (t);
+      while (TREE_CODE (type) == ARRAY_TYPE)
+	type = TREE_TYPE (type);
+
+      /* Check for special function availablity by building a call to one
+	 and discarding the results.  C.f. check_constructor_callable.  */
+      if (CLASS_TYPE_P (type))
 	{
-	  /* FIXME */
+	  int save_errorcount = errorcount;
+
+	  if (need_default_ctor && TYPE_NEEDS_CONSTRUCTING (type))
+	    {
+	      build_special_member_call (NULL_TREE, complete_ctor_identifier,
+					 NULL_TREE, type, LOOKUP_NORMAL);
+	    }
+	  if (need_copy_ctor && TYPE_NEEDS_CONSTRUCTING (type))
+	    {
+	      build_special_member_call (NULL_TREE, complete_ctor_identifier,
+					 build_tree_list (NULL, t),
+					 type, LOOKUP_NORMAL);
+	    }
+	  if (need_copy_assignment)
+	    {
+	      build_special_member_call (t, ansi_assopname (NOP_EXPR),
+					 build_tree_list (NULL, t),
+					 type, LOOKUP_NORMAL);
+	    }
+
+	  if (errorcount != save_errorcount)
+	    remove = true;
 	}
 
       if (remove)
-	*pc = OMP_CLAUSE_CHAIN (c);
+	{
+	  *pc = OMP_CLAUSE_CHAIN (c);
+
+	  /* If we don't remove the corresponding firstprivate clause, we
+	     can wind up with spurrious errors later, since this changes
+	     the set of constructors we request.  */
+	  if (c_kind == OMP_CLAUSE_LASTPRIVATE
+	      && bitmap_bit_p (&firstprivate_head,
+			       DECL_UID (OMP_CLAUSE_DECL (c))))
+	    {
+	      tree *p;
+	      for (p = &clauses; *p ; p = &OMP_CLAUSE_CHAIN (*p))
+		if (TREE_CODE (*p) == OMP_CLAUSE_FIRSTPRIVATE
+		    && OMP_CLAUSE_DECL (*p) == OMP_CLAUSE_DECL (c))
+		  {
+		    *p = OMP_CLAUSE_CHAIN (*p);
+		    break;
+		  }
+	    }
+	}
       else
 	pc = &OMP_CLAUSE_CHAIN (c);
     }
@@ -3696,9 +3745,55 @@ cxx_omp_predetermined_sharing (tree decl
 
   return OMP_CLAUSE_DEFAULT_UNSPECIFIED;
 }
-
-/* Perform initialization related to this module.  */
 
+/* Build and return code to initialize DECL with its default constructor.
+   Return NULL if there's nothing to do.  */
+
+tree
+cxx_omp_clause_default_ctor (tree decl)
+{
+  tree type = TREE_TYPE (decl);
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      tree etype = type;
+      while (TREE_CODE (etype) == ARRAY_TYPE)
+	etype = TREE_TYPE (etype);
+
+      if (TYPE_NEEDS_CONSTRUCTING (etype))
+	return build_vec_init (decl, NULL, NULL, true, 0);
+      else
+	return NULL;
+    }
+  else if (TYPE_NEEDS_CONSTRUCTING (type))
+    return build_aggr_init (decl, NULL, 0);
+  else
+    return NULL;
+}
+
+/* Build and return code for a copy constructor from SRC to DST.  */
+
+tree
+cxx_omp_clause_copy_ctor (tree dst, tree src)
+{
+  if (TREE_CODE (TREE_TYPE (dst)) == ARRAY_TYPE)
+    return build_vec_init (dst, NULL, src, false, 1);
+  else
+    return build_modify_expr (dst, INIT_EXPR, src);
+}
+
+/* Similarly, except use an assignment operator instead.  */
+
+tree
+cxx_omp_clause_assign_op (tree dst, tree src)
+{
+  if (TREE_CODE (TREE_TYPE (dst)) == ARRAY_TYPE)
+    return build_vec_init (dst, NULL, src, false, 2);
+  else
+    return build_modify_expr (dst, NOP_EXPR, src);
+}
+
+
 void
 init_cp_semantics (void)
 {
Index: gcc/testsuite/g++.dg/gomp/clause-2.C
===================================================================
RCS file: gcc/testsuite/g++.dg/gomp/clause-2.C
diff -N gcc/testsuite/g++.dg/gomp/clause-2.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/g++.dg/gomp/clause-2.C	24 Oct 2005 03:47:53 -0000
@@ -0,0 +1,38 @@
+// { dg-do compile }
+
+struct A { int a; };
+struct B { B(); };
+struct C { C(); C(const C&); };
+struct D { D& operator=(const D&); };
+
+class E { private: E(); public: E(int); };	// { dg-error "private" }
+class F { private: F(const F&); public: F(); };	// { dg-error "private" }
+class G { private: G& operator=(const G&); };	// { dg-error "private" }
+
+void bar();
+void foo()
+{
+  A a; B b; C c; D d; E e(0); F f; G g;
+
+  #pragma omp parallel shared(a, b, c, d, e, f, g)
+    bar();
+
+  #pragma omp parallel private(a, b, c, d, f, g)
+    bar();
+  #pragma omp parallel private(e)		// { dg-error "context" }
+    bar();
+
+  #pragma omp parallel firstprivate(a, b, c, d, e, g)
+    bar();
+  #pragma omp parallel firstprivate(f)		// { dg-error "context" }
+    bar();
+
+  #pragma omp parallel sections lastprivate(a, b, d, c, f)
+    { bar(); }
+  #pragma omp parallel sections lastprivate(e)	// { dg-error "context" }
+    { bar(); }
+  #pragma omp parallel sections lastprivate(g)	// { dg-error "context" }
+    { bar(); }
+  #pragma omp parallel sections firstprivate(e) lastprivate(e)
+    { bar(); }
+}
Index: libgomp/testsuite/libgomp.c++/ctor-1.C
===================================================================
RCS file: libgomp/testsuite/libgomp.c++/ctor-1.C
diff -N libgomp/testsuite/libgomp.c++/ctor-1.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libgomp/testsuite/libgomp.c++/ctor-1.C	24 Oct 2005 03:47:53 -0000
@@ -0,0 +1,65 @@
+// { dg-do run }
+
+#include <omp.h>
+#include <assert.h>
+
+struct B
+{
+  static int icount;
+  static int dcount;
+  static int xcount;
+
+  B();
+  B(const B &);
+  ~B();
+  B& operator=(const B &);
+  void doit();
+};
+
+int B::icount;
+int B::dcount;
+int B::xcount;
+
+B::B()
+{
+  #pragma omp atomic 
+    icount++;
+}
+
+B::~B()
+{
+  #pragma omp atomic
+    dcount++;
+}
+
+void B::doit()
+{
+  #pragma omp atomic
+    xcount++;
+}
+
+static int nthreads;
+
+void foo()
+{
+  B b;
+  #pragma omp parallel private(b)
+    {
+      #pragma omp master
+	nthreads = omp_get_num_threads ();
+      b.doit();
+    }
+}
+
+int main()
+{
+  omp_set_dynamic (0);
+  omp_set_num_threads (4);
+  foo();
+
+  assert (B::xcount == nthreads);
+  assert (B::icount == nthreads+1);
+  assert (B::dcount == nthreads+1);
+
+  return 0;
+}
Index: libgomp/testsuite/libgomp.c++/ctor-2.C
===================================================================
RCS file: libgomp/testsuite/libgomp.c++/ctor-2.C
diff -N libgomp/testsuite/libgomp.c++/ctor-2.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libgomp/testsuite/libgomp.c++/ctor-2.C	24 Oct 2005 03:47:53 -0000
@@ -0,0 +1,76 @@
+// { dg-do run }
+
+#include <omp.h>
+#include <assert.h>
+
+struct B
+{
+  static int ccount;
+  static int dcount;
+  static int xcount;
+  static B *expected;
+
+  B();
+  B(int);
+  B(const B &);
+  ~B();
+  B& operator=(const B &);
+  void doit();
+};
+
+int B::ccount;
+int B::dcount;
+int B::xcount;
+B * B::expected;
+
+B::B(int)
+{
+  expected = this;
+}
+
+B::B(const B &b)
+{
+  #pragma omp atomic 
+    ccount++;
+  assert (&b == expected);
+}
+
+B::~B()
+{
+  #pragma omp atomic
+    dcount++;
+}
+
+void B::doit()
+{
+  #pragma omp atomic
+    xcount++;
+  assert (this != expected);
+}
+
+static int nthreads;
+
+void foo()
+{
+  B b(0);
+
+  #pragma omp parallel firstprivate(b)
+    {
+      #pragma omp master
+	nthreads = omp_get_num_threads ();
+      b.doit();
+    }
+}
+
+int main()
+{
+  omp_set_dynamic (0);
+  omp_set_num_threads (4);
+  foo();
+
+  assert (B::xcount == nthreads);
+  assert (B::ccount == nthreads);
+  assert (B::dcount == nthreads+1);
+
+  return 0;
+}
Index: libgomp/testsuite/libgomp.c++/ctor-3.C
===================================================================
RCS file: libgomp/testsuite/libgomp.c++/ctor-3.C
diff -N libgomp/testsuite/libgomp.c++/ctor-3.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libgomp/testsuite/libgomp.c++/ctor-3.C	24 Oct 2005 03:47:53 -0000
@@ -0,0 +1,89 @@
+// { dg-do run }
+
+#include <omp.h>
+#include <assert.h>
+
+struct B
+{
+  static int icount;
+  static int dcount;
+  static int ccount;
+  static B *e_inner;
+  static B *e_outer;
+
+  B();
+  B(int);
+  B(const B &);
+  ~B();
+  B& operator=(const B &);
+  void doit();
+};
+
+int B::icount;
+int B::dcount;
+int B::ccount;
+B * B::e_inner;
+B * B::e_outer;
+
+B::B()
+{
+  #pragma omp atomic 
+    icount++;
+}
+
+B::B(int)
+{
+  e_outer = this;
+}
+
+B::~B()
+{
+  #pragma omp atomic
+    dcount++;
+}
+
+B& B::operator= (const B &b)
+{
+  assert (&b == e_inner);
+  assert (this == e_outer);
+  #pragma omp atomic
+    ccount++;
+  return *this;
+}
+
+void B::doit()
+{
+  #pragma omp critical
+    {
+      assert (e_inner == 0);
+      e_inner = this;
+    }
+}
+
+static int nthreads;
+
+void foo()
+{
+  B b(0);
+
+  #pragma omp parallel sections lastprivate(b)
+    {
+    #pragma omp section
+      nthreads = omp_get_num_threads ();
+    #pragma omp section
+      b.doit ();
+    }
+}
+
+int main()
+{
+  omp_set_dynamic (0);
+  omp_set_num_threads (4);
+  foo();
+
+  assert (B::ccount == 1);
+  assert (B::icount == nthreads);
+  assert (B::dcount == nthreads+1);
+
+  return 0;
+}
Index: libgomp/testsuite/libgomp.c++/ctor-4.C
===================================================================
RCS file: libgomp/testsuite/libgomp.c++/ctor-4.C
diff -N libgomp/testsuite/libgomp.c++/ctor-4.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libgomp/testsuite/libgomp.c++/ctor-4.C	24 Oct 2005 03:47:53 -0000
@@ -0,0 +1,90 @@
+// { dg-do run }
+
+#include <omp.h>
+#include <assert.h>
+
+struct B
+{
+  static int ccount;
+  static int dcount;
+  static int ecount;
+  static B *e_inner;
+  static B *e_outer;
+
+  B();
+  B(int);
+  B(const B &);
+  ~B();
+  B& operator=(const B &);
+  void doit();
+};
+
+int B::ccount;
+int B::dcount;
+int B::ecount;
+B * B::e_inner;
+B * B::e_outer;
+
+B::B(int)
+{
+  e_outer = this;
+}
+
+B::B(const B &b)
+{
+  assert (&b == e_outer);
+  #pragma omp atomic 
+    ccount++;
+}
+
+B::~B()
+{
+  #pragma omp atomic
+    dcount++;
+}
+
+B& B::operator= (const B &b)
+{
+  assert (&b == e_inner);
+  assert (this == e_outer);
+  #pragma omp atomic
+    ecount++;
+  return *this;
+}
+
+void B::doit()
+{
+  #pragma omp critical
+    {
+      assert (e_inner == 0);
+      e_inner = this;
+    }
+}
+
+static int nthreads;
+
+void foo()
+{
+  B b(0);
+
+  #pragma omp parallel sections firstprivate(b) lastprivate(b)
+    {
+    #pragma omp section
+      nthreads = omp_get_num_threads ();
+    #pragma omp section
+      b.doit ();
+    }
+}
+
+int main()
+{
+  omp_set_dynamic (0);
+  omp_set_num_threads (4);
+  foo();
+
+  assert (B::ecount == 1);
+  assert (B::ccount == nthreads);
+  assert (B::dcount == nthreads+1);
+
+  return 0;
+}
Index: libgomp/testsuite/libgomp.c++/ctor-5.C
===================================================================
RCS file: libgomp/testsuite/libgomp.c++/ctor-5.C
diff -N libgomp/testsuite/libgomp.c++/ctor-5.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libgomp/testsuite/libgomp.c++/ctor-5.C	24 Oct 2005 03:47:53 -0000
@@ -0,0 +1,51 @@
+// { dg-do run }
+
+#include <omp.h>
+#include <assert.h>
+
+struct B
+{
+  static int count;
+  static B *expected;
+
+  B& operator=(const B &);
+};
+
+int B::count;
+B * B::expected;
+
+static B thr;
+#pragma omp threadprivate(thr)
+
+B& B::operator= (const B &b)
+{
+  assert (&b == expected);
+  assert (this != expected);
+  #pragma omp atomic
+    count++;
+  return *this;
+}
+
+static int nthreads;
+
+void foo()
+{
+  B::expected = &thr;
+
+  #pragma omp parallel copyin(thr)
+    {
+    #pragma omp master
+      nthreads = omp_get_num_threads ();
+    }
+}
+
+int main()
+{
+  omp_set_dynamic (0);
+  omp_set_num_threads (4);
+  foo();
+
+  assert (B::count == nthreads-1);
+
+  return 0;
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]