Patchwork [gomp4] Taskgroup and cancellation compiler fixes

login
register
mail settings
Submitter Jakub Jelinek
Date Sept. 24, 2013, 7:15 p.m.
Message ID <20130924191531.GU30970@tucnak.zalov.cz>
Download mbox | patch
Permalink /patch/277603/
State New
Headers show

Comments

Jakub Jelinek - Sept. 24, 2013, 7:15 p.m.
Hi!

This patch:
1) defers expansion of taskgroup into GOMP_taskgroup_start and
   GOMP_taskgroup_end until omplower/ompexp, mainly so that e.g. invalid
   nesting can be diagnosed (e.g. #pragma omp cancel * inside of
   #pragma omp taskgroup nested in some other construct)
2) diagnoses structured block restrictions also for #pragma omp target{,data}
   and #pragma omp teams and taskgroup
3) fixes a bug, where cancellation of sections, for and parallel/task
   jumped to after the dtors rather than before them, because then some
   variables won't be properly destructed

Will commit tomorrow to gomp-4_0-branch unless somebody finds issues with
this.

2013-09-24  Jakub Jelinek  <jakub@redhat.com>

	* omp-low.c (lower_omp_sections, lower_omp_for, lower_omp_taskreg):
	Emit ctx->cancel_label before destructors.

	* gimple-pretty-print.c (dump_gimple_omp_block,
	pp_gimple_stmt_1): Handle GIMPLE_OMP_TASKGROUP.
	* tree-nested.c (convert_nonlocal_reference_stmt,
	convert_local_reference_stmt, convert_gimple_call): Likewise.
	* tree-cfg.c (make_edges): Likewise.
	* gimple.h (gimple_build_omp_taskgroup): New prototype.
	(gimple_has_substatement): Handle GIMPLE_OMP_TASKGROUP.
	(CASE_GIMPLE_OMP): Likewise.
	* gimplify.c (is_gimple_stmt, gimplify_expr): Handle OMP_TASKGROUP.
	* omp-low.c (check_omp_nesting_restrictions): Warn if #pragma omp
	cancel is used in nowait loop or sections construct.
	(scan_omp_1_stmt, expand_omp_synch, expand_omp, lower_omp_1): Handle
	GIMPLE_OMP_TASKGROUP.
	(diagnose_sb_1, diagnose_sb_2): Likewise.  Handle GIMPLE_OMP_TARGET
	and GIMPLE_OMP_TEAMS.
	(lower_omp_taskgroup): New function.
	* tree-inline.c (remap_gimple_stmt, estimate_num_insns): Handle
	GIMPLE_OMP_TASKGROUP.
	* gimple-low.c (lower_stmt): Likewise.
	* tree.h (OMP_TASKGROUP_BODY): Define.
	* tree.def (OMP_TASKGROUP): New tree.
	* tree-pretty-print.c (dump_generic_node): Handle OMP_TASKGROUP.
	* gimple.c (gimple_build_omp_taskgroup): New function.
	(walk_gimple_stmt, gimple_copy): Handle GIMPLE_OMP_TASKGROUP.
	* gimple.def (GIMPLE_OMP_TASKGROUP): New GIMPLE code.
c-family/
	* c-common.h (c_finish_omp_taskgroup): New prototype.
	* c-omp.c (c_finish_omp_taskgroup): New function.
c/
	* c-parser.c (c_parser_omp_taskgroup): Return tree.
	Don't call c_begin_omp_taskgroup.
	(c_parser_omp_construct): Adjust caller.
	* c-typeck.c (c_begin_omp_taskgroup, c_finish_omp_taskgroup): Remove.
	* c-tree.h (c_begin_omp_taskgroup, c_finish_omp_taskgroup): Remove.
cp/
	* parser.c (cp_parser_omp_taskgroup): Return tree.  Use
	c_finish_omp_taskgroup.
	(cp_parser_omp_construct): Adjust caller.
	* cp-array-notation.c (expand_array_notation_exprs): Handle
	OMP_TASKGROUP.
	* pt.c (tsubst_expr): Handle OMP_TASKGROUP.
	* semantics.c (finish_omp_taskgroup): Remove.
	* cp-tree.h (finish_omp_taskgroup): Remove.
testsuite/
	* g++.dg/gomp/target-1.C: New test.
	* g++.dg/gomp/target-2.C: New test.
	* g++.dg/gomp/teams-1.C: New test.
	* g++.dg/gomp/taskgroup-1.C: New test.
	* gcc.dg/gomp/teams-1.c: New test.
	* gcc.dg/gomp/taskgroup-1.c: New test.
	* gcc.dg/gomp/target-1.c: New test.
	* gcc.dg/gomp/target-2.c: New test.
	* c-c++-common/gomp/cancel-1.c: New test.


	Jakub

Patch

--- gcc/gimple-pretty-print.c.jj	2013-09-13 16:48:21.000000000 +0200
+++ gcc/gimple-pretty-print.c	2013-09-23 15:06:23.857832390 +0200
@@ -1360,8 +1360,8 @@  dump_gimple_omp_sections (pretty_printer
     }
 }
 
-/* Dump a GIMPLE_OMP_{MASTER,ORDERED,SECTION} tuple on the pretty_printer
-   BUFFER.  */
+/* Dump a GIMPLE_OMP_{MASTER,TASKGROUP,ORDERED,SECTION} tuple on the
+   pretty_printer BUFFER.  */
 
 static void
 dump_gimple_omp_block (pretty_printer *buffer, gimple gs, int spc, int flags)
