--- gcc/c/c-lang.h.jj	2013-03-20 10:04:58.000000000 +0100
+++ gcc/c/c-lang.h	2013-07-06 17:29:09.733747004 +0200
@@ -55,5 +55,8 @@ struct GTY(()) language_function {
   int warn_about_return_type;
 };
 
+/* If non-zero, implicit "omp declare target" attribute is added into the
+   attribute lists.  */
+extern GTY(()) int current_omp_declare_target_attribute;
 
 #endif /* ! GCC_C_LANG_H */
--- gcc/c/Make-lang.in.jj	2013-06-26 12:13:51.000000000 +0200
+++ gcc/c/Make-lang.in	2013-07-06 17:31:02.763880113 +0200
@@ -181,8 +181,8 @@ c/c-objc-common.o : c/c-objc-common.c c/
 	$(TREE_PRETTY_PRINT_H)
 
 c/c-parser.o : c/c-parser.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
-	$(TM_H) $(TREE_H) $(C_TREE_H) $(C_COMMON_H) $(C_PRAGMA_H) $(CPPLIB_H) \
-	$(GGC_H) $(TIMEVAR_H) $(INPUT_H) $(FLAGS_H) \
+	$(TM_H) $(TREE_H) c/c-lang.h $(C_TREE_H) $(C_COMMON_H) $(C_PRAGMA_H) \
+	$(CPPLIB_H) $(GGC_H) $(TIMEVAR_H) $(INPUT_H) $(FLAGS_H) \
 	gt-c-c-parser.h langhooks.h \
 	$(VEC_H) $(TARGET_H) $(CGRAPH_H) $(PLUGIN_H) \
 	c-family/c-objc.h
--- gcc/c/c-parser.c.jj	2013-07-03 22:15:07.000000000 +0200
+++ gcc/c/c-parser.c	2013-07-06 19:59:14.729863508 +0200
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3.
 #include "timevar.h"
 #include "c-family/c-pragma.h"
 #include "c-tree.h"
+#include "c-lang.h"
 #include "flags.h"
 #include "ggc.h"
 #include "c-family/c-common.h"
@@ -1192,6 +1193,8 @@ static void c_parser_omp_cancellation_po
 enum pragma_context { pragma_external, pragma_struct, pragma_param,
 		      pragma_stmt, pragma_compound };
 static bool c_parser_pragma (c_parser *, enum pragma_context);
+static bool c_parser_omp_target (c_parser *, enum pragma_context);
+static void c_parser_omp_end_declare_target (c_parser *);
 static void c_parser_omp_declare (c_parser *, enum pragma_context);
 
 /* These Objective-C parser functions are only ever called when
@@ -8803,6 +8806,13 @@ c_parser_pragma (c_parser *parser, enum
       c_parser_omp_threadprivate (parser);
       return false;
 
+    case PRAGMA_OMP_TARGET:
+      return c_parser_omp_target (parser, context);
+
+    case PRAGMA_OMP_END_DECLARE_TARGET:
+      c_parser_omp_end_declare_target (parser);
+      return false;
+
     case PRAGMA_OMP_SECTION:
       error_at (c_parser_peek_token (parser)->location,
 		"%<#pragma omp section%> may only be used in "
@@ -8996,6 +9006,8 @@ c_parser_omp_clause_name (c_parser *pars
 	case 't':
 	  if (!strcmp ("taskgroup", p))
 	    result = PRAGMA_OMP_CLAUSE_TASKGROUP;
+	  else if (!strcmp ("thread_limit", p))
+	    result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT;
 	  else if (!strcmp ("to", p))
 	    result = PRAGMA_OMP_CLAUSE_TO;
 	  break;
@@ -9064,22 +9076,70 @@ c_parser_omp_variable_list (c_parser *pa
 	t = lookup_name (c_parser_peek_token (parser)->value);
 
       if (t == NULL_TREE)
-	undeclared_variable (c_parser_peek_token (parser)->location,
-			     c_parser_peek_token (parser)->value);
-      else if (t == error_mark_node)
+	{
+	  undeclared_variable (c_parser_peek_token (parser)->location,
+			       c_parser_peek_token (parser)->value);
+	  t = error_mark_node;
+	}
+
+      c_parser_consume_token (parser);
+
+      if (t == error_mark_node)
 	;
       else if (kind != 0)
 	{
-	  tree u = build_omp_clause (clause_loc, kind);
-	  OMP_CLAUSE_DECL (u) = t;
-	  OMP_CLAUSE_CHAIN (u) = list;
-	  list = u;
+	  switch (kind)
+	    {
+	    case OMP_CLAUSE_MAP:
+	    case OMP_CLAUSE_FROM:
+	    case OMP_CLAUSE_TO:
+	    case OMP_CLAUSE_DEPEND:
+	      while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+		{
+		  tree low_bound = NULL_TREE, length = NULL_TREE;
+
+		  c_parser_consume_token (parser);
+		  if (!c_parser_next_token_is (parser, CPP_COLON))
+		    low_bound = c_parser_expression (parser).value;
+		  if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+		    length = integer_one_node;
+		  else
+		    {
+		      /* Look for `:'.  */
+		      if (!c_parser_require (parser, CPP_COLON,
+					     "expected %<:%>"))
+			{
+			  t = error_mark_node;
+			  break;
+			}
+		      if (!c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+			length = c_parser_expression (parser).value;
+		    }
+		  /* Look for the closing `]'.  */
+		  if (!c_parser_require (parser, CPP_CLOSE_SQUARE,
+					 "expected %<]%>"))
+		    {
+		      t = error_mark_node;
+		      break;
+		    }
+		  t = tree_cons (low_bound, length, t);
+		}
+	      break;
+	    default:
+	      break;
+	    }
+
+	  if (t != error_mark_node)
+	    {
+	      tree u = build_omp_clause (clause_loc, kind);
+	      OMP_CLAUSE_DECL (u) = t;
+	      OMP_CLAUSE_CHAIN (u) = list;
+	      list = u;
+	    }
 	}
       else
 	list = tree_cons (t, NULL_TREE, list);
 
-      c_parser_consume_token (parser);
-
       if (c_parser_next_token_is_not (parser, CPP_COMMA))
 	break;
 
@@ -9401,7 +9461,7 @@ c_parser_omp_clause_private (c_parser *p
      One of: + * - & ^ | && || max min  */
 
 static tree
-c_parser_omp_clause_reduction (c_parser *parser, tree list, bool declare_simd)
+c_parser_omp_clause_reduction (c_parser *parser, tree list)
 {
   location_t clause_loc = c_parser_peek_token (parser)->location;
   if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
@@ -9463,8 +9523,7 @@ c_parser_omp_clause_reduction (c_parser
 	  tree nl, c;
 
 	  nl = c_parser_omp_variable_list (parser, clause_loc,
-					   OMP_CLAUSE_REDUCTION, list,
-					   declare_simd);
+					   OMP_CLAUSE_REDUCTION, list, false);
 	  for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
 	    OMP_CLAUSE_REDUCTION_CODE (c) = code;
 
@@ -9622,24 +9681,7 @@ static tree
 c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED,
 				enum omp_clause_code code, tree list)
 {
-  tree c;
-  location_t loc = c_parser_peek_token (parser)->location;
-
-  for (c = list; c; c = OMP_CLAUSE_CHAIN (c))
-    switch (OMP_CLAUSE_CODE (c))
-      {
-      case OMP_CLAUSE_PARALLEL:
-      case OMP_CLAUSE_FOR:
-      case OMP_CLAUSE_SECTIONS:
-      case OMP_CLAUSE_TASKGROUP:
-	error_at (loc, "only one of %<parallel%>, %<for%>, %<sections%> "
-		       "and %<taskgroup%> clauses can be specified");
-	break;
-      default:
-	break;
-      }
-
-  c = build_omp_clause (loc, code);
+  tree c = build_omp_clause (c_parser_peek_token (parser)->location, code);
   OMP_CLAUSE_CHAIN (c) = list;
 
   return c;
@@ -9690,6 +9732,51 @@ c_parser_omp_clause_num_teams (c_parser
 }
 
 /* OpenMP 4.0:
+   thread_limit ( expression ) */
+
+static tree
+c_parser_omp_clause_thread_limit (c_parser *parser, tree list)
+{
+  location_t num_teams_loc = c_parser_peek_token (parser)->location;
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      location_t expr_loc = c_parser_peek_token (parser)->location;
+      tree c, t = c_parser_expression (parser).value;
+      mark_exp_read (t);
+      t = c_fully_fold (t, false, NULL);
+
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+	{
+	  c_parser_error (parser, "expected integer expression");
+	  return list;
+	}
+
+      /* Attempt to statically determine when the number isn't positive.  */
+      c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
+			   build_int_cst (TREE_TYPE (t), 0));
+      if (CAN_HAVE_LOCATION_P (c))
+	SET_EXPR_LOCATION (c, expr_loc);
+      if (c == boolean_true_node)
+	{
+	  warning_at (expr_loc, 0, "%<thread_limit%> value must be positive");
+	  t = integer_one_node;
+	}
+
+      check_no_duplicate_clause (list, OMP_CLAUSE_THREAD_LIMIT,
+				 "thread_limit");
+
+      c = build_omp_clause (num_teams_loc, OMP_CLAUSE_THREAD_LIMIT);
+      OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t;
+      OMP_CLAUSE_CHAIN (c) = list;
+      list = c;
+    }
+
+  return list;
+}
+
+/* OpenMP 4.0:
    aligned ( variable-list )
    aligned ( variable-list : constant-expression ) */
 
