diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b767290676b8fe1b142b709bdeac35c806810dd7..bbb7af867ffe0939a5e978e246e28c056a093ee1 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2009-04-01  Jakub Jelinek  <jakub@redhat.com>
+
+	PR other/39591
+	* omp-low.c (remove_exit_barrier): Don't optimize if there are any
+	addressable variables in the parallel that could go out of scope while
+	running queued tasks.
+
 2009-04-01  Anatoly Sokolov  <aesok@post.ru>
 
 	* config/avr/avr.h (avr_case_values_threshold): Remove declaration.
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 40658760d38c1b08e16eedc10eb2bee41e7edb29..b96da5fe1e24c70d51364ae49f9c46ce3d7837ae 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -3,7 +3,7 @@
    marshalling to implement data sharing and copying clauses.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
-   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -3123,6 +3123,7 @@ remove_exit_barrier (struct omp_region *region)
   edge_iterator ei;
   edge e;
   gimple stmt;
+  int any_addressable_vars = -1;
 
   exit_bb = region->exit;
 
@@ -3148,8 +3149,52 @@ remove_exit_barrier (struct omp_region *region)
       if (gsi_end_p (gsi))
 	continue;
       stmt = gsi_stmt (gsi);
-      if (gimple_code (stmt) == GIMPLE_OMP_RETURN)
-	gimple_omp_return_set_nowait (stmt);
+      if (gimple_code (stmt) == GIMPLE_OMP_RETURN
+	  && !gimple_omp_return_nowait_p (stmt))
+	{
+	  /* OpenMP 3.0 tasks unfortunately prevent this optimization
+	     in many cases.  If there could be tasks queued, the barrier
+	     might be needed to let the tasks run before some local
+	     variable of the parallel that the task uses as shared
+	     runs out of scope.  The task can be spawned either
+	     from within current function (this would be easy to check)
+	     or from some function it calls and gets passed an address
+	     of such a variable.  */
+	  if (any_addressable_vars < 0)
+	    {
+	      gimple parallel_stmt = last_stmt (region->entry);
+	      tree child_fun = gimple_omp_parallel_child_fn (parallel_stmt);
+	      tree local_decls = DECL_STRUCT_FUNCTION (child_fun)->local_decls;
+	      tree block;
+
+	      any_addressable_vars = 0;
+	      for (; local_decls; local_decls = TREE_CHAIN (local_decls))
+		if (TREE_ADDRESSABLE (TREE_VALUE (local_decls)))
+		  {
+		    any_addressable_vars = 1;
+		    break;
+		  }
+	      for (block = gimple_block (stmt);
+		   !any_addressable_vars
+		   && block
+		   && TREE_CODE (block) == BLOCK;
+		   block = BLOCK_SUPERCONTEXT (block))
+		{
+		  for (local_decls = BLOCK_VARS (block);
+		       local_decls;
+		       local_decls = TREE_CHAIN (local_decls))
+		    if (TREE_ADDRESSABLE (local_decls))
+		      {
+			any_addressable_vars = 1;
+			break;
+		      }
+		  if (block == gimple_block (parallel_stmt))
+		    break;
+		}
+	    }
+	  if (!any_addressable_vars)
+	    gimple_omp_return_set_nowait (stmt);
+	}
     }
 }
 
diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index a77fdde70e9f6a88ffb16b93c8e8caf228305986..15eb2c6c7694b17f5ccb468bbbc07564133e919c 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,3 +1,10 @@
+2009-04-01  Jakub Jelinek  <jakub@redhat.com>
+
+	PR other/39591
+	* testsuite/libgomp.c/pr39591-1.c: New test.
+	* testsuite/libgomp.c/pr39591-2.c: New test.
+	* testsuite/libgomp.c/pr39591-3.c: New test.
+
 2009-03-25  Uros Bizjak  <ubizjak@gmail.com>
 
 	* testsuite/libgomp.c/atomic-5.c: Cleanup cpuid usage.
diff --git a/libgomp/testsuite/libgomp.c/pr39591-1.c b/libgomp/testsuite/libgomp.c/pr39591-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..dfd8d9e8aca60504801edeab3c01d6400c5bb1f0
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/pr39591-1.c
@@ -0,0 +1,33 @@
+/* PR other/39591 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern void abort (void);
+
+int err;
+
+int
+main (void)
+{
+#pragma omp parallel
+  {
+    int array[40];
+    int i;
+    for (i = 0; i < sizeof array / sizeof array[0]; i++)
+      array[i] = 0x55555555;
+
+#pragma omp for schedule(dynamic)
+    for (i = 0; i < 50; i++)
+#pragma omp task shared(array)
+      {
+	int j;
+	for (j = 0; j < sizeof array / sizeof array[0]; j++)
+	  if (array[j] != 0x55555555)
+#pragma omp atomic
+	    err++;
+      }
+  }
+  if (err)
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/pr39591-2.c b/libgomp/testsuite/libgomp.c/pr39591-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b5f8f9cc7b22c5a380a31d079e8ea61778f0eae7
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/pr39591-2.c
@@ -0,0 +1,39 @@
+/* PR other/39591 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern void abort (void);
+
+int err;
+
+void __attribute__((noinline))
+foo (int *array)
+{
+#pragma omp task
+  {
+    int j;
+    for (j = 0; j < sizeof array / sizeof array[0]; j++)
+      if (array[j] != 0x55555555)
+#pragma omp atomic
+	err++;
+  }
+}
+
+int
+main (void)
+{
+#pragma omp parallel
+  {
+    int array[40];
+    int i;
+    for (i = 0; i < sizeof array / sizeof array[0]; i++)
+      array[i] = 0x55555555;
+
+#pragma omp for schedule (dynamic)
+    for (i = 0; i < 50; i++)
+      foo (array);
+  }
+  if (err)
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/pr39591-3.c b/libgomp/testsuite/libgomp.c/pr39591-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..a9aeea7c83ad488f46451dd0e9fbcee66336dbf1
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/pr39591-3.c
@@ -0,0 +1,40 @@
+/* PR other/39591 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern void abort (void);
+
+int err, a[40];
+
+void __attribute__((noinline))
+foo (int *array)
+{
+#pragma omp task
+  {
+    int j;
+    for (j = 0; j < sizeof array / sizeof array[0]; j++)
+      if (array[j] != 0x55555555)
+#pragma omp atomic
+	err++;
+  }
+}
+
+int
+main (void)
+{
+  int k;
+  for (k = 0; k < sizeof a / sizeof a[0]; k++)
+    a[k] = 0x55555555;
+
+#pragma omp parallel
+  {
+    int i;
+
+#pragma omp for schedule (dynamic)
+    for (i = 0; i < 50; i++)
+      foo (a);
+  }
+  if (err)
+    abort ();
+  return 0;
+}