@@ -1376,6 +1376,9 @@  dump_gimple_omp_block (pretty_printer *b
 	case GIMPLE_OMP_MASTER:
 	  pp_string (buffer, "#pragma omp master");
 	  break;
+	case GIMPLE_OMP_TASKGROUP:
+	  pp_string (buffer, "#pragma omp taskgroup");
+	  break;
 	case GIMPLE_OMP_ORDERED:
 	  pp_string (buffer, "#pragma omp ordered");
 	  break;
@@ -2131,6 +2134,7 @@  pp_gimple_stmt_1 (pretty_printer *buffer
       break;
 
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SECTION:
       dump_gimple_omp_block (buffer, gs, spc, flags);
--- gcc/tree-nested.c.jj	2013-09-13 16:49:05.000000000 +0200
+++ gcc/tree-nested.c	2013-09-23 15:06:23.857832390 +0200
@@ -1309,6 +1309,7 @@  convert_nonlocal_reference_stmt (gimple_
 
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
       walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
 	         info, gimple_omp_body_ptr (stmt));
@@ -1748,6 +1749,7 @@  convert_local_reference_stmt (gimple_stm
 
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
       walk_body (convert_local_reference_stmt, convert_local_reference_op,
 		 info, gimple_omp_body_ptr (stmt));
@@ -2106,6 +2108,7 @@  convert_gimple_call (gimple_stmt_iterato
     case GIMPLE_OMP_TARGET:
     case GIMPLE_OMP_TEAMS:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_CRITICAL:
       walk_body (convert_gimple_call, NULL, info, gimple_omp_body_ptr (stmt));
--- gcc/c/c-parser.c.jj	2013-09-19 09:12:43.000000000 +0200
+++ gcc/c/c-parser.c	2013-09-23 15:07:45.788417931 +0200
@@ -11861,15 +11861,12 @@  c_parser_omp_taskyield (c_parser *parser
    # pragma omp taskgroup new-line
 */
 
-static void
+static tree
 c_parser_omp_taskgroup (c_parser *parser)
 {
   location_t loc = c_parser_peek_token (parser)->location;
   c_parser_skip_to_pragma_eol (parser);
-
-  tree block = c_begin_omp_taskgroup ();
-  c_parser_statement (parser);
-  c_finish_omp_taskgroup (loc, block);
+  return c_finish_omp_taskgroup (loc, c_parser_omp_structured_block (parser));
 }
 
 /* OpenMP 4.0:
@@ -12891,8 +12888,8 @@  c_parser_omp_construct (c_parser *parser
       stmt = c_parser_omp_task (loc, parser);
       break;
     case PRAGMA_OMP_TASKGROUP:
-      c_parser_omp_taskgroup (parser);
-      return;
+      stmt = c_parser_omp_taskgroup (parser);
+      break;
     case PRAGMA_OMP_TEAMS:
       strcpy (p_name, "#pragma omp");
       stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL);
--- gcc/c/c-typeck.c.jj	2013-09-19 19:00:43.000000000 +0200
+++ gcc/c/c-typeck.c	2013-09-24 20:46:42.886738344 +0200
@@ -10693,34 +10693,6 @@  c_finish_omp_task (location_t loc, tree
   return add_stmt (stmt);
 }
 
-/* Like c_begin_compound_stmt, except force the retention of the BLOCK.  */
-
-tree
-c_begin_omp_taskgroup (void)
-{
-  tree block;
-
-  keep_next_level ();
-  block = c_begin_compound_stmt (true);
-
-  return block;
-}
-
-/* Generate code for #pragma omp taskgroup.  */
-
-void
-c_finish_omp_taskgroup (location_t loc, tree block)
-{
-  tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_START);
-  tree stmt = build_call_expr_loc (loc, fn, 0);
-  block = c_end_compound_stmt (loc, block, true);
-  add_stmt (stmt);
-  add_stmt (block);
-  fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_END);
-  stmt = build_call_expr_loc (loc, fn, 0);
-  add_stmt (stmt);
-}
-
 /* Generate GOMP_cancel call for #pragma omp cancel.  */
 
 void
--- gcc/c/c-tree.h.jj	2013-09-19 09:12:43.000000000 +0200
+++ gcc/c/c-tree.h	2013-09-24 20:46:32.673788355 +0200
@@ -639,8 +639,6 @@  extern tree c_begin_omp_parallel (void);
 extern tree c_finish_omp_parallel (location_t, tree, tree);
 extern tree c_begin_omp_task (void);
 extern tree c_finish_omp_task (location_t, tree, tree);
-extern tree c_begin_omp_taskgroup (void);
-extern void c_finish_omp_taskgroup (location_t, tree);
 extern void c_finish_omp_cancel (location_t, tree);
 extern void c_finish_omp_cancellation_point (location_t, tree);
 extern tree c_finish_omp_clauses (tree);
--- gcc/tree-cfg.c.jj	2013-09-13 16:52:37.000000000 +0200
+++ gcc/tree-cfg.c	2013-09-23 15:06:23.857832390 +0200
@@ -612,6 +612,7 @@  make_edges (void)
 	    case GIMPLE_OMP_SINGLE:
 	    case GIMPLE_OMP_TEAMS:
 	    case GIMPLE_OMP_MASTER:
+	    case GIMPLE_OMP_TASKGROUP:
 	    case GIMPLE_OMP_ORDERED:
 	    case GIMPLE_OMP_CRITICAL:
 	    case GIMPLE_OMP_SECTION:
--- gcc/cp/parser.c.jj	2013-09-18 12:43:23.000000000 +0200
+++ gcc/cp/parser.c	2013-09-23 15:06:23.857832390 +0200
@@ -29331,26 +29331,15 @@  cp_parser_omp_taskyield (cp_parser *pars
    # pragma omp taskgroup new-line
      structured-block  */
 
-static void
+static tree
 cp_parser_omp_taskgroup (cp_parser *parser, cp_token *pragma_tok)
 {
-  tree sb;
-  unsigned int save;
-  location_t saved_loc;
-
   cp_parser_require_pragma_eol (parser, pragma_tok);
-  sb = begin_omp_structured_block ();
-  save = cp_parser_begin_omp_structured_block (parser);
-  cp_parser_statement (parser, NULL_TREE, false, NULL);
-  cp_parser_end_omp_structured_block (parser, save);
-  saved_loc = input_location;
-  input_location = pragma_tok->location;
-  finish_omp_taskgroup (finish_omp_structured_block (sb));
-  input_location = saved_loc;
+  return c_finish_omp_taskgroup (input_location,
+				 cp_parser_omp_structured_block (parser));
 }
 
 
-
 /* OpenMP 2.5:
    # pragma omp threadprivate (variable-list) */
 
@@ -30340,8 +30329,8 @@  cp_parser_omp_construct (cp_parser *pars
       stmt = cp_parser_omp_task (parser, pragma_tok);
       break;
     case PRAGMA_OMP_TASKGROUP:
-      cp_parser_omp_taskgroup (parser, pragma_tok);
-      return;
+      stmt = cp_parser_omp_taskgroup (parser, pragma_tok);
+      break;
     case PRAGMA_OMP_TEAMS:
       strcpy (p_name, "#pragma omp");
       stmt = cp_parser_omp_teams (parser, pragma_tok, p_name, mask, NULL);
--- gcc/cp/cp-array-notation.c.jj	2013-08-27 20:50:54.000000000 +0200
+++ gcc/cp/cp-array-notation.c	2013-09-23 15:06:23.857832390 +0200
@@ -1193,6 +1193,7 @@  expand_array_notation_exprs (tree t)
     case OMP_SECTION:
     case OMP_SECTIONS:
     case OMP_MASTER:
+    case OMP_TASKGROUP:
     case OMP_ORDERED:
     case OMP_CRITICAL:
     case OMP_ATOMIC:
--- gcc/cp/pt.c.jj	2013-09-18 12:43:23.000000000 +0200
+++ gcc/cp/pt.c	2013-09-23 15:06:23.857832390 +0200
@@ -13634,6 +13634,7 @@  tsubst_expr (tree t, tree args, tsubst_f
     case OMP_SECTION:
     case OMP_CRITICAL:
     case OMP_MASTER:
+    case OMP_TASKGROUP:
     case OMP_ORDERED:
       stmt = push_stmt_list ();
       RECUR (OMP_BODY (t));
--- gcc/cp/semantics.c.jj	2013-09-18 12:43:23.000000000 +0200
+++ gcc/cp/semantics.c	2013-09-23 15:06:23.857832390 +0200
@@ -6529,20 +6529,6 @@  finish_omp_taskyield (void)
 }
 
 void
-finish_omp_taskgroup (tree block_stmt)
-{
-  tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_START);
-  vec<tree, va_gc> *vec = make_tree_vector ();
-  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
-  finish_expr_stmt (stmt);
-  finish_expr_stmt (block_stmt);
-  fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_END);
-  stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
-  finish_expr_stmt (stmt);
-  release_tree_vector (vec);
-}
-
-void
 finish_omp_cancel (tree clauses)
 {
   tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCEL);
--- gcc/cp/cp-tree.h.jj	2013-09-18 12:43:23.000000000 +0200
+++ gcc/cp/cp-tree.h	2013-09-23 14:58:59.927014761 +0200
@@ -5806,7 +5806,6 @@  extern void finish_omp_barrier			(void);
 extern void finish_omp_flush			(void);
 extern void finish_omp_taskwait			(void);
 extern void finish_omp_taskyield		(void);
-extern void finish_omp_taskgroup		(tree);
 extern void finish_omp_cancel			(tree);
 extern void finish_omp_cancellation_point	(tree);
 extern tree begin_transaction_stmt		(location_t, tree *, int);
--- gcc/gimple.h.jj	2013-09-13 16:52:36.000000000 +0200
+++ gcc/gimple.h	2013-09-23 14:22:00.694017141 +0200
@@ -815,6 +815,7 @@  gimple gimple_build_omp_critical (gimple
 gimple gimple_build_omp_section (gimple_seq);
 gimple gimple_build_omp_continue (tree, tree);
 gimple gimple_build_omp_master (gimple_seq);
+gimple gimple_build_omp_taskgroup (gimple_seq);
 gimple gimple_build_omp_return (bool);
 gimple gimple_build_omp_ordered (gimple_seq);
 gimple gimple_build_omp_sections (gimple_seq, tree);
@@ -1264,6 +1265,7 @@  gimple_has_substatements (gimple g)
     case GIMPLE_TRY:
     case GIMPLE_OMP_FOR:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_PARALLEL:
@@ -5180,6 +5182,7 @@  gimple_return_set_retval (gimple gs, tre
     case GIMPLE_OMP_TEAMS:			\
     case GIMPLE_OMP_SECTION:			\
     case GIMPLE_OMP_MASTER:			\
+    case GIMPLE_OMP_TASKGROUP:			\
     case GIMPLE_OMP_ORDERED:			\
     case GIMPLE_OMP_CRITICAL:			\
     case GIMPLE_OMP_RETURN:			\
--- gcc/gimplify.c.jj	2013-09-18 12:43:23.000000000 +0200
+++ gcc/gimplify.c	2013-09-23 15:06:23.857832390 +0200
@@ -4729,6 +4729,7 @@  is_gimple_stmt (tree t)
     case OMP_SECTION:
     case OMP_SINGLE:
     case OMP_MASTER:
+    case OMP_TASKGROUP:
     case OMP_ORDERED:
     case OMP_CRITICAL:
     case OMP_TASK:
@@ -8236,6 +8237,7 @@  gimplify_expr (tree *expr_p, gimple_seq
 
 	case OMP_SECTION:
 	case OMP_MASTER:
+	case OMP_TASKGROUP:
 	case OMP_ORDERED:
 	case OMP_CRITICAL:
 	  {
@@ -8251,6 +8253,19 @@  gimplify_expr (tree *expr_p, gimple_seq
 	      case OMP_MASTER:
 	        g = gimple_build_omp_master (body);
 		break;
+	      case OMP_TASKGROUP:
+		{
+		  gimple_seq cleanup = NULL;
+		  tree fn
+		    = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_END);
+		  g = gimple_build_call (fn, 0);
+		  gimple_seq_add_stmt (&cleanup, g);
+		  g = gimple_build_try (body, cleanup, GIMPLE_TRY_FINALLY);
+		  body = NULL;
+		  gimple_seq_add_stmt (&body, g);
+		  g = gimple_build_omp_taskgroup (body);
+		}
+		break;
 	      case OMP_ORDERED:
 		g = gimple_build_omp_ordered (body);
 		break;
@@ -8583,6 +8598,7 @@  gimplify_expr (tree *expr_p, gimple_seq
 		  && code != OMP_CRITICAL
 		  && code != OMP_FOR
 		  && code != OMP_MASTER
+		  && code != OMP_TASKGROUP
 		  && code != OMP_ORDERED
 		  && code != OMP_PARALLEL
 		  && code != OMP_SECTIONS
--- gcc/omp-low.c.jj	2013-09-19 19:00:45.000000000 +0200
+++ gcc/omp-low.c	2013-09-24 18:47:57.457861620 +0200
@@ -2272,7 +2272,19 @@  check_omp_nesting_restrictions (gimple s
 	      else if (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))
 		       == BUILT_IN_GOMP_CANCEL
 		       && !integer_zerop (gimple_call_arg (stmt, 1)))
-		ctx->cancellable = true;
+		{
+		  ctx->cancellable = true;
+		  if (find_omp_clause (gimple_omp_for_clauses (ctx->stmt),
+				       OMP_CLAUSE_NOWAIT))
+		    warning_at (gimple_location (stmt), 0,
+				"%<#pragma omp cancel for%> inside "
+				"%<nowait%> for construct");
+		  if (find_omp_clause (gimple_omp_for_clauses (ctx->stmt),
+				       OMP_CLAUSE_ORDERED))
+		    warning_at (gimple_location (stmt), 0,
+				"%<#pragma omp cancel for%> inside "
+				"%<ordered%> for construct");
+		}
 	      kind = "for";
 	      break;
 	    case 4:
@@ -2284,13 +2296,27 @@  check_omp_nesting_restrictions (gimple s
 		       && !integer_zerop (gimple_call_arg (stmt, 1)))
 		{
 		  if (gimple_code (ctx->stmt) == GIMPLE_OMP_SECTIONS)
-		    ctx->cancellable = true;
+		    {
+		      ctx->cancellable = true;
+		      if (find_omp_clause (gimple_omp_sections_clauses
+								(ctx->stmt),
+					   OMP_CLAUSE_NOWAIT))
+			warning_at (gimple_location (stmt), 0,
+				    "%<#pragma omp cancel sections%> inside "
+				    "%<nowait%> sections construct");
+		    }
 		  else
 		    {
 		      gcc_assert (ctx->outer
 				  && gimple_code (ctx->outer->stmt)
 				     == GIMPLE_OMP_SECTIONS);
 		      ctx->outer->cancellable = true;
+		      if (find_omp_clause (gimple_omp_sections_clauses
+							(ctx->outer->stmt),
+					   OMP_CLAUSE_NOWAIT))
+			warning_at (gimple_location (stmt), 0,
+				    "%<#pragma omp cancel sections%> inside "
+				    "%<nowait%> sections construct");
 		    }
 		}
 	      kind = "sections";
@@ -2553,6 +2579,7 @@  scan_omp_1_stmt (gimple_stmt_iterator *g
 
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_CRITICAL:
       ctx = new_omp_context (stmt, ctx);
@@ -7034,6 +7061,7 @@  expand_omp_synch (struct omp_region *reg
   si = gsi_last_bb (entry_bb);
   gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE
 	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASTER
+	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TASKGROUP
 	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ORDERED
 	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL
 	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TEAMS);
@@ -7988,6 +8016,7 @@  expand_omp (struct omp_region *region)
 	  break;
 
 	case GIMPLE_OMP_MASTER:
+	case GIMPLE_OMP_TASKGROUP:
 	case GIMPLE_OMP_ORDERED:
 	case GIMPLE_OMP_CRITICAL:
 	case GIMPLE_OMP_TEAMS:
@@ -8309,12 +8338,12 @@  lower_omp_sections (gimple_stmt_iterator
   gimple_seq_add_stmt (&new_body, t);
 
   gimple_seq_add_seq (&new_body, olist);
+  if (ctx->cancellable)
+    gimple_seq_add_stmt (&new_body, gimple_build_label (ctx->cancel_label));
   gimple_seq_add_seq (&new_body, dlist);
 
   new_body = maybe_catch_exception (new_body);
 
-  if (ctx->cancellable)
-    gimple_seq_add_stmt (&new_body, gimple_build_label (ctx->cancel_label));
   t = gimple_build_omp_return
         (!!find_omp_clause (gimple_omp_sections_clauses (stmt),
 			    OMP_CLAUSE_NOWAIT));
@@ -8543,6 +8572,33 @@  lower_omp_master (gimple_stmt_iterator *
 }
 
 
+/* Expand code for an OpenMP taskgroup directive.  */
+
+static void
+lower_omp_taskgroup (gimple_stmt_iterator *gsi_p, omp_context *ctx)
+{
+  gimple stmt = gsi_stmt (*gsi_p), bind, x;
+  tree block = make_node (BLOCK);
+
+  bind = gimple_build_bind (NULL, NULL, block);
+  gsi_replace (gsi_p, bind, true);
+  gimple_bind_add_stmt (bind, stmt);
+
+  x = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_START),
+			 0);
+  gimple_bind_add_stmt (bind, x);
+
+  lower_omp (gimple_omp_body_ptr (stmt), ctx);
+  gimple_bind_add_seq (bind, gimple_omp_body (stmt));
+  gimple_omp_set_body (stmt, NULL);
+
+  gimple_bind_add_stmt (bind, gimple_build_omp_return (true));
+
+  gimple_bind_append_vars (bind, ctx->block_vars);
+  BLOCK_VARS (block) = ctx->block_vars;
+}
+
+
 /* Expand code for an OpenMP ordered directive.  */
 
 static void
@@ -8846,13 +8902,14 @@  lower_omp_for (gimple_stmt_iterator *gsi
   /* After the loop, add exit clauses.  */
   lower_reduction_clauses (gimple_omp_for_clauses (stmt), &body, ctx);
 
+  if (ctx->cancellable)
+    gimple_seq_add_stmt (&body, gimple_build_label (ctx->cancel_label));
+
   gimple_seq_add_seq (&body, dlist);
 
   body = maybe_catch_exception (body);
 
   /* Region exit marker goes at the end of the loop body.  */
-  if (ctx->cancellable)
-    gimple_seq_add_stmt (&body, gimple_build_label (ctx->cancel_label));
   gimple_seq_add_stmt (&body, gimple_build_omp_return (fd.have_nowait));
   maybe_add_implicit_barrier_cancel (ctx, &body);
   pop_gimplify_context (new_stmt);
@@ -9264,10 +9321,10 @@  lower_omp_taskreg (gimple_stmt_iterator
   gimple_seq_add_seq (&new_body, par_ilist);
   gimple_seq_add_seq (&new_body, par_body);
   gimple_seq_add_seq (&new_body, par_rlist);
-  gimple_seq_add_seq (&new_body, par_olist);
-  new_body = maybe_catch_exception (new_body);
   if (ctx->cancellable)
     gimple_seq_add_stmt (&new_body, gimple_build_label (ctx->cancel_label));
+  gimple_seq_add_seq (&new_body, par_olist);
+  new_body = maybe_catch_exception (new_body);
   gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
   gimple_omp_set_body (stmt, new_body);
 
@@ -9759,6 +9816,11 @@  lower_omp_1 (gimple_stmt_iterator *gsi_p
       gcc_assert (ctx);
       lower_omp_master (gsi_p, ctx);
       break;
+    case GIMPLE_OMP_TASKGROUP:
+      ctx = maybe_lookup_ctx (stmt);
+      gcc_assert (ctx);
+      lower_omp_taskgroup (gsi_p, ctx);
+      break;
     case GIMPLE_OMP_ORDERED:
       ctx = maybe_lookup_ctx (stmt);
       gcc_assert (ctx);
@@ -10025,6 +10087,9 @@  diagnose_sb_1 (gimple_stmt_iterator *gsi
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_CRITICAL:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
+    case GIMPLE_OMP_TASKGROUP:
       /* The minimal context here is just the current OMP construct.  */
       inner_context = stmt;
       wi->info = inner_context;
@@ -10080,6 +10145,9 @@  diagnose_sb_2 (gimple_stmt_iterator *gsi
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_CRITICAL:
+    case GIMPLE_OMP_TARGET:
+    case GIMPLE_OMP_TEAMS:
+    case GIMPLE_OMP_TASKGROUP:
       wi->info = stmt;
       walk_gimple_seq_mod (gimple_omp_body_ptr (stmt), diagnose_sb_2, NULL, wi);
       wi->info = context;
--- gcc/tree-inline.c.jj	2013-09-18 12:17:56.000000000 +0200
+++ gcc/tree-inline.c	2013-09-23 15:06:23.857832390 +0200
@@ -1345,6 +1345,11 @@  remap_gimple_stmt (gimple stmt, copy_bod
 	  copy = gimple_build_omp_master (s1);
 	  break;
 
+	case GIMPLE_OMP_TASKGROUP:
+	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+	  copy = gimple_build_omp_taskgroup (s1);
+	  break;
+
 	case GIMPLE_OMP_ORDERED:
 	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
 	  copy = gimple_build_omp_ordered (s1);
@@ -3841,6 +3846,7 @@  estimate_num_insns (gimple stmt, eni_wei
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_SECTIONS:
--- gcc/gimple-low.c.jj	2013-09-13 16:46:32.000000000 +0200
+++ gcc/gimple-low.c	2013-09-23 15:06:23.857832390 +0200
@@ -424,6 +424,7 @@  lower_stmt (gimple_stmt_iterator *gsi, s
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_SINGLE:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_OMP_RETURN:
--- gcc/tree.h.jj	2013-09-18 12:43:23.000000000 +0200
+++ gcc/tree.h	2013-09-23 14:21:16.824238761 +0200
@@ -1185,6 +1185,8 @@  extern void protected_set_expr_location
 
 #define OMP_MASTER_BODY(NODE)	   TREE_OPERAND (OMP_MASTER_CHECK (NODE), 0)
 
+#define OMP_TASKGROUP_BODY(NODE)   TREE_OPERAND (OMP_TASKGROUP_CHECK (NODE), 0)
+
 #define OMP_ORDERED_BODY(NODE)	   TREE_OPERAND (OMP_ORDERED_CHECK (NODE), 0)
 
 #define OMP_CRITICAL_BODY(NODE)    TREE_OPERAND (OMP_CRITICAL_CHECK (NODE), 0)
--- gcc/tree.def.jj	2013-08-27 22:06:18.000000000 +0200
+++ gcc/tree.def	2013-09-23 14:19:07.617876632 +0200
@@ -1071,6 +1071,10 @@  DEFTREECODE (OMP_SECTION, "omp_section",
    Operand 0: OMP_MASTER_BODY: Master section body.  */
 DEFTREECODE (OMP_MASTER, "omp_master", tcc_statement, 1)
 
+/* OpenMP - #pragma omp taskgroup
+   Operand 0: OMP_TASKGROUP_BODY: Taskgroup body.  */
+DEFTREECODE (OMP_TASKGROUP, "omp_taskgroup", tcc_statement, 1)
+
 /* OpenMP - #pragma omp ordered
    Operand 0: OMP_ORDERED_BODY: Master section body.  */
 DEFTREECODE (OMP_ORDERED, "omp_ordered", tcc_statement, 1)
--- gcc/testsuite/g++.dg/gomp/target-1.C.jj	2013-09-24 10:26:09.896136098 +0200
+++ gcc/testsuite/g++.dg/gomp/target-1.C	2013-09-24 10:29:46.237046033 +0200
@@ -0,0 +1,32 @@ 
+// { dg-do compile }
+
+void
+foo (int x)
+{
+  bad1:				// { dg-error "jump to label" }
+  #pragma omp target
+    goto bad1;			// { dg-error "from here|exits OpenMP" }
+
+  goto bad2;			// { dg-error "from here" }
+  #pragma omp target
+    {
+      bad2: ;			// { dg-error "jump to label|enters OpenMP" }
+    }
+
+  #pragma omp target
+    {
+      int i;
+      goto ok1;
+      for (i = 0; i < 10; ++i)
+	{ ok1: break; }
+    }
+
+  switch (x)
+  {
+  #pragma omp target
+    { case 0:; }		// { dg-error "jump|enters" }
+  }
+}
+
+// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 }
+// { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 }
--- gcc/testsuite/g++.dg/gomp/target-2.C.jj	2013-09-24 10:26:09.896136098 +0200
+++ gcc/testsuite/g++.dg/gomp/target-2.C	2013-09-24 10:30:17.235890414 +0200
@@ -0,0 +1,32 @@ 
+// { dg-do compile }
+
+void
+foo (int x, int y)
+{
+  bad1:				// { dg-error "jump to label" }
+  #pragma omp target data map(tofrom: y)
+    goto bad1;			// { dg-error "from here|exits OpenMP" }
+
+  goto bad2;			// { dg-error "from here" }
+  #pragma omp target data map(tofrom: y)
+    {
+      bad2: ;			// { dg-error "jump to label|enters OpenMP" }
+    }
+
+  #pragma omp target data map(tofrom: y)
+    {
+      int i;
+      goto ok1;
+      for (i = 0; i < 10; ++i)
+	{ ok1: break; }
+    }
+
+  switch (x)
+  {
+  #pragma omp target data map(tofrom: y)
+    { case 0:; }		// { dg-error "jump|enters" }
+  }
+}
+
+// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 }
+// { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 }
--- gcc/testsuite/g++.dg/gomp/teams-1.C.jj	2013-09-24 10:26:09.896136098 +0200
+++ gcc/testsuite/g++.dg/gomp/teams-1.C	2013-09-24 10:31:45.907449396 +0200
@@ -0,0 +1,66 @@ 
+// { dg-do compile }
+
+void
+foo (int x)
+{
+  bad1:				// { dg-error "jump to label" }
+  #pragma omp target teams
+    goto bad1;			// { dg-error "from here|exits OpenMP" }
+
+  goto bad2;			// { dg-error "from here" }
+  #pragma omp target teams
+    {
+      bad2: ;			// { dg-error "jump to label|enters OpenMP" }
+    }
+
+  #pragma omp target teams
+    {
+      int i;
+      goto ok1;
+      for (i = 0; i < 10; ++i)
+	{ ok1: break; }
+    }
+
+  switch (x)
+  {
+  #pragma omp target teams
+    { case 0:; }		// { dg-error "jump|enters" }
+  }
+}
+
+void
+bar (int x)
+{
+  bad1:				// { dg-error "jump to label" }
+  #pragma omp target
+  #pragma omp teams
+    goto bad1;			// { dg-error "from here|exits OpenMP" }
+
+  goto bad2;			// { dg-error "from here" }
+  #pragma omp target
+  #pragma omp teams
+    {
+      bad2: ;			// { dg-error "jump to label|enters OpenMP" }
+    }
+
+  #pragma omp target
+  #pragma omp teams
+    {
+      int i;
+      goto ok1;
+      for (i = 0; i < 10; ++i)
+	{ ok1: break; }
+    }
+
+  switch (x)
+  {
+  #pragma omp target
+  #pragma omp teams
+    { case 0:; }		// { dg-error "jump|enters" }
+  }
+}
+
+// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 }
+// { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 }
+// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 37 }
+// { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 39 }
--- gcc/testsuite/g++.dg/gomp/taskgroup-1.C.jj	2013-09-24 10:26:09.896136098 +0200
+++ gcc/testsuite/g++.dg/gomp/taskgroup-1.C	2013-09-24 10:30:38.378788871 +0200
@@ -0,0 +1,32 @@ 
+// { dg-do compile }
+
+void
+foo (int x)
+{
+  bad1:				// { dg-error "jump to label" }
+  #pragma omp taskgroup
+    goto bad1;			// { dg-error "from here|exits OpenMP" }
+
+  goto bad2;			// { dg-error "from here" }
+  #pragma omp taskgroup
+    {
+      bad2: ;			// { dg-error "jump to label|enters OpenMP" }
+    }
+
+  #pragma omp taskgroup
+    {
+      int i;
+      goto ok1;
+      for (i = 0; i < 10; ++i)
+	{ ok1: break; }
+    }
+
+  switch (x)
+  {
+  #pragma omp taskgroup
+    { case 0:; }		// { dg-error "jump|enters" }
+  }
+}
+
+// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 }
+// { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 }
--- gcc/testsuite/gcc.dg/gomp/teams-1.c.jj	2013-09-24 10:20:26.073866380 +0200
+++ gcc/testsuite/gcc.dg/gomp/teams-1.c	2013-09-24 10:21:11.990638320 +0200
@@ -0,0 +1,61 @@ 
+/* { dg-do compile } */
+
+void
+foo (int x)
+{
+  bad1:
+  #pragma omp target teams
+    goto bad1;			/* { dg-error "invalid branch" } */
+
+  goto bad2;			/* { dg-error "invalid entry" } */
+  #pragma omp target teams
+    {
+      bad2: ;
+    }
+
+  #pragma omp target teams
+    {
+      int i;
+      goto ok1;
+      for (i = 0; i < 10; ++i)
+	{ ok1: break; }
+    }
+
+  switch (x)			/* { dg-error "invalid entry" } */
+  {
+  #pragma omp target teams
+    { case 0:; }
+  }
+}
+
+void
+bar (int x)
+{
+  bad1:
+  #pragma omp target
+  #pragma omp teams
+    goto bad1;			/* { dg-error "invalid branch" } */
+
+  goto bad2;			/* { dg-error "invalid entry" } */
+  #pragma omp target
+  #pragma omp teams
+    {
+      bad2: ;
+    }
+
+  #pragma omp target
+  #pragma omp teams
+    {
+      int i;
+      goto ok1;
+      for (i = 0; i < 10; ++i)
+	{ ok1: break; }
+    }
+
+  switch (x)			/* { dg-error "invalid entry" } */
+  {
+  #pragma omp target
+  #pragma omp teams
+    { case 0:; }
+  }
+}
--- gcc/testsuite/gcc.dg/gomp/taskgroup-1.c.jj	2013-09-24 10:19:33.056133832 +0200
+++ gcc/testsuite/gcc.dg/gomp/taskgroup-1.c	2013-09-24 10:19:46.514062767 +0200
@@ -0,0 +1,29 @@ 
+/* { dg-do compile } */
+
+void
+foo (int x)
+{
+  bad1:
+  #pragma omp taskgroup
+    goto bad1;			/* { dg-error "invalid branch" } */
+
+  goto bad2;			/* { dg-error "invalid entry" } */
+  #pragma omp taskgroup
+    {
+      bad2: ;
+    }
+
+  #pragma omp taskgroup
+    {
+      int i;
+      goto ok1;
+      for (i = 0; i < 10; ++i)
+	{ ok1: break; }
+    }
+
+  switch (x)			/* { dg-error "invalid entry" } */
+  {
+  #pragma omp taskgroup
+    { case 0:; }
+  }
+}
--- gcc/testsuite/gcc.dg/gomp/target-2.c.jj	2013-09-24 10:18:35.710422631 +0200
+++ gcc/testsuite/gcc.dg/gomp/target-2.c	2013-09-24 10:19:19.410224872 +0200
@@ -0,0 +1,29 @@ 
+/* { dg-do compile } */
+
+void
+foo (int x, int y)
+{
+  bad1:
+  #pragma omp target data map(tofrom: y)
+    goto bad1;			/* { dg-error "invalid branch" } */
+
+  goto bad2;			/* { dg-error "invalid entry" } */
+  #pragma omp target data map(tofrom: y)
+    {
+      bad2: ;
+    }
+
+  #pragma omp target data map(tofrom: y)
+    {
+      int i;
+      goto ok1;
+      for (i = 0; i < 10; ++i)
+	{ ok1: break; }
+    }
+
+  switch (x)			/* { dg-error "invalid entry" } */
+  {
+  #pragma omp target data map(tofrom: y)
+    { case 0:; }
+  }
+}
--- gcc/testsuite/gcc.dg/gomp/target-1.c.jj	2013-09-24 10:18:27.956460166 +0200
+++ gcc/testsuite/gcc.dg/gomp/target-1.c	2013-09-24 10:17:59.216584442 +0200
@@ -0,0 +1,29 @@ 
+/* { dg-do compile } */
+
+void
+foo (int x)
+{
+  bad1:
+  #pragma omp target
+    goto bad1;			/* { dg-error "invalid branch" } */
+
+  goto bad2;			/* { dg-error "invalid entry" } */
+  #pragma omp target
+    {
+      bad2: ;
+    }
+
+  #pragma omp target
+    {
+      int i;
+      goto ok1;
+      for (i = 0; i < 10; ++i)
+	{ ok1: break; }
+    }
+
+  switch (x)			/* { dg-error "invalid entry" } */
+  {
+  #pragma omp target
+    { case 0:; }
+  }
+}
--- gcc/testsuite/c-c++-common/gomp/cancel-1.c.jj	2013-09-23 14:07:57.200202039 +0200
+++ gcc/testsuite/c-c++-common/gomp/cancel-1.c	2013-09-24 10:32:34.261202645 +0200
@@ -0,0 +1,396 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+void
+f1 (void)
+{
+  #pragma omp cancel parallel			/* { dg-error "orphaned" } */
+  #pragma omp cancel for			/* { dg-error "orphaned" } */
+  #pragma omp cancel sections			/* { dg-error "orphaned" } */
+  #pragma omp cancel taskgroup			/* { dg-error "orphaned" } */
+  #pragma omp cancellation point parallel	/* { dg-error "orphaned" } */
+  #pragma omp cancellation point for		/* { dg-error "orphaned" } */
+  #pragma omp cancellation point sections	/* { dg-error "orphaned" } */
+  #pragma omp cancellation point taskgroup	/* { dg-error "orphaned" } */
+}
+
+void
+f2 (void)
+{
+  int i;
+  #pragma omp parallel
+  {
+    #pragma omp cancel parallel
+    #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+    #pragma omp cancel sections			/* { dg-error "not closely nested inside" } */
+    #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point parallel
+    #pragma omp cancellation point for		/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    #pragma omp master
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+    #pragma omp single
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+    #pragma omp critical
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+    #pragma omp taskgroup
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+    #pragma omp task
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup
+    }
+    #pragma omp for
+    for (i = 0; i < 10; i++)
+      {
+	#pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel for
+	#pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point for
+	#pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */
+      }
+    #pragma omp for ordered
+    for (i = 0; i < 10; i++)
+      #pragma omp ordered
+      {
+	#pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */
+      }
+    #pragma omp sections
+    {
+      {
+	#pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel sections
+	#pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point sections
+	#pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */
+      }
+      #pragma omp section
+      {
+	#pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel sections
+	#pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point sections
+	#pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */
+      }
+    }
+    #pragma omp target data
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+    #pragma omp target
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+  }
+  #pragma omp target data
+  {
+    #pragma omp cancel parallel			/* { dg-error "not closely nested inside" } */
+    #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+    #pragma omp cancel sections			/* { dg-error "not closely nested inside" } */
+    #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point for		/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+  }
+  #pragma omp target
+  {
+    #pragma omp cancel parallel			/* { dg-error "not closely nested inside" } */
+    #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+    #pragma omp cancel sections			/* { dg-error "not closely nested inside" } */
+    #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point for		/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+  }
+  #pragma omp target teams
+  {
+    #pragma omp cancel parallel			/* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+    #pragma omp cancel for			/* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+    #pragma omp cancel sections			/* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+    #pragma omp cancel taskgroup		/* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+    #pragma omp cancellation point parallel	/* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+    #pragma omp cancellation point for		/* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+    #pragma omp cancellation point sections	/* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+    #pragma omp cancellation point taskgroup	/* { dg-error "only distribute or parallel constructs are allowed to be closely nested" } */
+  }
+  #pragma omp target teams distribute
+  for (i = 0; i < 10; i++)
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+  #pragma omp for
+  for (i = 0; i < 10; i++)
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+  #pragma omp for
+  for (i = 0; i < 10; i++)
+    #pragma omp target data
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+  #pragma omp for
+  for (i = 0; i < 10; i++)
+    #pragma omp target
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+  #pragma omp for ordered
+  for (i = 0; i < 10; i++)
+    #pragma omp ordered
+      #pragma omp target data
+      {
+	#pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */
+      }
+  #pragma omp for ordered
+  for (i = 0; i < 10; i++)
+    #pragma omp ordered
+      #pragma omp target
+      {
+	#pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+	#pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */
+      }
+  #pragma omp sections
+  {
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+    #pragma omp section
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+  }
+  #pragma omp sections
+  {
+    #pragma omp target data
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+    #pragma omp section
+    #pragma omp target data
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+  }
+  #pragma omp sections
+  {
+    #pragma omp target
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+    #pragma omp section
+    #pragma omp target
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+  }
+  #pragma omp task
+  {
+    #pragma omp cancel parallel			/* { dg-error "not closely nested inside" } */
+    #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+    #pragma omp cancel sections			/* { dg-error "not closely nested inside" } */
+    #pragma omp cancel taskgroup
+    #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point for		/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+    #pragma omp cancellation point taskgroup
+    #pragma omp taskgroup
+    {
+      #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel sections		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancel taskgroup		/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point parallel	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point for	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point sections	/* { dg-error "not closely nested inside" } */
+      #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
+    }
+  }
+}
+
+void
+f3 (void)
+{
+  int i;
+  #pragma omp for nowait
+  for (i = 0; i < 10; i++)
+    {
+      #pragma omp cancel for		/* { dg-warning "nowait" } */
+    }
+  #pragma omp sections nowait
+  {
+    {
+      #pragma omp cancel sections	/* { dg-warning "nowait" } */
+    }
+    #pragma omp section
+    {
+      #pragma omp cancel sections	/* { dg-warning "nowait" } */
+    }
+  }
+  #pragma omp for ordered
+  for (i = 0; i < 10; i++)
+    {
+      #pragma omp cancel for		/* { dg-warning "ordered" } */
+      #pragma omp ordered
+      {
+      }
+    }
+}
--- gcc/tree-pretty-print.c.jj	2013-09-18 12:43:23.000000000 +0200
+++ gcc/tree-pretty-print.c	2013-09-23 15:06:23.857832390 +0200
@@ -2478,6 +2478,10 @@  dump_generic_node (pretty_printer *buffe
       pp_string (buffer, "#pragma omp master");
       goto dump_omp_body;
 
+    case OMP_TASKGROUP:
+      pp_string (buffer, "#pragma omp taskgroup");
+      goto dump_omp_body;
+
     case OMP_ORDERED:
       pp_string (buffer, "#pragma omp ordered");
       goto dump_omp_body;
--- gcc/gimple.c.jj	2013-09-13 16:52:32.000000000 +0200
+++ gcc/gimple.c	2013-09-23 15:06:23.857832390 +0200
@@ -1007,6 +1007,22 @@  gimple_build_omp_master (gimple_seq body
 }
 
 
+/* Build a GIMPLE_OMP_TASKGROUP statement.
+
+   BODY is the sequence of statements to be executed by the taskgroup
+   construct.  */
+
+gimple
+gimple_build_omp_taskgroup (gimple_seq body)
+{
+  gimple p = gimple_alloc (GIMPLE_OMP_TASKGROUP, 0);
+  if (body)
+    gimple_omp_set_body (p, body);
+
+  return p;
+}
+
+
 /* Build a GIMPLE_OMP_CONTINUE statement.
 
    CONTROL_DEF is the definition of the control variable.
@@ -1837,6 +1853,7 @@  walk_gimple_stmt (gimple_stmt_iterator *
       /* FALL THROUGH.  */
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_PARALLEL:
@@ -2371,6 +2388,7 @@  gimple_copy (gimple stmt)
 	case GIMPLE_OMP_TEAMS:
 	case GIMPLE_OMP_SECTION:
 	case GIMPLE_OMP_MASTER:
+	case GIMPLE_OMP_TASKGROUP:
 	case GIMPLE_OMP_ORDERED:
 	copy_omp_body:
 	  new_seq = gimple_seq_copy (gimple_omp_body (stmt));
--- gcc/c-family/c-common.h.jj	2013-09-13 16:45:28.000000000 +0200
+++ gcc/c-family/c-common.h	2013-09-23 14:53:25.558665832 +0200
@@ -1172,6 +1172,7 @@  enum c_omp_clause_split
 };
 
 extern tree c_finish_omp_master (location_t, tree);
+extern tree c_finish_omp_taskgroup (location_t, tree);
 extern tree c_finish_omp_critical (location_t, tree, tree);
 extern tree c_finish_omp_ordered (location_t, tree);
 extern void c_finish_omp_barrier (location_t);
--- gcc/c-family/c-omp.c.jj	2013-08-19 12:07:50.000000000 +0200
+++ gcc/c-family/c-omp.c	2013-09-23 15:06:23.857832390 +0200
@@ -42,6 +42,17 @@  c_finish_omp_master (location_t loc, tre
   return t;
 }
 
+/* Complete a #pragma omp taskgroup construct.  STMT is the structured-block
+   that follows the pragma.  LOC is the l*/
+
+tree
+c_finish_omp_taskgroup (location_t loc, tree stmt)
+{
+  tree t = add_stmt (build1 (OMP_TASKGROUP, void_type_node, stmt));
+  SET_EXPR_LOCATION (t, loc);
+  return t;
+}
+
 /* Complete a #pragma omp critical construct.  STMT is the structured-block
    that follows the pragma, NAME is the identifier in the pragma, or null
    if it was omitted.  LOC is the location of the #pragma.  */
--- gcc/gimple.def.jj	2013-09-05 09:19:03.000000000 +0200
+++ gcc/gimple.def	2013-09-23 14:20:39.121419992 +0200
@@ -276,6 +276,10 @@  DEFGSCODE(GIMPLE_OMP_FOR, "gimple_omp_fo
    BODY is the sequence of statements to execute in the master section.  */
 DEFGSCODE(GIMPLE_OMP_MASTER, "gimple_omp_master", GSS_OMP)
 
+/* GIMPLE_OMP_TASKGROUP <BODY> represents #pragma omp taskgroup.
+   BODY is the sequence of statements to execute in the taskgroup section.  */
+DEFGSCODE(GIMPLE_OMP_TASKGROUP, "gimple_omp_taskgroup", GSS_OMP)
+
 /* GIMPLE_OMP_ORDERED <BODY> represents #pragma omp ordered.
    BODY is the sequence of statements to execute in the ordered section.  */
 DEFGSCODE(GIMPLE_OMP_ORDERED, "gimple_omp_ordered", GSS_OMP)