@@ -10106,7 +10193,8 @@ c_parser_omp_clause_uniform (c_parser *p
 
 static tree
 c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
-			  const char *where, bool declare_simd)
+			  const char *where, bool finish_p = true,
+			  bool declare_simd = false)
 {
   tree clauses = NULL;
   bool first = true;
@@ -10121,7 +10209,6 @@ c_parser_omp_all_clauses (c_parser *pars
       if (!first && c_parser_next_token_is (parser, CPP_COMMA))
 	c_parser_consume_token (parser);
 
-      first = false;
       here = c_parser_peek_token (parser)->location;
       c_kind = c_parser_omp_clause_name (parser);
 
@@ -10180,8 +10267,7 @@ c_parser_omp_all_clauses (c_parser *pars
 	  c_name = "private";
 	  break;
 	case PRAGMA_OMP_CLAUSE_REDUCTION:
-	  clauses = c_parser_omp_clause_reduction (parser, clauses,
-						   declare_simd);
+	  clauses = c_parser_omp_clause_reduction (parser, clauses);
 	  c_name = "reduction";
 	  break;
 	case PRAGMA_OMP_CLAUSE_SCHEDULE:
@@ -10211,24 +10297,37 @@ c_parser_omp_all_clauses (c_parser *pars
 	    = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL,
 					      clauses);
 	  c_name = "parallel";
+	  if (!first)
+	    {
+	     clause_not_first:
+	      error_at (here, "%qs must be the first clause of %qs",
+			c_name, where);
+	      clauses = prev;
+	    }
 	  break;
 	case PRAGMA_OMP_CLAUSE_FOR:
 	  clauses
 	    = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR,
 					      clauses);
 	  c_name = "for";
+	  if (!first)
+	    goto clause_not_first;
 	  break;
 	case PRAGMA_OMP_CLAUSE_SECTIONS:
 	  clauses
 	    = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS,
 					      clauses);
 	  c_name = "sections";
+	  if (!first)
+	    goto clause_not_first;
 	  break;
 	case PRAGMA_OMP_CLAUSE_TASKGROUP:
 	  clauses
 	    = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP,
 					      clauses);
 	  c_name = "taskgroup";
+	  if (!first)
+	    goto clause_not_first;
 	  break;
 	case PRAGMA_OMP_CLAUSE_TO:
 	  clauses = c_parser_omp_clause_to (parser, clauses);
@@ -10246,6 +10345,10 @@ c_parser_omp_all_clauses (c_parser *pars
 	  clauses = c_parser_omp_clause_num_teams (parser, clauses);
 	  c_name = "num_teams";
 	  break;
+	case PRAGMA_OMP_CLAUSE_THREAD_LIMIT:
+	  clauses = c_parser_omp_clause_thread_limit (parser, clauses);
+	  c_name = "thread_limit";
+	  break;
 	case PRAGMA_OMP_CLAUSE_ALIGNED:
 	  clauses = c_parser_omp_clause_aligned (parser, clauses,
 						 declare_simd);
@@ -10288,6 +10391,8 @@ c_parser_omp_all_clauses (c_parser *pars
 	  goto saw_error;
 	}
 
+      first = false;
+
       if (((mask >> c_kind) & 1) == 0 && !parser->error)
 	{
 	  /* Remove the invalid clause(s) from the list to avoid
@@ -10300,10 +10405,10 @@ c_parser_omp_all_clauses (c_parser *pars
  saw_error:
   c_parser_skip_to_pragma_eol (parser);
 
-  if (declare_simd)
-    return clauses;
+  if (finish_p)
+    return c_finish_omp_clauses (clauses);
 
-  return c_finish_omp_clauses (clauses);
+  return clauses;
 }
 
 /* OpenMP 2.5:
@@ -10785,7 +10890,7 @@ c_parser_omp_flush (c_parser *parser)
 
 static tree
 c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
-		       tree clauses, tree *par_clauses)
+		       tree clauses, tree *cclauses)
 {
   tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
   tree declv, condv, incrv, initv, ret = NULL;
@@ -11017,10 +11122,11 @@ c_parser_omp_for_loop (location_t loc, c
 			       incrv, body, NULL);
       if (stmt)
 	{
-	  if (par_clauses != NULL)
+	  if (cclauses != NULL
+	      && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL)
 	    {
 	      tree *c;
-	      for (c = par_clauses; *c ; )
+	      for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; )
 		if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE
 		    && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE)
 		  c = &OMP_CLAUSE_CHAIN (*c);
@@ -11069,6 +11175,20 @@ pop_scopes:
   return ret;
 }
 
+/* Helper function for OpenMP parsing, split clauses and call
+   finish_omp_clauses on each of the set of clauses afterwards.  */
+
+static void
+omp_split_clauses (location_t loc, enum tree_code code,
+		   omp_clause_mask mask, tree clauses, tree *cclauses)
+{
+  int i;
+  c_omp_split_clauses (loc, code, mask, clauses, cclauses);
+  for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
+    if (cclauses[i])
+      cclauses[i] = c_finish_omp_clauses (cclauses[i]);
+}
+
 /* OpenMP 4.0:
    #pragma omp simd simd-clause[optseq] new-line
      for-loop
@@ -11086,15 +11206,24 @@ pop_scopes:
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE))
 
 static tree
-c_parser_omp_simd (location_t loc, c_parser *parser)
+c_parser_omp_simd (location_t loc, c_parser *parser,
+		   char *p_name, omp_clause_mask mask, tree *cclauses)
 {
   tree block, clauses, ret;
 
-  clauses = c_parser_omp_all_clauses (parser, OMP_SIMD_CLAUSE_MASK,
-				      "#pragma omp simd", false);
+  strcat (p_name, " simd");
+  mask |= OMP_SIMD_CLAUSE_MASK;
+  mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED);
+
+  clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+  if (cclauses)
+    {
+      omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses);
+      clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
+    }
 
   block = c_begin_compound_stmt (true);
-  ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, NULL);
+  ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, cclauses);
   block = c_end_compound_stmt (loc, block, true);
   add_stmt (block);
 
@@ -11123,12 +11252,15 @@ c_parser_omp_simd (location_t loc, c_par
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
 
 static tree
-c_parser_omp_for (location_t loc, c_parser *parser)
+c_parser_omp_for (location_t loc, c_parser *parser,
+		  char *p_name, omp_clause_mask mask, tree *cclauses)
 {
   tree block, clauses, ret;
-  enum tree_code code = OMP_FOR;
-  omp_clause_mask mask = OMP_FOR_CLAUSE_MASK;
-  const char *p_name = "#pragma omp for";
+
+  strcat (p_name, " for");
+  mask |= OMP_FOR_CLAUSE_MASK;
+  if (cclauses)
+    mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
 
   if (c_parser_next_token_is (parser, CPP_NAME))
     {
@@ -11136,17 +11268,35 @@ c_parser_omp_for (location_t loc, c_pars
 
       if (strcmp (p, "simd") == 0)
 	{
-	  c_parser_consume_token (parser);
-	  /* code = OMP_FOR_SIMD; */
-	  mask |= OMP_SIMD_CLAUSE_MASK;
-	  p_name = "#pragma omp for simd";
+	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+	  if (cclauses == NULL)
+	    cclauses = cclauses_buf;
+
+	  c_parser_consume_token (parser);
+	  block = c_begin_compound_stmt (true);
+	  ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
+	  block = c_end_compound_stmt (loc, block, true);
+	  if (ret == NULL_TREE)
+	    return ret;
+	  ret = make_node (OMP_FOR);
+	  TREE_TYPE (ret) = void_type_node;
+	  OMP_FOR_BODY (ret) = block;
+	  OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+	  SET_EXPR_LOCATION (ret, loc);
+	  add_stmt (ret);
+	  return ret;
 	}
     }
 
-  clauses = c_parser_omp_all_clauses (parser, mask, p_name, false);
+  clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+  if (cclauses)
+    {
+      omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses);
+      clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+    }
 
   block = c_begin_compound_stmt (true);
-  ret = c_parser_omp_for_loop (loc, parser, code, clauses, NULL);
+  ret = c_parser_omp_for_loop (loc, parser, OMP_FOR, clauses, cclauses);
   block = c_end_compound_stmt (loc, block, true);
   add_stmt (block);
 
@@ -11270,12 +11420,22 @@ c_parser_omp_sections_scope (location_t
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
 
 static tree
-c_parser_omp_sections (location_t loc, c_parser *parser)
+c_parser_omp_sections (location_t loc, c_parser *parser,
+		       char *p_name, omp_clause_mask mask, tree *cclauses)
 {
   tree block, clauses, ret;
 
-  clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK,
-				      "#pragma omp sections", false);
+  strcat (p_name, " sections");
+  mask |= OMP_SECTIONS_CLAUSE_MASK;
+  if (cclauses)
+    mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
+
+  clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+  if (cclauses)
+    {
+      omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses);
+      clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS];
+    }
 
   block = c_begin_compound_stmt (true);
   ret = c_parser_omp_sections_scope (loc, parser);
@@ -11307,93 +11467,60 @@ c_parser_omp_sections (location_t loc, c
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND))
 
 static tree
-c_parser_omp_parallel (location_t loc, c_parser *parser)
+c_parser_omp_parallel (location_t loc, c_parser *parser,
+		       char *p_name, omp_clause_mask mask, tree *cclauses)
 {
-  enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL;
-  const char *p_name = "#pragma omp parallel";
-  tree stmt, clauses, par_clause, ws_clause, block;
-  omp_clause_mask mask = OMP_PARALLEL_CLAUSE_MASK;
-  tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT];
+  tree stmt, clauses, block;
+
+  strcat (p_name, " parallel");
+  mask |= OMP_PARALLEL_CLAUSE_MASK;
 
   if (c_parser_next_token_is_keyword (parser, RID_FOR))
     {
+      tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+      if (cclauses == NULL)
+	cclauses = cclauses_buf;
+
       c_parser_consume_token (parser);
-      p_kind = PRAGMA_OMP_PARALLEL_FOR;
-      p_name = "#pragma omp parallel for";
-      mask |= OMP_FOR_CLAUSE_MASK;
-      mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
-      if (c_parser_next_token_is (parser, CPP_NAME))
-	{
-	  const char *p
-	    = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
-	  if (strcmp (p, "simd") == 0)
-	    {
-	      c_parser_consume_token (parser);
-	      p_kind = PRAGMA_OMP_PARALLEL_FOR_SIMD;
-	      p_name = "#pragma omp parallel for simd";
-	      mask |= OMP_SIMD_CLAUSE_MASK;
-	    }
-	}
+      block = c_begin_omp_parallel ();
+      c_parser_omp_for (loc, parser, p_name, mask, cclauses);
+      stmt
+	= c_finish_omp_parallel (loc, cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+				 block);
+      OMP_PARALLEL_COMBINED (stmt) = 1;
+      return stmt;
+    }
+  else if (cclauses)
+    {
+      error_at (loc, "expected %<for%> after %qs", p_name);
+      c_parser_skip_to_pragma_eol (parser);
+      return NULL_TREE;
     }
   else if (c_parser_next_token_is (parser, CPP_NAME))
     {
       const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
       if (strcmp (p, "sections") == 0)
 	{
+	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+	  if (cclauses == NULL)
+	    cclauses = cclauses_buf;
+
 	  c_parser_consume_token (parser);
-	  p_kind = PRAGMA_OMP_PARALLEL_SECTIONS;
-	  p_name = "#pragma omp parallel sections";
-	  mask |= OMP_SECTIONS_CLAUSE_MASK;
-	  mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
+	  block = c_begin_omp_parallel ();
+	  c_parser_omp_sections (loc, parser, p_name, mask, cclauses);
+	  stmt = c_finish_omp_parallel (loc,
+					cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+					block);
+	  OMP_PARALLEL_COMBINED (stmt) = 1;
+	  return stmt;
 	}
     }
 
-  clauses = c_parser_omp_all_clauses (parser, mask, p_name, false);
-
-  switch (p_kind)
-    {
-    case PRAGMA_OMP_PARALLEL:
-      block = c_begin_omp_parallel ();
-      c_parser_statement (parser);
-      stmt = c_finish_omp_parallel (loc, clauses, block);
-      break;
-
-    case PRAGMA_OMP_PARALLEL_FOR:
-      block = c_begin_omp_parallel ();
-      c_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses);
-      par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL];
-      ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
-      c_parser_omp_for_loop (loc, parser, OMP_FOR, ws_clause, &par_clause);
-      stmt = c_finish_omp_parallel (loc, par_clause, block);
-      OMP_PARALLEL_COMBINED (stmt) = 1;
-      break;
+  clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
 
-    case PRAGMA_OMP_PARALLEL_FOR_SIMD:
-      block = c_begin_omp_parallel ();
-      c_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses);
-      par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL];
-      ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
-      c_parser_omp_for_loop (loc, parser, OMP_FOR /*_SIMD*/, ws_clause,
-			     &par_clause);
-      stmt = c_finish_omp_parallel (loc, par_clause, block);
-      OMP_PARALLEL_COMBINED (stmt) = 1;
-      break;
-
-    case PRAGMA_OMP_PARALLEL_SECTIONS:
-      block = c_begin_omp_parallel ();
-      c_omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses);
-      par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL];
-      ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS];
-      stmt = c_parser_omp_sections_scope (loc, parser);
-      if (stmt)
-	OMP_SECTIONS_CLAUSES (stmt) = ws_clause;
-      stmt = c_finish_omp_parallel (loc, par_clause, block);
-      OMP_PARALLEL_COMBINED (stmt) = 1;
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
+  block = c_begin_omp_parallel ();
+  c_parser_statement (parser);
+  stmt = c_finish_omp_parallel (loc, clauses, block);
 
   return stmt;
 }
@@ -11420,7 +11547,7 @@ c_parser_omp_single (location_t loc, c_p
 
   OMP_SINGLE_CLAUSES (stmt)
     = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK,
-				"#pragma omp single", false);
+				"#pragma omp single");
   OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser);
 
   return add_stmt (stmt);
@@ -11449,7 +11576,7 @@ c_parser_omp_task (location_t loc, c_par
   tree clauses, block;
 
   clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK,
-				      "#pragma omp task", false);
+				      "#pragma omp task");
 
   block = c_begin_omp_task ();
   c_parser_statement (parser);
@@ -11519,7 +11646,7 @@ c_parser_omp_cancel (c_parser *parser)
 
   c_parser_consume_pragma (parser);
   tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK,
-					   "#pragma omp cancel", false);
+					   "#pragma omp cancel");
 
   c_finish_omp_cancel (loc, clauses);
 }
@@ -11562,12 +11689,280 @@ c_parser_omp_cancellation_point (c_parse
 
   clauses
     = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK,
-				"#pragma omp cancellation point", false);
+				"#pragma omp cancellation point");
 
   c_finish_omp_cancellation_point (loc, clauses);
 }
 
 /* OpenMP 4.0:
+   #pragma omp distribute distribute-clause[optseq] new-line
+     for-loop  */
+
+#define OMP_DISTRIBUTE_CLAUSE_MASK				\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE))
+
+static tree
+c_parser_omp_distribute (location_t loc, c_parser *parser,
+			 char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+  tree clauses, block, ret;
+
+  strcat (p_name, " distribute");
+  mask |= OMP_DISTRIBUTE_CLAUSE_MASK;
+
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      bool simd = false;
+      bool parallel = false;
+
+      if (strcmp (p, "simd") == 0)
+	simd = true;
+      else
+	parallel = strcmp (p, "parallel") == 0;
+      if (parallel || simd)
+	{
+	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+	  if (cclauses == NULL)
+	    cclauses = cclauses_buf;
+	  c_parser_consume_token (parser);
+	  block = c_begin_compound_stmt (true);
+	  if (simd)
+	    ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
+	  else
+	    ret = c_parser_omp_parallel (loc, parser, p_name, mask, cclauses);
+	  block = c_end_compound_stmt (loc, block, true);
+	  if (ret == NULL)
+	    return ret;
+	  ret = make_node (OMP_DISTRIBUTE);
+	  TREE_TYPE (ret) = void_type_node;
+	  OMP_FOR_BODY (ret) = block;
+	  OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE];
+	  SET_EXPR_LOCATION (ret, loc);
+	  add_stmt (ret);
+	  return ret;
+	}
+    }
+
+  clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+  if (cclauses)
+    {
+      omp_split_clauses (loc, OMP_DISTRIBUTE, mask, clauses, cclauses);
+      clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE];
+    }
+
+  block = c_begin_compound_stmt (true);
+  ret = c_parser_omp_for_loop (loc, parser, OMP_DISTRIBUTE, clauses, NULL);
+  block = c_end_compound_stmt (loc, block, true);
+  add_stmt (block);
+
+  return ret;
+}
+
+/* OpenMP 4.0:
+   # pragma omp teams teams-clause[optseq] new-line
+     structured-block  */
+
+#define OMP_TEAMS_CLAUSE_MASK					\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT))
+
+static tree
+c_parser_omp_teams (location_t loc, c_parser *parser,
+		    char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+  tree clauses, block, ret;
+
+  strcat (p_name, " teams");
+  mask |= OMP_TEAMS_CLAUSE_MASK;
+
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (strcmp (p, "distribute") == 0)
+	{
+	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+	  if (cclauses == NULL)
+	    cclauses = cclauses_buf;
+
+	  c_parser_consume_token (parser);
+	  block = c_begin_compound_stmt (true);
+	  ret = c_parser_omp_distribute (loc, parser, p_name, mask, cclauses);
+	  block = c_end_compound_stmt (loc, block, true);
+	  if (ret == NULL)
+	    return ret;
+	  clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+	  ret = make_node (OMP_TEAMS);
+	  TREE_TYPE (ret) = void_type_node;
+	  OMP_TEAMS_CLAUSES (ret) = clauses;
+	  OMP_TEAMS_BODY (ret) = block;
+	  return add_stmt (ret);
+	}
+    }
+
+  clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+  if (cclauses)
+    {
+      omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses);
+      clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+    }
+
+  tree stmt = make_node (OMP_TEAMS);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_TEAMS_CLAUSES (stmt) = clauses;
+  OMP_TEAMS_BODY (stmt) = c_parser_omp_structured_block (parser);
+
+  return add_stmt (stmt);
+}
+
+/* OpenMP 4.0:
+   # pragma omp target data target-data-clause[optseq] new-line
+     structured-block  */
+
+#define OMP_TARGET_DATA_CLAUSE_MASK				\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static tree
+c_parser_omp_target_data (location_t loc, c_parser *parser)
+{
+  tree stmt = make_node (OMP_TARGET_DATA);
+  TREE_TYPE (stmt) = void_type_node;
+
+  OMP_TARGET_DATA_CLAUSES (stmt)
+    = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
+				"#pragma omp target data");
+  OMP_TARGET_DATA_BODY (stmt) = c_parser_omp_structured_block (parser);
+
+  SET_EXPR_LOCATION (stmt, loc);
+  return add_stmt (stmt);
+}
+
+/* OpenMP 4.0:
+   # pragma omp target update target-update-clause[optseq] new-line */
+
+#define OMP_TARGET_UPDATE_CLAUSE_MASK				\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static bool
+c_parser_omp_target_update (location_t loc, c_parser *parser,
+			    enum pragma_context context)
+{
+  if (context == pragma_stmt)
+    {
+      error_at (loc,
+		"%<#pragma omp target update%> may only be "
+		"used in compound statements");
+      c_parser_skip_to_pragma_eol (parser);
+      return false;
+    }
+
+  tree clauses
+    = c_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK,
+				"#pragma omp target update");
+  if (find_omp_clause (clauses, OMP_CLAUSE_TO) == NULL_TREE
+      && find_omp_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE)
+    {
+      error_at (loc,
+		"%<#pragma omp target update must contain at least one "
+		"%<from%> or %<to%> clauses");
+      return false;
+    }
+
+  tree stmt = make_node (OMP_TARGET_UPDATE);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses;
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+  return false;
+}
+
+/* OpenMP 4.0:
+   # pragma omp target target-clause[optseq] new-line
+     structured-block  */
+
+#define OMP_TARGET_CLAUSE_MASK					\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static bool
+c_parser_omp_target (c_parser *parser, enum pragma_context context)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_pragma (parser);
+
+  if (context != pragma_stmt && context != pragma_compound)
+    {
+      c_parser_error (parser, "expected declaration specifiers");
+      c_parser_skip_to_pragma_eol (parser);
+      return false;
+    }
+
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+      if (strcmp (p, "data") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  c_parser_omp_target_data (loc, parser);
+	  return true;
+	}
+      else if (strcmp (p, "update") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  return c_parser_omp_target_update (loc, parser, context);
+	}
+      else if (strcmp (p, "teams") == 0)
+	{
+	  tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT];
+	  char p_name[sizeof ("#pragma omp target teams distribute "
+			      "parallel for simd")];
+
+	  c_parser_consume_token (parser);
+	  strcpy (p_name, "#pragma omp target");
+	  tree block = c_begin_compound_stmt (true);
+	  tree ret = c_parser_omp_teams (loc, parser, p_name,
+					 OMP_TARGET_CLAUSE_MASK, cclauses);
+	  block = c_end_compound_stmt (loc, block, true);
+	  if (ret == NULL)
+	    return ret;
+	  tree stmt = make_node (OMP_TARGET);
+	  TREE_TYPE (stmt) = void_type_node;
+	  OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
+	  OMP_TARGET_BODY (stmt) = block;
+	  add_stmt (stmt);
+	  return true;
+	}
+    }
+
+  tree stmt = make_node (OMP_TARGET);
+  TREE_TYPE (stmt) = void_type_node;
+
+  OMP_TARGET_CLAUSES (stmt)
+    = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
+				"#pragma omp target");
+  OMP_TARGET_BODY (stmt) = c_parser_omp_structured_block (parser);
+
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+  return true;
+}
+
+/* OpenMP 4.0:
    # pragma omp declare simd declare-simd-clauses[optseq] new-line  */
 
 #define OMP_DECLARE_SIMD_CLAUSE_MASK				\
@@ -11575,7 +11970,6 @@ c_parser_omp_cancellation_point (c_parse
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH))
 
@@ -11584,7 +11978,7 @@ c_parser_omp_declare_simd (c_parser *par
 {
   vec<tree> clauses = vNULL;
   tree cl = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
-				      "#pragma omp declare simd", true);
+				      "#pragma omp declare simd", false, true);
   clauses.safe_push (cl);
 
   while (c_parser_next_token_is (parser, CPP_PRAGMA))
@@ -11606,7 +12000,7 @@ c_parser_omp_declare_simd (c_parser *par
       c_parser_consume_pragma (parser);
       c_parser_consume_token (parser);
       cl = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
-				     "#pragma omp declare simd", true);
+				     "#pragma omp declare simd", false, true);
       clauses.safe_push (cl);
     }
 
@@ -11668,10 +12062,58 @@ c_parser_omp_declare_simd (c_parser *par
   clauses.release ();
 }
 
+/* OpenMP 4.0:
+   # pragma omp declare target new-line
+   declarations and definitions
+   # pragma omp end declare target new-line  */
+
+static void
+c_parser_omp_declare_target (c_parser *parser)
+{
+  c_parser_skip_to_pragma_eol (parser);
+  current_omp_declare_target_attribute++;
+}
+
+static void
+c_parser_omp_end_declare_target (c_parser *parser)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_pragma (parser);
+  if (c_parser_next_token_is (parser, CPP_NAME)
+      && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
+		 "declare") == 0)
+    {
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_NAME)
+	  && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
+		     "target") == 0)
+	c_parser_consume_token (parser);
+      else
+	{
+	  c_parser_error (parser, "expected %<target%>");
+	  c_parser_skip_to_pragma_eol (parser);
+	  return;
+	}
+    }
+  else
+    {
+      c_parser_error (parser, "expected %<declare%>");
+      c_parser_skip_to_pragma_eol (parser);
+      return;
+    }
+  c_parser_skip_to_pragma_eol (parser);
+  if (!current_omp_declare_target_attribute)
+    error_at (loc, "%<#pragma omp end declare target%> without corresponding "
+		   "%<#pragma omp declare target%>");
+  else
+    current_omp_declare_target_attribute--;
+}
+
 /* OpenMP 4.0
    #pragma omp declare simd declare-simd-clauses[optseq] new-line
    #pragma omp declare reduction (reduction-id : typename-list : expression) \
-      identity-clause[opt] new-line */
+      identity-clause[opt] new-line
+   #pragma omp declare target new-line  */
 
 static void
 c_parser_omp_declare (c_parser *parser, enum pragma_context context)
@@ -11692,9 +12134,16 @@ c_parser_omp_declare (c_parser *parser,
 	  c_parser_omp_declare_reduction (parser);
 	  return;
 	}  */
+      if (strcmp (p, "target") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  c_parser_omp_declare_target (parser);
+	  return;
+	}
     }
 
-  c_parser_error (parser, "expected %<simd%> or %<reduction%>");
+  c_parser_error (parser, "expected %<simd%> or %<reduction%> "
+			  "or %<target%>");
   c_parser_skip_to_pragma_eol (parser);
 }
 
@@ -11706,6 +12155,8 @@ c_parser_omp_construct (c_parser *parser
   enum pragma_kind p_kind;
   location_t loc;
   tree stmt;
+  char p_name[sizeof "#pragma omp teams distribute parallel for simd"];
+  omp_clause_mask mask (0);
 
   loc = c_parser_peek_token (parser)->location;
   p_kind = c_parser_peek_token (parser)->pragma_kind;
@@ -11719,8 +12170,13 @@ c_parser_omp_construct (c_parser *parser
     case PRAGMA_OMP_CRITICAL:
       stmt = c_parser_omp_critical (loc, parser);
       break;
+    case PRAGMA_OMP_DISTRIBUTE:
+      strcpy (p_name, "#pragma omp");
+      stmt = c_parser_omp_distribute (loc, parser, p_name, mask, NULL);
+      break;
     case PRAGMA_OMP_FOR:
-      stmt = c_parser_omp_for (loc, parser);
+      strcpy (p_name, "#pragma omp");
+      stmt = c_parser_omp_for (loc, parser, p_name, mask, NULL);
       break;
     case PRAGMA_OMP_MASTER:
       stmt = c_parser_omp_master (loc, parser);
@@ -11729,13 +12185,16 @@ c_parser_omp_construct (c_parser *parser
       stmt = c_parser_omp_ordered (loc, parser);
       break;
     case PRAGMA_OMP_PARALLEL:
-      stmt = c_parser_omp_parallel (loc, parser);
+      strcpy (p_name, "#pragma omp");
+      stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL);
       break;
     case PRAGMA_OMP_SECTIONS:
-      stmt = c_parser_omp_sections (loc, parser);
+      strcpy (p_name, "#pragma omp");
+      stmt = c_parser_omp_sections (loc, parser, p_name, mask, NULL);
       break;
     case PRAGMA_OMP_SIMD:
-      stmt = c_parser_omp_simd (loc, parser);
+      strcpy (p_name, "#pragma omp");
+      stmt = c_parser_omp_simd (loc, parser, p_name, mask, NULL);
       break;
     case PRAGMA_OMP_SINGLE:
       stmt = c_parser_omp_single (loc, parser);
@@ -11746,6 +12205,10 @@ c_parser_omp_construct (c_parser *parser
     case PRAGMA_OMP_TASKGROUP:
       c_parser_omp_taskgroup (parser);
       return;
+    case PRAGMA_OMP_TEAMS:
+      strcpy (p_name, "#pragma omp");
+      stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL);
+      break;
     default:
       gcc_unreachable ();
     }
--- gcc/c/c-decl.c.jj	2013-06-26 12:13:51.000000000 +0200
+++ gcc/c/c-decl.c	2013-07-06 18:34:37.499264094 +0200
@@ -147,6 +147,9 @@ static bool undef_nested_function;
 
 enum machine_mode c_default_pointer_mode = VOIDmode;
 
+/* If non-zero, implicit "omp declare target" attribute is added into the
+   attribute lists.  */
+int current_omp_declare_target_attribute;
 
 /* Each c_binding structure describes one binding of an identifier to
    a decl.  All the decls in a scope - irrespective of namespace - are
@@ -3974,6 +3977,35 @@ groktypename (struct c_type_name *type_n
   return type;
 }
 
+/* Wrapper for decl_attributes that adds some implicit attributes
+   to VAR_DECLs or FUNCTION_DECLs.  */
+
+static tree
+c_decl_attributes (tree *node, tree attributes, int flags)
+{
+  /* Add implicit "omp declare target" attribute if requested.  */
+  if (current_omp_declare_target_attribute
+      && ((TREE_CODE (*node) == VAR_DECL && TREE_STATIC (*node))
+	  || TREE_CODE (*node) == FUNCTION_DECL))
+    {
+      if (TREE_CODE (*node) == VAR_DECL
+	  && ((DECL_CONTEXT (*node)
+	       && TREE_CODE (DECL_CONTEXT (*node)) == FUNCTION_DECL)
+	      || (current_function_decl && !DECL_EXTERNAL (*node))))
+	error ("%q+D in block scope inside of declare target directive",
+	       *node);
+      else if (TREE_CODE (*node) == VAR_DECL
+	       && !COMPLETE_TYPE_P (TREE_TYPE (*node)))
+	error ("%q+D in declare target directive does not have mappable type",
+	       *node);
+      else
+	attributes = tree_cons (get_identifier ("omp declare target"),
+				NULL_TREE, attributes);
+    }
+  return decl_attributes (node, attributes, flags);
+}
+
+
 /* Decode a declarator in an ordinary declaration or data definition.
    This is called as soon as the type information and variable name
    have been parsed, before parsing the initializer if any.
@@ -4108,7 +4140,7 @@ start_decl (struct c_declarator *declara
     DECL_COMMON (decl) = 1;
 
   /* Set attributes here so if duplicate decl, will have proper attributes.  */
-  decl_attributes (&decl, attributes, 0);
+  c_decl_attributes (&decl, attributes, 0);
 
   /* Handle gnu_inline attribute.  */
   if (declspecs->inline_p
@@ -7724,7 +7756,7 @@ start_function (struct c_declspecs *decl
 
   loc = DECL_SOURCE_LOCATION (decl1);
 
-  decl_attributes (&decl1, attributes, 0);
+  c_decl_attributes (&decl1, attributes, 0);
 
   if (DECL_DECLARED_INLINE_P (decl1)
       && DECL_UNINLINABLE (decl1)
--- gcc/c/c-typeck.c.jj	2013-07-03 22:15:07.000000000 +0200
+++ gcc/c/c-typeck.c	2013-07-06 18:24:50.762931048 +0200
@@ -10730,6 +10730,435 @@ c_finish_omp_cancellation_point (locatio
   add_stmt (stmt);
 }
 
+/* Helper function for handle_omp_array_sections.  Called recursively
+   to handle multiple array-section-subscripts.  C is the clause,
+   T current expression (initially OMP_CLAUSE_DECL), which is either
+   a TREE_LIST for array-section-subscript (TREE_PURPOSE is low-bound
+   expression if specified, TREE_VALUE length expression if specified,
+   TREE_CHAIN is what it has been specified after, or some decl.
+   TYPES vector is populated with array section types, MAYBE_ZERO_LEN
+   set to true if any of the array-section-subscript could have length
+   of zero (explicit or implicit), FIRST_NON_ONE is the index of the
+   first array-section-subscript which is known not to have length
+   of one.  Given say:
+   map(a[:b][2:1][:c][:2][:d][e:f][2:5])
+   FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c]
+   all are or may have length of 1, array-section-subscript [:2] is the
+   first one knonwn not to have length 1.  For array-section-subscript
+   <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't
+   0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we
+   can if MAYBE_ZERO_LEN is false.  MAYBE_ZERO_LEN will be true in the above
+   case though, as some lengths could be zero.  */
+
+static tree
+handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
+			     bool &maybe_zero_len, unsigned int &first_non_one,
+			     bool &pointer_based_p)
+{
+  tree ret, low_bound, length, type;
+  if (TREE_CODE (t) != TREE_LIST)
+    {
+      if (t == error_mark_node || TREE_TYPE (t) == error_mark_node)
+	return error_mark_node;
+      if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+	{
+	  if (DECL_P (t))
+	    error_at (OMP_CLAUSE_LOCATION (c),
+		      "%qD is not a variable in %qs clause", t,
+		      omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+	  else
+	    error_at (OMP_CLAUSE_LOCATION (c),
+		      "%qE is not a variable in %qs clause", t,
+		      omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+	  return error_mark_node;
+	}
+      else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND
+	       && TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t))
+	{
+	  error_at (OMP_CLAUSE_LOCATION (c),
+		    "%qD is threadprivate variable in %qs clause", t,
+		    omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+	  return error_mark_node;
+	}
+      if (POINTER_TYPE_P (TREE_TYPE (t))
+	  && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
+	pointer_based_p = true;
+      return t;
+    }
+
+  ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types,
+				     maybe_zero_len, first_non_one,
+				     pointer_based_p);
+  if (ret == error_mark_node || ret == NULL_TREE)
+    return ret;
+
+  type = TREE_TYPE (ret);
+  low_bound = TREE_PURPOSE (t);
+  length = TREE_VALUE (t);
+
+  if (low_bound == error_mark_node || length == error_mark_node)
+    return error_mark_node;
+
+  if (low_bound && !INTEGRAL_TYPE_P (TREE_TYPE (low_bound)))
+    {
+      error_at (OMP_CLAUSE_LOCATION (c),
+		"low bound %qE of array section does not have integral type",
+		low_bound);
+      return error_mark_node;
+    }
+  if (length && !INTEGRAL_TYPE_P (TREE_TYPE (length)))
+    {
+      error_at (OMP_CLAUSE_LOCATION (c),
+		"length %qE of array section does not have integral type",
+		length);
+      return error_mark_node;
+    }
+  if (low_bound
+      && TREE_CODE (low_bound) == INTEGER_CST
+      && TYPE_PRECISION (TREE_TYPE (low_bound))
+	 > TYPE_PRECISION (sizetype))
+    low_bound = fold_convert (sizetype, low_bound);
+  if (length
+      && TREE_CODE (length) == INTEGER_CST
+      && TYPE_PRECISION (TREE_TYPE (length))
+	 > TYPE_PRECISION (sizetype))
+    length = fold_convert (sizetype, length);
+  if (low_bound == NULL_TREE)
+    low_bound = integer_zero_node;
+
+  if (length != NULL_TREE)
+    {
+      if (!integer_nonzerop (length))
+	maybe_zero_len = true;
+      if (first_non_one == types.length ()
+	  && (TREE_CODE (length) != INTEGER_CST || integer_onep (length)))
+	first_non_one++;
+    }
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      if (length == NULL_TREE
+	  && (TYPE_DOMAIN (type) == NULL_TREE
+	      || TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE))
+	{
+	  error_at (OMP_CLAUSE_LOCATION (c),
+		    "for unknown bound array type length expression is "
+		    "not optional");
+	  return error_mark_node;
+	}
+      if (TREE_CODE (low_bound) == INTEGER_CST
+	  && tree_int_cst_sgn (low_bound) == -1)
+	{
+	  error_at (OMP_CLAUSE_LOCATION (c),
+		    "negative low bound in array section in %qs clause",
+		    omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+	  return error_mark_node;
+	}
+      if (length != NULL_TREE
+	  && TREE_CODE (length) == INTEGER_CST
+	  && tree_int_cst_sgn (length) == -1)
+	{
+	  error_at (OMP_CLAUSE_LOCATION (c),
+		    "negative length in array section in %qs clause",
+		    omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+	  return error_mark_node;
+	}
+      if (TYPE_DOMAIN (type)
+	  && TYPE_MAX_VALUE (TYPE_DOMAIN (type))
+	  && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
+			== INTEGER_CST)
+	{
+	  tree size = size_binop (PLUS_EXPR,
+				  TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
+				  size_one_node);
+	  if (TREE_CODE (low_bound) == INTEGER_CST)
+	    {
+	      if (tree_int_cst_lt (size, low_bound))
+		{
+		  error_at (OMP_CLAUSE_LOCATION (c),
+			    "low bound %qE above array section size "
+			    "in %qs clause", low_bound,
+			    omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+		  return error_mark_node;
+		}
+	      if (tree_int_cst_equal (size, low_bound))
+		maybe_zero_len = true;
+	      else if (length == NULL_TREE
+		       && first_non_one == types.length ()
+		       && tree_int_cst_equal
+			    (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
+			     low_bound))
+		first_non_one++;
+	    }
+	  else if (length == NULL_TREE)
+	    {
+	      maybe_zero_len = true;
+	      if (first_non_one == types.length ())
+		first_non_one++;
+	    }
+	  if (length && TREE_CODE (length) == INTEGER_CST)
+	    {
+	      if (tree_int_cst_lt (size, length))
+		{
+		  error_at (OMP_CLAUSE_LOCATION (c),
+			    "length %qE above array section size "
+			    "in %qs clause", length,
+			    omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+		  return error_mark_node;
+		}
+	      if (TREE_CODE (low_bound) == INTEGER_CST)
+		{
+		  tree lbpluslen
+		    = size_binop (PLUS_EXPR,
+				  fold_convert (sizetype, low_bound),
+				  fold_convert (sizetype, length));
+		  if (TREE_CODE (lbpluslen) == INTEGER_CST
+		      && tree_int_cst_lt (size, lbpluslen))
+		    {
+		      error_at (OMP_CLAUSE_LOCATION (c),
+				"high bound %qE above array section size "
+				"in %qs clause", lbpluslen,
+				omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+		      return error_mark_node;
+		    }
+		}
+	    }
+	}
+      else if (length == NULL_TREE)
+	{
+	  maybe_zero_len = true;
+	  if (first_non_one == types.length ())
+	    first_non_one++;
+	}
+
+      /* For [lb:] we will need to evaluate lb more than once.  */
+      if (length == NULL_TREE && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
+	{
+	  tree lb = c_save_expr (low_bound);
+	  if (lb != low_bound)
+	    {
+	      TREE_PURPOSE (t) = lb;
+	      low_bound = lb;
+	    }
+	}
+    }
+  else if (TREE_CODE (type) == POINTER_TYPE)
+    {
+      if (length == NULL_TREE)
+	{
+	  error_at (OMP_CLAUSE_LOCATION (c),
+		    "for pointer type length expression is not optional");
+	  return error_mark_node;
+	}
+      /* If there is a pointer type anywhere but in the very first
+	 array-section-subscript, the array section can't be contiguous.  */
+      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND
+	  && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST)
+	{
+	  error_at (OMP_CLAUSE_LOCATION (c),
+		    "array section is not contiguous in %qs clause",
+		    omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+	  return error_mark_node;
+	}
+    }
+  else
+    {
+      error_at (OMP_CLAUSE_LOCATION (c),
+		"%qE does not have pointer or array type", ret);
+      return error_mark_node;
+    }
+  if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
+    types.safe_push (TREE_TYPE (ret));
+  /* For pointer based array sections we will need to evaluate lb more
+     than once.  */
+  if (pointer_based_p)
+    {
+      tree lb = c_save_expr (low_bound);
+      if (lb != low_bound)
+	{
+	  TREE_PURPOSE (t) = lb;
+	  low_bound = lb;
+	}
+    }
+  ret = build_array_ref (OMP_CLAUSE_LOCATION (c), ret, low_bound);
+  return ret;
+}
+
+/* Handle array sections for clause C.  */
+
+static bool
+handle_omp_array_sections (tree c)
+{
+  bool maybe_zero_len = false;
+  bool pointer_based_p = false;
+  unsigned int first_non_one = 0;
+  vec<tree> types = vNULL;
+  tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types,
+					    maybe_zero_len, first_non_one,
+					    pointer_based_p);
+  if (first == error_mark_node)
+    {
+      types.release ();
+      return true;
+    }
+  if (first == NULL_TREE)
+    {
+      types.release ();
+      return false;
+    }
+  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND)
+    {
+      tree t = OMP_CLAUSE_DECL (c);
+      tree tem = NULL_TREE;
+      types.release ();
+      /* Need to evaluate side effects in the length expressions
+	 if any.  */
+      while (TREE_CODE (t) == TREE_LIST)
+	{
+	  if (TREE_VALUE (t) && TREE_SIDE_EFFECTS (TREE_VALUE (t)))
+	    {
+	      if (tem == NULL_TREE)
+		tem = TREE_VALUE (t);
+	      else
+		tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem),
+			      TREE_VALUE (t), tem);
+	    }
+	  t = TREE_CHAIN (t);
+	}
+      if (tem)
+	first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first);
+      OMP_CLAUSE_DECL (c) = first;
+    }
+  else
+    {
+      unsigned int num = types.length (), i;
+      tree t, side_effects = NULL_TREE, size = NULL_TREE;
+      tree condition = NULL_TREE;
+
+      if (int_size_in_bytes (TREE_TYPE (first)) <= 0)
+	maybe_zero_len = true;
+
+      for (i = num, t = OMP_CLAUSE_DECL (c); i > 0;
+	   t = TREE_CHAIN (t))
+	{
+	  tree low_bound = TREE_PURPOSE (t);
+	  tree length = TREE_VALUE (t);
+
+	  i--;
+	  if (low_bound
+	      && TREE_CODE (low_bound) == INTEGER_CST
+	      && TYPE_PRECISION (TREE_TYPE (low_bound))
+		 > TYPE_PRECISION (sizetype))
+	    low_bound = fold_convert (sizetype, low_bound);
+	  if (length
+	      && TREE_CODE (length) == INTEGER_CST
+	      && TYPE_PRECISION (TREE_TYPE (length))
+		 > TYPE_PRECISION (sizetype))
+	    length = fold_convert (sizetype, length);
+	  if (low_bound == NULL_TREE)
+	    low_bound = integer_zero_node;
+	  if (!maybe_zero_len && i > first_non_one)
+	    {
+	      if (integer_nonzerop (low_bound))
+		goto do_warn_noncontiguous;
+	      if (length != NULL_TREE
+		  && TREE_CODE (length) == INTEGER_CST
+		  && TYPE_DOMAIN (types[i])
+		  && TYPE_MAX_VALUE (TYPE_DOMAIN (types[i]))
+		  && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])))
+		     == INTEGER_CST)
+		{
+		  tree size;
+		  size = size_binop (PLUS_EXPR,
+				     TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])),
+				     size_one_node);
+		  if (!tree_int_cst_equal (length, size))
+		    {
+		     do_warn_noncontiguous:
+		      error_at (OMP_CLAUSE_LOCATION (c),
+				"array section is not contiguous in %qs "
+				"clause",
+				omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+		      types.release ();
+		      return true;
+		    }
+		}
+	      if (length != NULL_TREE
+		  && TREE_SIDE_EFFECTS (length))
+		{
+		  if (side_effects == NULL_TREE)
+		    side_effects = length;
+		  else
+		    side_effects = build2 (COMPOUND_EXPR,
+					   TREE_TYPE (side_effects),
+					   length, side_effects);
+		}
+	    }
+	  else
+	    {
+	      tree l;
+
+	      if (i > first_non_one && length && integer_nonzerop (length))
+		continue;
+	      if (length)
+		l = fold_convert (sizetype, length);
+	      else
+		{
+		  l = size_binop (PLUS_EXPR,
+				  TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])),
+				  size_one_node);
+		  l = size_binop (MINUS_EXPR, l,
+				  fold_convert (sizetype, low_bound));
+		}
+	      if (i > first_non_one)
+		{
+		  l = fold_build2 (NE_EXPR, boolean_type_node, l,
+				   size_zero_node);
+		  if (condition == NULL_TREE)
+		    condition = l;
+		  else
+		    condition = fold_build2 (BIT_AND_EXPR, boolean_type_node,
+					     l, condition);
+		}
+	      else if (size == NULL_TREE)
+		{
+		  size = size_in_bytes (TREE_TYPE (types[i]));
+		  size = size_binop (MULT_EXPR, size, l);
+		  if (condition)
+		    size = fold_build3 (COND_EXPR, sizetype, condition,
+					size, size_zero_node);
+		}
+	      else
+		size = size_binop (MULT_EXPR, size, l);
+	    }
+	}
+      types.release ();
+      if (side_effects)
+	size = build2 (COMPOUND_EXPR, sizetype, side_effects, size);
+      OMP_CLAUSE_DECL (c) = first;
+      OMP_CLAUSE_SIZE (c) = size;
+      if (pointer_based_p)
+	{
+	  tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
+	  OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER;
+	  if (!c_mark_addressable (t))
+	    return false;
+	  OMP_CLAUSE_DECL (c2) = t;
+	  t = build_fold_addr_expr (first);
+	  t = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+				build_pointer_type (char_type_node), t);
+	  t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
+			       ptrdiff_type_node, t,
+			       fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+						 TREE_TYPE (t),
+						 OMP_CLAUSE_DECL (c2)));
+	  OMP_CLAUSE_SIZE (c2) = t;
+	  OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
+	  OMP_CLAUSE_CHAIN (c) = c2;
+	}
+    }
+  return false;
+}
+
 /* For all elements of CLAUSES, validate them vs OpenMP constraints.
    Remove any elements from the list that are invalid.  */
 
@@ -10954,21 +11383,49 @@ c_finish_omp_clauses (tree clauses)
 
 	case OMP_CLAUSE_DEPEND:
 	  t = OMP_CLAUSE_DECL (c);
-	  /* FIXME: depend clause argument may be also array section.  */
-	  if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+	  if (TREE_CODE (t) == TREE_LIST)
+	    {
+	      if (handle_omp_array_sections (c))
+		remove = true;
+	      break;
+	    }
+	  if (t == error_mark_node)
+	    remove = true;
+	  else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
 			"%qE is not a variable in %<depend%> clause", t);
 	      remove = true;
 	    }
+	  else if (!c_mark_addressable (t))
+	    remove = true;
 	  break;
 
 	case OMP_CLAUSE_MAP:
 	case OMP_CLAUSE_TO:
 	case OMP_CLAUSE_FROM:
 	  t = OMP_CLAUSE_DECL (c);
-	  /* FIXME: map clause argument may be also array section.  */
-	  if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+	  if (TREE_CODE (t) == TREE_LIST)
+	    {
+	      if (handle_omp_array_sections (c))
+		remove = true;
+	      else
+		{
+		  t = OMP_CLAUSE_DECL (c);
+		  if (!COMPLETE_TYPE_P (TREE_TYPE (t)))
+		    {
+		      error_at (OMP_CLAUSE_LOCATION (c),
+				"array section does not have mappable type "
+				"in %qs clause",
+				omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+		      remove = true;
+		    }
+		}
+	      break;
+	    }
+	  if (t == error_mark_node)
+	    remove = true;
+	  else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
 			"%qE is not a variable in %qs clause", t,
@@ -10982,6 +11439,24 @@ c_finish_omp_clauses (tree clauses)
 			omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
 	      remove = true;
 	    }
+	  else if (!c_mark_addressable (t))
+	    remove = true;
+	  else if (!COMPLETE_TYPE_P (TREE_TYPE (t)))
+	    {
+	      error_at (OMP_CLAUSE_LOCATION (c),
+			"%qD does not have a mappable type in %qs clause", t,
+			omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+	      remove = true;
+	    }
+	  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
+	    break;
+	  else if (bitmap_bit_p (&generic_head, DECL_UID (t)))
+	    {
+	      error ("%qD appears more than once in motion clauses", t);
+	      remove = true;
+	    }
+	  else
+	    bitmap_set_bit (&generic_head, DECL_UID (t));
 	  break;
 
 	case OMP_CLAUSE_UNIFORM:
@@ -11013,6 +11488,7 @@ c_finish_omp_clauses (tree clauses)
 
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
+	case OMP_CLAUSE_THREAD_LIMIT:
 	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_DEFAULT:
--- gcc/cp/parser.c.jj	2013-07-03 22:15:07.000000000 +0200
+++ gcc/cp/parser.c	2013-07-06 19:33:15.297030502 +0200
@@ -29745,6 +29745,36 @@ cp_parser_omp_declare_target (cp_parser
 static void
 cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok)
 {
+  const char *p = "";
+  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+    {
+      tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+      p = IDENTIFIER_POINTER (id);
+    }
+  if (strcmp (p, "declare") == 0)
+    {
+      cp_lexer_consume_token (parser->lexer);
+      p = "";
+      if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+	{
+	  tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+	  p = IDENTIFIER_POINTER (id);
+	}
+      if (strcmp (p, "target") == 0)
+	cp_lexer_consume_token (parser->lexer);
+      else
+	{
+	  cp_parser_error (parser, "expected %<target%>");
+	  cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+	  return;
+	}
+    }
+  else
+    {
+      cp_parser_error (parser, "expected %<declare%>");
+      cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+      return;
+    }
   cp_parser_skip_to_pragma_eol (parser, pragma_tok);
   if (!current_omp_declare_target_attribute)
     error_at (pragma_tok->location,
@@ -29757,7 +29787,8 @@ cp_parser_omp_end_declare_target (cp_par
 /* OpenMP 4.0
    #pragma omp declare simd declare-simd-clauses[optseq] new-line
    #pragma omp declare reduction (reduction-id : typename-list : expression) \
-      identity-clause[opt] new-line */
+      identity-clause[opt] new-line
+   #pragma omp declare target new-line  */
 
 static void
 cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok,
@@ -29790,7 +29821,8 @@ cp_parser_omp_declare (cp_parser *parser
 	  return;
 	}
     }
-  cp_parser_error (parser, "expected %<simd%> or %<reduction%>");
+  cp_parser_error (parser, "expected %<simd%> or %<reduction%> "
+			   "or %<target%>");
   cp_parser_require_pragma_eol (parser, pragma_tok);
 }
 
--- gcc/testsuite/c-c++-common/gomp/depend-2.c.jj	2013-06-04 20:55:56.000000000 +0200
+++ gcc/testsuite/c-c++-common/gomp/depend-2.c	2013-07-06 19:18:19.474914134 +0200
@@ -1,4 +1,4 @@
-/* { dg-do compile { target c++ } } */
+/* { dg-do compile } */
 /* { dg-options "-fopenmp" } */
 
 void bar (int a[10][10][10]);
--- gcc/testsuite/c-c++-common/gomp/map-1.c.jj	2013-06-04 20:55:56.000000000 +0200
+++ gcc/testsuite/c-c++-common/gomp/map-1.c	2013-07-06 19:18:46.161478820 +0200
@@ -1,4 +1,4 @@
-/* { dg-do compile { target c++ } } */
+/* { dg-do compile } */
 /* { dg-options "-fopenmp" } */
 
 extern int a[][10], a2[][10];
--- gcc/testsuite/c-c++-common/gomp/depend-1.c.jj	2013-06-04 20:55:56.000000000 +0200
+++ gcc/testsuite/c-c++-common/gomp/depend-1.c	2013-07-06 19:18:08.434094464 +0200
@@ -1,4 +1,4 @@
-/* { dg-do compile { target c++ } } */
+/* { dg-do compile } */
 /* { dg-options "-fopenmp" } */
 
 extern int a[][10], a2[][10];
--- gcc/c-family/c-pragma.h.jj	2013-06-14 18:46:39.000000000 +0200
+++ gcc/c-family/c-pragma.h	2013-07-06 18:32:58.451917415 +0200
@@ -33,42 +33,24 @@ typedef enum pragma_kind {
   PRAGMA_OMP_CANCELLATION_POINT,
   PRAGMA_OMP_CRITICAL,
   PRAGMA_OMP_DECLARE_REDUCTION,
-  PRAGMA_OMP_DECLARE_SIMD,
-  PRAGMA_OMP_DECLARE_TARGET,
   PRAGMA_OMP_DISTRIBUTE,
-  PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR,
-  PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD,
-  PRAGMA_OMP_DISTRIBUTE_SIMD,
   PRAGMA_OMP_END_DECLARE_TARGET,
   PRAGMA_OMP_FLUSH,
   PRAGMA_OMP_FOR,
-  PRAGMA_OMP_FOR_SIMD,
   PRAGMA_OMP_MASTER,
   PRAGMA_OMP_ORDERED,
   PRAGMA_OMP_PARALLEL,
-  PRAGMA_OMP_PARALLEL_FOR,
-  PRAGMA_OMP_PARALLEL_FOR_SIMD,
-  PRAGMA_OMP_PARALLEL_SECTIONS,
   PRAGMA_OMP_SECTION,
   PRAGMA_OMP_SECTIONS,
   PRAGMA_OMP_SIMD,
   PRAGMA_OMP_SINGLE,
   PRAGMA_OMP_TARGET,
-  PRAGMA_OMP_TARGET_DATA,
-  PRAGMA_OMP_TARGET_TEAMS,
-  PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE,
-  PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR,
-  PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD,
-  PRAGMA_OMP_TARGET_UPDATE,
   PRAGMA_OMP_TASK,
   PRAGMA_OMP_TASKGROUP,
   PRAGMA_OMP_TASKWAIT,
   PRAGMA_OMP_TASKYIELD,
   PRAGMA_OMP_THREADPRIVATE,
   PRAGMA_OMP_TEAMS,
-  PRAGMA_OMP_TEAMS_DISTRIBUTE,
-  PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR,
-  PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD,
 
   PRAGMA_GCC_PCH_PREPROCESS,
 
--- libgomp/testsuite/libgomp.c/for-3.c.jj	2013-07-06 19:43:08.307165397 +0200
+++ libgomp/testsuite/libgomp.c/for-3.c	2013-07-06 19:44:29.618818923 +0200
@@ -0,0 +1,113 @@
+/* { dg-options "-std=gnu99 -fopenmp" } */
+
+extern void abort ();
+
+#define M(x, y, z) O(x, y, z)
+#define O(x, y, z) x ## _ ## y ## _ ## z
+
+#pragma omp declare target
+
+#define F distribute
+#define G d
+#define S
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F distribute
+#define G d_ds128
+#define S dist_schedule(static, 128)
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F distribute simd
+#define G ds
+#define S
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F distribute simd
+#define G ds_ds128
+#define S dist_schedule(static, 128)
+#define N(x) M(x, G, normal)
+#include "for-2.h"
+#undef S
+#undef N
+#undef F
+#undef G
+
+#define F distribute parallel for
+#define G dpf
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F distribute parallel for dist_schedule(static, 128)
+#define G dpf_ds128
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F distribute parallel for simd
+#define G dpfs
+#include "for-1.h"
+#undef F
+#undef G
+
+#define F distribute parallel for simd dist_schedule(static, 128)
+#define G dpfs_ds128
+#include "for-1.h"
+#undef F
+#undef G
+
+#pragma omp end declare target
+
+int
+main ()
+{
+  int err = 0;
+/* FIXME: distribute construct must be closely nested
+   in teams region, but we don't handle target expansions
+   yet.  Enable when it works.  */
+/* #pragma omp target teams reduction(|:err) */
+    {
+      err |= test_d_normal ();
+      err |= test_d_ds128_normal ();
+      err |= test_ds_normal ();
+      err |= test_ds_ds128_normal ();
+      err |= test_dpf_static ();
+      err |= test_dpf_static32 ();
+      err |= test_dpf_auto ();
+      err |= test_dpf_guided32 ();
+      err |= test_dpf_runtime ();
+      err |= test_dpf_ds128_static ();
+      err |= test_dpf_ds128_static32 ();
+      err |= test_dpf_ds128_auto ();
+      err |= test_dpf_ds128_guided32 ();
+      err |= test_dpf_ds128_runtime ();
+      err |= test_dpfs_static ();
+      err |= test_dpfs_static32 ();
+      err |= test_dpfs_auto ();
+      err |= test_dpfs_guided32 ();
+      err |= test_dpfs_runtime ();
+      err |= test_dpfs_ds128_static ();
+      err |= test_dpfs_ds128_static32 ();
+      err |= test_dpfs_ds128_auto ();
+      err |= test_dpfs_ds128_guided32 ();
+      err |= test_dpfs_ds128_runtime ();
+    }
+  if (err)
+    abort ();
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/simd-1.c.jj	2013-07-06 19:41:20.872945458 +0200
+++ libgomp/testsuite/libgomp.c/simd-1.c	2013-07-06 20:22:41.110996196 +0200
@@ -0,0 +1,57 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-msse2" { target sse2_runtime } } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+
+extern void abort ();
+int a[1024] __attribute__((aligned (32))) = { 1 };
+int b[1024] __attribute__((aligned (32))) = { 1 };
+int k, m;
+struct U { int u; };
+struct V { int v; };
+
+__attribute__((noinline, noclone)) int
+foo (int *p)
+{
+  int i, s = 0;
+  struct U u;
+  struct V v;
+  #pragma omp simd aligned(a, p : 32) linear(k: m + 1) \
+		   reduction(+:s) lastprivate(u, v)
+  for (i = 0; i < 1024; i++)
+    {
+      a[i] *= p[i];
+      u.u = p[i] + k;
+      k += m + 1;
+      v.v = p[i] + k;
+      s += p[i] + k;
+    }
+  if (u.u != 36 + 4 + 3 * 1023 || v.v != 36 + 4 + 3 * 1024)
+    abort ();
+  return s;
+}
+
+int
+main ()
+{
+#if __SIZEOF_INT__ >= 4
+  int i;
+  k = 4;
+  m = 2;
+  for (i = 0; i < 1024; i++)
+    {
+      a[i] = i - 512;
+      b[i] = (i - 51) % 39;
+    }
+  int s = foo (b);
+  for (i = 0; i < 1024; i++)
+    {
+      if (b[i] != (i - 51) % 39
+	  || a[i] != (i - 512) * b[i])
+	abort ();
+    }
+  if (k != 4 + 3 * 1024 || s != 1596127)
+    abort ();
+#endif
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/simd-2.c.jj	2013-07-06 19:41:23.902895215 +0200
+++ libgomp/testsuite/libgomp.c/simd-2.c	2013-07-06 19:47:08.878746011 +0200
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-msse2" { target sse2_runtime } } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+
+extern void abort ();
+__UINTPTR_TYPE__ arr[1027];
+
+__attribute__((noinline, noclone)) void
+foo ()
+{
+  int i, v;
+  #pragma omp simd private (v) safelen(16)
+  for (i = 0; i < 1027; i++)
+    arr[i] = (__UINTPTR_TYPE__) &v;
+}
+
+int
+main ()
+{
+  int i, j, cnt = 0;
+  __UINTPTR_TYPE__ arr2[16];
+  foo ();
+  for (i = 0; i < 1027; i++)
+    {
+      for (j = 0; j < cnt; j++)
+	if (arr[i] == arr2[j])
+	  break;
+      if (j != cnt)
+	continue;
+      if (cnt == 16)
+	abort ();
+      arr2[cnt++] = arr[i];
+    }
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/simd-3.c.jj	2013-07-06 19:41:26.916845206 +0200
+++ libgomp/testsuite/libgomp.c/simd-3.c	2013-07-06 19:48:02.498396227 +0200
@@ -0,0 +1,131 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-msse2" { target sse2_runtime } } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+
+extern void abort ();
+int a[1024] __attribute__((aligned (32))) = { 1 };
+int b[1024] __attribute__((aligned (32))) = { 1 };
+unsigned char c[1024] __attribute__((aligned (32))) = { 1 };
+int k, m;
+__UINTPTR_TYPE__ u, u2, u3;
+
+__attribute__((noinline, noclone)) int
+foo (int *p)
+{
+  int i, s = 0, s2 = 0, t, t2;
+  #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s) \
+		   lastprivate (t2)
+  for (i = 0; i < 512; i++)
+    {
+      a[i] *= p[i];
+      t2 = k + p[i];
+      k += m + 1;
+      s += p[i] + k;
+      c[i]++;
+    }
+  #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s2) \
+		   lastprivate (t, u, u2, u3)
+  for (i = 512; i < 1024; i++)
+    {
+      a[i] *= p[i];
+      k += m + 1;
+      t = k + p[i];
+      u = (__UINTPTR_TYPE__) &k;
+      u2 = (__UINTPTR_TYPE__) &s2;
+      u3 = (__UINTPTR_TYPE__) &t;
+      s2 += t;
+      c[i]++;
+    }
+  return s + s2 + t + t2;
+}
+
+__attribute__((noinline, noclone)) long int
+bar (int *p, long int n, long int o)
+{
+  long int i, s = 0, s2 = 0, t, t2;
+  #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s) \
+		   lastprivate (t2)
+  for (i = 0; i < n; i++)
+    {
+      a[i] *= p[i];
+      t2 = k + p[i];
+      k += m + 1;
+      s += p[i] + k;
+      c[i]++;
+    }
+  #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s2) \
+		   lastprivate (t, u, u2, u3)
+  for (i = n; i < o; i++)
+    {
+      a[i] *= p[i];
+      k += m + 1;
+      t = k + p[i];
+      u = (__UINTPTR_TYPE__) &k;
+      u2 = (__UINTPTR_TYPE__) &s2;
+      u3 = (__UINTPTR_TYPE__) &t;
+      s2 += t;
+      c[i]++;
+    }
+  return s + s2 + t + t2;
+}
+
+int
+main ()
+{
+#if __SIZEOF_INT__ >= 4
+  int i;
+  k = 4;
+  m = 2;
+  for (i = 0; i < 1024; i++)
+    {
+      a[i] = i - 512;
+      b[i] = (i - 51) % 39;
+      c[i] = (unsigned char) i;
+    }
+  int s = foo (b);
+  for (i = 0; i < 1024; i++)
+    {
+      if (b[i] != (i - 51) % 39
+	  || a[i] != (i - 512) * b[i]
+	  || c[i] != (unsigned char) (i + 1))
+	abort ();
+      a[i] = i - 512;
+    }
+  if (k != 4 + 3 * 1024
+      || s != 1596127 + (4 + 3 * 511 + b[511]) + (4 + 3 * 1024 + b[1023]))
+    abort ();
+  k = 4;
+  s = bar (b, 512, 1024);
+  for (i = 0; i < 1024; i++)
+    {
+      if (b[i] != (i - 51) % 39
+	  || a[i] != (i - 512) * b[i]
+	  || c[i] != (unsigned char) (i + 2))
+	abort ();
+      a[i] = i - 512;
+    }
+  if (k != 4 + 3 * 1024
+      || s != 1596127 + (4 + 3 * 511 + b[511]) + (4 + 3 * 1024 + b[1023]))
+    abort ();
+  k = 4;
+  s = bar (b, 511, 1021);
+  for (i = 0; i < 1021; i++)
+    {
+      if (b[i] != (i - 51) % 39
+	  || a[i] != (i - 512) * b[i]
+	  || c[i] != (unsigned char) (i + 3))
+	abort ();
+      a[i] = i - 512;
+    }
+  for (i = 1021; i < 1024; i++)
+    if (b[i] != (i - 51) % 39
+	|| a[i] != i - 512
+	|| c[i] != (unsigned char) (i + 2))
+      abort ();
+  if (k != 4 + 3 * 1021
+      || s != 1586803 + (4 + 3 * 510 + b[510]) + (4 + 3 * 1021 + b[1020]))
+    abort ();
+#endif
+  return 0;
+}
