diff mbox

[1/6] OpenMP 4.0 C FE support

Message ID 20131008195240.GA30970@tucnak.zalov.cz
State New
Headers show

Commit Message

Jakub Jelinek Oct. 8, 2013, 7:52 p.m. UTC
Hi!

2013-10-08  Jakub Jelinek  <jakub@redhat.com>

gcc/c/
	* c-lang.h (current_omp_declare_target_attribute): New extern
	decl.
	* c-parser.c: Include c-lang.h.
	(struct c_parser): Change tokens to c_token *.
	Add tokens_buf field.  Change tokens_avail type to unsigned int.
	(c_parser_consume_token): If parser->tokens isn't
	&parser->tokens_buf[0], increment parser->tokens.
	(c_parser_consume_pragma): Likewise.
	(enum pragma_context): Add pragma_struct and pragma_param.
	(c_parser_external_declaration): Adjust
	c_parser_declaration_or_fndef caller.
	(c_parser_declaration_or_fndef): Add omp_declare_simd_clauses
	argument, if it is non-vNULL vector, call c_finish_omp_declare_simd.
	Adjust recursive call.
	(c_parser_struct_or_union_specifier): Use pragma_struct instead
	of pragma_external.
	(c_parser_parameter_declaration): Use pragma_param instead of
	pragma_external.
	(c_parser_compound_statement_nostart, c_parser_label,
	c_parser_for_statement): Adjust
	c_parser_declaration_or_fndef callers.
	(c_parser_expr_no_commas): Add omp_atomic_lhs argument, pass
	it through to c_parser_conditional_expression.
	(c_parser_conditional_expression): Add omp_atomic_lhs argument,
	pass it through to c_parser_binary_expression.  Adjust recursive
	call.
	(c_parser_binary_expression): Remove prec argument, add
	omp_atomic_lhs argument instead.  Always start from PREC_NONE, if
	omp_atomic_lhs is non-NULL and one of the arguments of toplevel
	binop matches it, use build2 instead of parser_build_binary_op.
	(c_parser_pragma): Handle PRAGMA_OMP_CANCEL,
	PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_TARGET,
	PRAGMA_OMP_END_DECLARE_TARGET, PRAGMA_OMP_DECLARE_REDUCTION.
	Handle pragma_struct and pragma_param the same as pragma_external.
	(c_parser_omp_clause_name): Parse new OpenMP 4.0 clause names.
	(c_parser_omp_variable_list): Parse array sections for
	OMP_CLAUSE_{DEPEND,MAP,TO,FROM} clauses.
	(c_parser_omp_clause_collapse): Fully fold collapse expression.
	(c_parser_omp_clause_reduction): Handle user defined reductions.
	(c_parser_omp_clause_branch, c_parser_omp_clause_cancelkind,
	c_parser_omp_clause_num_teams, c_parser_omp_clause_thread_limit,
	c_parser_omp_clause_aligned, c_parser_omp_clause_linear,
	c_parser_omp_clause_safelen, c_parser_omp_clause_simdlen,
	c_parser_omp_clause_depend, c_parser_omp_clause_map,
	c_parser_omp_clause_device, c_parser_omp_clause_dist_schedule,
	c_parser_omp_clause_proc_bind, c_parser_omp_clause_to,
	c_parser_omp_clause_from, c_parser_omp_clause_uniform): New functions.
	(c_parser_omp_all_clauses): Add finish_p argument.  Don't call
	c_finish_omp_clauses if it is false.  Handle new OpenMP 4.0 clauses.
	(c_parser_omp_atomic): Parse seq_cst clause, pass true if it is
	present to c_finish_omp_atomic.  Handle OpenMP 4.0 atomic forms.
	(c_parser_omp_for_loop): Add CODE argument, pass it through
	to c_finish_omp_for.  Change last argument to cclauses,
	and adjust uses to grab parallel clauses from the array of all
	the split clauses.  Adjust c_parser_binary_expression,
	c_parser_declaration_or_fndef and c_finish_omp_for callers.
	(omp_split_clauses): New function.
	(c_parser_omp_simd): New function.
	(c_parser_omp_for): Add p_name, mask and cclauses arguments.
	Allow the function to be called also when parsing combined constructs,
	and call c_parser_omp_simd when parsing for simd.
	(c_parser_omp_sections_scope): If section-sequence doesn't start with
	#pragma omp section, require exactly one structured-block instead of
	sequence of statements.
	(c_parser_omp_sections): Add p_name, mask and cclauses arguments.
	Allow the function to be called also when parsing combined constructs.
	(c_parser_omp_parallel): Add p_name, mask and cclauses arguments.
	Allow the function to be called also when parsing combined
	constructs.
	(c_parser_omp_taskgroup, c_parser_omp_cancel,
	c_parser_omp_cancellation_point, c_parser_omp_distribute,
	c_parser_omp_teams, c_parser_omp_target_data,
	c_parser_omp_target_update, c_parser_omp_target,
	c_parser_omp_declare_simd, c_finish_omp_declare_simd,
	c_parser_omp_declare_target, c_parser_omp_end_declare_target,
	c_parser_omp_declare_reduction, c_parser_omp_declare): New functions.
	(c_parser_omp_construct): Add p_name and mask vars.  Handle
	PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_SIMD, PRAGMA_OMP_TASKGROUP,
	PRAGMA_OMP_TEAMS.  Adjust c_parser_omp_for, c_parser_omp_parallel
	and c_parser_omp_sections callers.
	(c_parse_file): Initialize tparser.tokens and the_parser->tokens here.
	(OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK,
	OMP_SINGLE_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1.
	(OMP_PARALLEL_CLAUSE_MASK): Likewise.  Add OMP_CLAUSE_PROC_BIND.
	(OMP_TASK_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1.  Add
	OMP_CLAUSE_DEPEND.
	(OMP_SIMD_CLAUSE_MASK, OMP_CANCEL_CLAUSE_MASK,
	OMP_CANCELLATION_POINT_CLAUSE_MASK, OMP_DISTRIBUTE_CLAUSE_MASK,
	OMP_TEAMS_CLAUSE_MASK, OMP_TARGET_DATA_CLAUSE_MASK,
	OMP_TARGET_UPDATE_CLAUSE_MASK, OMP_TARGET_CLAUSE_MASK,
	OMP_DECLARE_SIMD_CLAUSE_MASK): Define.
	* c-typeck.c: Include tree-inline.h.
	(c_finish_omp_cancel, c_finish_omp_cancellation_point,
	handle_omp_array_sections_1, handle_omp_array_sections,
	c_clone_omp_udr, c_find_omp_placeholder_r): New functions.
	(c_finish_omp_clauses): Handle new OpenMP 4.0 clauses and
	user defined reductions.
	(c_tree_equal): New function.
	* c-tree.h (temp_store_parm_decls, temp_pop_parm_decls,
	c_finish_omp_cancel, c_finish_omp_cancellation_point, c_tree_equal,
	c_omp_reduction_id, c_omp_reduction_decl, c_omp_reduction_lookup,
	c_check_omp_declare_reduction_r): New prototypes.
	* c-decl.c (current_omp_declare_target_attribute): New variable.
	(c_decl_attributes): New function.
	(start_decl, start_function): Use it instead of decl_attributes.
	(temp_store_parm_decls, temp_pop_parm_decls, c_omp_reduction_id,
	c_omp_reduction_decl, c_omp_reduction_lookup,
	c_check_omp_declare_reduction_r): New functions.


	Jakub

Comments

Jakub Jelinek Oct. 8, 2013, 7:55 p.m. UTC | #1
Hi!

Sorry for the subject, that was meant to be [2/6], not [1/6].

	Jakub
Joseph Myers Oct. 10, 2013, 5:14 p.m. UTC | #2
My only comment is that you change the parameters to 
c_parser_binary_expression, but don't change the comment above that 
function documenting what they are.
diff mbox

Patch

--- gcc/c/c-decl.c	(.../trunk)	(revision 203241)
+++ gcc/c/c-decl.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -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
@@ -3971,6 +3974,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.
@@ -4105,7 +4137,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
@@ -7727,7 +7759,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)
@@ -8324,6 +8356,44 @@  store_parm_decls (void)
   if (arg_info->pending_sizes)
     add_stmt (arg_info->pending_sizes);
 }
+
+/* Store PARM_DECLs in PARMS into scope temporarily.  Used for
+   c_finish_omp_declare_simd for function prototypes.  No diagnostics
+   should be done.  */
+
+void
+temp_store_parm_decls (tree fndecl, tree parms)
+{
+  push_scope ();
+  for (tree p = parms; p; p = DECL_CHAIN (p))
+    {
+      DECL_CONTEXT (p) = fndecl;
+      if (DECL_NAME (p))
+	bind (DECL_NAME (p), p, current_scope,
+	      /*invisible=*/false, /*nested=*/false,
+	      UNKNOWN_LOCATION);
+    }
+}
+
+/* Undo what temp_store_parm_decls did.  */
+
+void
+temp_pop_parm_decls (void)
+{
+  /* Clear all bindings in this temporary scope, so that
+     pop_scope doesn't create a BLOCK.  */
+  struct c_binding *b = current_scope->bindings;
+  current_scope->bindings = NULL;
+  for (; b; b = free_binding_and_advance (b))
+    {
+      gcc_assert (TREE_CODE (b->decl) == PARM_DECL);
+      gcc_assert (I_SYMBOL_BINDING (b->id) == b);
+      I_SYMBOL_BINDING (b->id) = b->shadowed;
+      if (b->shadowed && b->shadowed->u.type)
+	TREE_TYPE (b->shadowed->decl) = b->shadowed->u.type;
+    }
+  pop_scope ();
+}
 
 
 /* Finish up a function declaration and compile that function
@@ -10158,4 +10228,106 @@  c_register_addr_space (const char *word,
   ridpointers [rid] = id;
 }
 
+/* Return identifier to look up for omp declare reduction.  */
+
+tree
+c_omp_reduction_id (enum tree_code reduction_code, tree reduction_id)
+{
+  const char *p = NULL;
+  switch (reduction_code)
+    {
+    case PLUS_EXPR: p = "+"; break;
+    case MULT_EXPR: p = "*"; break;
+    case MINUS_EXPR: p = "-"; break;
+    case BIT_AND_EXPR: p = "&"; break;
+    case BIT_XOR_EXPR: p = "^"; break;
+    case BIT_IOR_EXPR: p = "|"; break;
+    case TRUTH_ANDIF_EXPR: p = "&&"; break;
+    case TRUTH_ORIF_EXPR: p = "||"; break;
+    case MIN_EXPR: p = "min"; break;
+    case MAX_EXPR: p = "max"; break;
+    default:
+      break;
+    }
+
+  if (p == NULL)
+    {
+      if (TREE_CODE (reduction_id) != IDENTIFIER_NODE)
+	return error_mark_node;
+      p = IDENTIFIER_POINTER (reduction_id);
+    }
+
+  const char prefix[] = "omp declare reduction ";
+  size_t lenp = sizeof (prefix);
+  size_t len = strlen (p);
+  char *name = XALLOCAVEC (char, lenp + len);
+  memcpy (name, prefix, lenp - 1);
+  memcpy (name + lenp - 1, p, len + 1);
+  return get_identifier (name);
+}
+
+/* Lookup REDUCTION_ID in the current scope, or create an artificial
+   VAR_DECL, bind it into the current scope and return it.  */
+
+tree
+c_omp_reduction_decl (tree reduction_id)
+{
+  struct c_binding *b = I_SYMBOL_BINDING (reduction_id);
+  if (b != NULL && B_IN_CURRENT_SCOPE (b))
+    return b->decl;
+
+  tree decl = build_decl (BUILTINS_LOCATION, VAR_DECL,
+			  reduction_id, integer_type_node);
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_EXTERNAL (decl) = 1;
+  TREE_STATIC (decl) = 1;
+  TREE_PUBLIC (decl) = 0;
+  bind (reduction_id, decl, current_scope, true, false, BUILTINS_LOCATION);
+  return decl;
+}
+
+/* Lookup REDUCTION_ID in the first scope where it has entry for TYPE.  */
+
+tree
+c_omp_reduction_lookup (tree reduction_id, tree type)
+{
+  struct c_binding *b = I_SYMBOL_BINDING (reduction_id);
+  while (b)
+    {
+      tree t;
+      for (t = DECL_INITIAL (b->decl); t; t = TREE_CHAIN (t))
+	if (comptypes (TREE_PURPOSE (t), type))
+	  return TREE_VALUE (t);
+      b = b->shadowed;
+    }
+  return error_mark_node;
+}
+
+/* Helper function called via walk_tree, to diagnose invalid
+   #pragma omp declare reduction combiners or initializers.  */
+
+tree
+c_check_omp_declare_reduction_r (tree *tp, int *, void *data)
+{
+  tree *vars = (tree *) data;
+  if (SSA_VAR_P (*tp)
+      && !DECL_ARTIFICIAL (*tp)
+      && *tp != vars[0]
+      && *tp != vars[1])
+    {
+      location_t loc = DECL_SOURCE_LOCATION (vars[0]);
+      if (strcmp (IDENTIFIER_POINTER (DECL_NAME (vars[0])), "omp_out") == 0)
+	error_at (loc, "%<#pragma omp declare reduction%> combiner refers to "
+		       "variable %qD which is not %<omp_out%> nor %<omp_in%>",
+		  *tp);
+      else
+	error_at (loc, "%<#pragma omp declare reduction%> initializer refers "
+		       "to variable %qD which is not %<omp_priv%> nor "
+		       "%<omp_orig%>",
+		  *tp);
+      return *tp;
+    }
+  return NULL_TREE;
+}
+
 #include "gt-c-c-decl.h"
--- gcc/c/c-lang.h	(.../trunk)	(revision 203241)
+++ gcc/c/c-lang.h	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -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/c-parser.c	(.../trunk)	(revision 203241)
+++ gcc/c/c-parser.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -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"
@@ -162,9 +163,12 @@  typedef struct GTY (()) c_token {
    tokens of look-ahead; more are not needed for C.  */
 typedef struct GTY(()) c_parser {
   /* The look-ahead tokens.  */
-  c_token tokens[2];
-  /* How many look-ahead tokens are available (0, 1 or 2).  */
-  short tokens_avail;
+  c_token * GTY((skip)) tokens;
+  /* Buffer for look-ahead tokens.  */
+  c_token tokens_buf[2];
+  /* How many look-ahead tokens are available (0, 1 or 2, or
+     more if parsing from pre-lexed tokens).  */
+  unsigned int tokens_avail;
   /* True if a syntax error is being recovered from; false otherwise.
      c_parser_error sets this flag.  It should clear this flag when
      enough tokens have been consumed to recover from the error.  */
@@ -736,7 +740,9 @@  c_parser_consume_token (c_parser *parser
   gcc_assert (parser->tokens[0].type != CPP_EOF);
   gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL);
   gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA);
-  if (parser->tokens_avail == 2)
+  if (parser->tokens != &parser->tokens_buf[0])
+    parser->tokens++;
+  else if (parser->tokens_avail == 2)
     parser->tokens[0] = parser->tokens[1];
   parser->tokens_avail--;
 }
@@ -750,7 +756,9 @@  c_parser_consume_pragma (c_parser *parse
   gcc_assert (!parser->in_pragma);
   gcc_assert (parser->tokens_avail >= 1);
   gcc_assert (parser->tokens[0].type == CPP_PRAGMA);
-  if (parser->tokens_avail == 2)
+  if (parser->tokens != &parser->tokens_buf[0])
+    parser->tokens++;
+  else if (parser->tokens_avail == 2)
     parser->tokens[0] = parser->tokens[1];
   parser->tokens_avail--;
   parser->in_pragma = true;
@@ -1112,7 +1120,7 @@  enum c_parser_prec {
 static void c_parser_external_declaration (c_parser *);
 static void c_parser_asm_definition (c_parser *);
 static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
-					   bool, bool, tree *);
+					   bool, bool, tree *, vec<c_token>);
 static void c_parser_static_assert_declaration_no_semi (c_parser *);
 static void c_parser_static_assert_declaration (c_parser *);
 static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
@@ -1155,11 +1163,12 @@  static tree c_parser_asm_statement (c_pa
 static tree c_parser_asm_operands (c_parser *);
 static tree c_parser_asm_goto_operands (c_parser *);
 static tree c_parser_asm_clobbers (c_parser *);
-static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *);
+static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *,
+					      tree = NULL_TREE);
 static struct c_expr c_parser_conditional_expression (c_parser *,
-						      struct c_expr *);
+						      struct c_expr *, tree);
 static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
-						 enum c_parser_prec);
+						 tree);
 static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
 static struct c_expr c_parser_unary_expression (c_parser *);
 static struct c_expr c_parser_sizeof_expression (c_parser *);
@@ -1185,9 +1194,15 @@  static void c_parser_omp_barrier (c_pars
 static void c_parser_omp_flush (c_parser *);
 static void c_parser_omp_taskwait (c_parser *);
 static void c_parser_omp_taskyield (c_parser *);
+static void c_parser_omp_cancel (c_parser *);
+static void c_parser_omp_cancellation_point (c_parser *);
 
-enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
+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
    compiling Objective-C.  */
@@ -1360,11 +1375,14 @@  c_parser_external_declaration (c_parser
 	 an @interface or @protocol with prefix attributes).  We can
 	 only tell which after parsing the declaration specifiers, if
 	 any, and the first declarator.  */
-      c_parser_declaration_or_fndef (parser, true, true, true, false, true, NULL);
+      c_parser_declaration_or_fndef (parser, true, true, true, false, true,
+				     NULL, vNULL);
       break;
     }
 }
 
+static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
+
 /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
    6.7, 6.9.1).  If FNDEF_OK is true, a function definition is
    accepted; otherwise (old-style parameter declarations) only other
@@ -1440,7 +1458,8 @@  static void
 c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 			       bool static_assert_ok, bool empty_ok,
 			       bool nested, bool start_attr_ok,
-			       tree *objc_foreach_object_declaration)
+			       tree *objc_foreach_object_declaration,
+			       vec<c_token> omp_declare_simd_clauses)
 {
   struct c_declspecs *specs;
   tree prefix_attrs;
@@ -1610,6 +1629,9 @@  c_parser_declaration_or_fndef (c_parser
 					C_DTR_NORMAL, &dummy);
       if (declarator == NULL)
 	{
+	  if (omp_declare_simd_clauses.exists ())
+	    c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE,
+				       omp_declare_simd_clauses);
 	  c_parser_skip_to_end_of_block_or_statement (parser);
 	  return;
 	}
@@ -1646,6 +1668,9 @@  c_parser_declaration_or_fndef (c_parser
 			      chainon (postfix_attrs, all_prefix_attrs));
 	      if (!d)
 		d = error_mark_node;
+	      if (omp_declare_simd_clauses.exists ())
+		c_finish_omp_declare_simd (parser, d, NULL_TREE,
+					   omp_declare_simd_clauses);
 	      start_init (d, asm_name, global_bindings_p ());
 	      init_loc = c_parser_peek_token (parser)->location;
 	      init = c_parser_initializer (parser);
@@ -1662,6 +1687,28 @@  c_parser_declaration_or_fndef (c_parser
 	      tree d = start_decl (declarator, specs, false,
 				   chainon (postfix_attrs,
 					    all_prefix_attrs));
+	      if (omp_declare_simd_clauses.exists ())
+		{
+		  tree parms = NULL_TREE;
+		  if (d && TREE_CODE (d) == FUNCTION_DECL)
+		    {
+		      struct c_declarator *ce = declarator;
+		      while (ce != NULL)
+			if (ce->kind == cdk_function)
+			  {
+			    parms = ce->u.arg_info->parms;
+			    break;
+			  }
+			else
+			  ce = ce->declarator;
+		    }
+		  if (parms)
+		    temp_store_parm_decls (d, parms);
+		  c_finish_omp_declare_simd (parser, d, parms,
+					     omp_declare_simd_clauses);
+		  if (parms)
+		    temp_pop_parm_decls ();
+		}
 	      if (d)
 		finish_decl (d, UNKNOWN_LOCATION, NULL_TREE,
 			     NULL_TREE, asm_name);
@@ -1751,8 +1798,11 @@  c_parser_declaration_or_fndef (c_parser
       while (c_parser_next_token_is_not (parser, CPP_EOF)
 	     && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
 	c_parser_declaration_or_fndef (parser, false, false, false,
-				       true, false, NULL);
+				       true, false, NULL, vNULL);
       store_parm_decls ();
+      if (omp_declare_simd_clauses.exists ())
+	c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
+				   omp_declare_simd_clauses);
       DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
 	= c_parser_peek_token (parser)->location;
       fnbody = c_parser_compound_statement (parser);
@@ -2481,7 +2531,7 @@  c_parser_struct_or_union_specifier (c_pa
 	  /* Accept #pragmas at struct scope.  */
 	  if (c_parser_next_token_is (parser, CPP_PRAGMA))
 	    {
-	      c_parser_pragma (parser, pragma_external);
+	      c_parser_pragma (parser, pragma_struct);
 	      continue;
 	    }
 	  /* Parse some comma-separated declarations, but not the
@@ -3329,7 +3379,7 @@  c_parser_parameter_declaration (c_parser
 
   /* Accept #pragmas between parameter declarations.  */
   while (c_parser_next_token_is (parser, CPP_PRAGMA))
-    c_parser_pragma (parser, pragma_external);
+    c_parser_pragma (parser, pragma_param);
 
   if (!c_parser_next_token_starts_declspecs (parser))
     {
@@ -4074,7 +4124,11 @@  c_parser_initval (c_parser *parser, stru
 
    openmp-directive:
      barrier-directive
-     flush-directive  */
+     flush-directive
+     taskwait-directive
+     taskyield-directive
+     cancel-directive
+     cancellation-point-directive  */
 
 static tree
 c_parser_compound_statement (c_parser *parser)
@@ -4179,7 +4233,8 @@  c_parser_compound_statement_nostart (c_p
 	{
 	  last_label = false;
 	  mark_valid_location_for_stdc_pragma (false);
-	  c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL);
+	  c_parser_declaration_or_fndef (parser, true, true, true, true,
+					 true, NULL, vNULL);
 	  if (last_stmt)
 	    pedwarn_c90 (loc,
 			 (pedantic && !flag_isoc99)
@@ -4207,7 +4262,7 @@  c_parser_compound_statement_nostart (c_p
 	      last_label = false;
 	      mark_valid_location_for_stdc_pragma (false);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL);
+					     true, NULL, vNULL);
 	      /* Following the old parser, __extension__ does not
 		 disable this diagnostic.  */
 	      restore_extension_diagnostics (ext);
@@ -4345,7 +4400,8 @@  c_parser_label (c_parser *parser)
 	  c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false,
 					 /*static_assert_ok*/ true,
 					 /*empty_ok*/ true, /*nested*/ true,
-					 /*start_attr_ok*/ true, NULL);
+					 /*start_attr_ok*/ true, NULL,
+					 vNULL);
 	}
     }
 }
@@ -4408,9 +4464,12 @@  c_parser_label (c_parser *parser)
    openmp-construct:
      parallel-construct
      for-construct
+     simd-construct
+     for-simd-construct
      sections-construct
      single-construct
      parallel-for-construct
+     parallel-for-simd-construct
      parallel-sections-construct
      master-construct
      critical-construct
@@ -4423,6 +4482,12 @@  c_parser_label (c_parser *parser)
    for-construct:
      for-directive iteration-statement
 
+   simd-construct:
+     simd-directive iteration-statements
+
+   for-simd-construct:
+     for-simd-directive iteration-statements
+
    sections-construct:
      sections-directive section-scope
 
@@ -4432,6 +4497,9 @@  c_parser_label (c_parser *parser)
    parallel-for-construct:
      parallel-for-directive iteration-statement
 
+   parallel-for-simd-construct:
+     parallel-for-simd-directive iteration-statement
+
    parallel-sections-construct:
      parallel-sections-directive section-scope
 
@@ -4979,7 +5047,7 @@  c_parser_for_statement (c_parser *parser
       else if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true, 
-					 &object_expression);
+					 &object_expression, vNULL);
 	  parser->objc_could_be_foreach_context = false;
 	  
 	  if (c_parser_next_token_is_keyword (parser, RID_IN))
@@ -5008,7 +5076,7 @@  c_parser_for_statement (c_parser *parser
 	      ext = disable_extension_diagnostics ();
 	      c_parser_consume_token (parser);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, &object_expression);
+					     true, &object_expression, vNULL);
 	      parser->objc_could_be_foreach_context = false;
 	      
 	      restore_extension_diagnostics (ext);
@@ -5396,13 +5464,14 @@  c_parser_asm_goto_operands (c_parser *pa
    error.  */
 
 static struct c_expr
-c_parser_expr_no_commas (c_parser *parser, struct c_expr *after)
+c_parser_expr_no_commas (c_parser *parser, struct c_expr *after,
+			 tree omp_atomic_lhs)
 {
   struct c_expr lhs, rhs, ret;
   enum tree_code code;
   location_t op_location, exp_location;
   gcc_assert (!after || c_dialect_objc ());
-  lhs = c_parser_conditional_expression (parser, after);
+  lhs = c_parser_conditional_expression (parser, after, omp_atomic_lhs);
   op_location = c_parser_peek_token (parser)->location;
   switch (c_parser_peek_token (parser)->type)
     {
@@ -5476,14 +5545,15 @@  c_parser_expr_no_commas (c_parser *parse
 */
 
 static struct c_expr
-c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
+c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
+				 tree omp_atomic_lhs)
 {
   struct c_expr cond, exp1, exp2, ret;
   location_t cond_loc, colon_loc, middle_loc;
 
   gcc_assert (!after || c_dialect_objc ());
 
-  cond = c_parser_binary_expression (parser, after, PREC_NONE);
+  cond = c_parser_binary_expression (parser, after, omp_atomic_lhs);
 
   if (c_parser_next_token_is_not (parser, CPP_QUERY))
     return cond;
@@ -5535,7 +5605,7 @@  c_parser_conditional_expression (c_parse
     }
   {
     location_t exp2_loc = c_parser_peek_token (parser)->location;
-    exp2 = c_parser_conditional_expression (parser, NULL);
+    exp2 = c_parser_conditional_expression (parser, NULL, NULL_TREE);
     exp2 = default_function_array_read_conversion (exp2_loc, exp2);
   }
   c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
@@ -5622,7 +5692,7 @@  c_parser_conditional_expression (c_parse
 
 static struct c_expr
 c_parser_binary_expression (c_parser *parser, struct c_expr *after,
-			    enum c_parser_prec prec)
+			    tree omp_atomic_lhs)
 {
   /* A binary expression is parsed using operator-precedence parsing,
      with the operands being cast expressions.  All the binary
@@ -5680,16 +5750,30 @@  c_parser_binary_expression (c_parser *pa
     stack[sp].expr							      \
       = default_function_array_read_conversion (stack[sp].loc,		      \
 						stack[sp].expr);	      \
-    stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc,		      \
-						 stack[sp].op,		      \
-						 stack[sp - 1].expr,	      \
-						 stack[sp].expr);	      \
+    if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1	      \
+	&& c_parser_peek_token (parser)->type == CPP_SEMICOLON		      \
+	&& ((1 << stack[sp].prec)					      \
+	    & (1 << (PREC_BITOR | PREC_BITXOR | PREC_BITAND | PREC_SHIFT      \
+		     | PREC_ADD | PREC_MULT)))				      \
+	&& stack[sp].op != TRUNC_MOD_EXPR				      \
+	&& stack[0].expr.value != error_mark_node			      \
+	&& stack[1].expr.value != error_mark_node			      \
+	&& (c_tree_equal (stack[0].expr.value, omp_atomic_lhs)		      \
+	    || c_tree_equal (stack[1].expr.value, omp_atomic_lhs)))	      \
+      stack[0].expr.value						      \
+	= build2 (stack[1].op, TREE_TYPE (stack[0].expr.value),		      \
+		  stack[0].expr.value, stack[1].expr.value);		      \
+    else								      \
+      stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc,	      \
+						   stack[sp].op,	      \
+						   stack[sp - 1].expr,	      \
+						   stack[sp].expr);	      \
     sp--;								      \
   } while (0)
   gcc_assert (!after || c_dialect_objc ());
   stack[0].loc = c_parser_peek_token (parser)->location;
   stack[0].expr = c_parser_cast_expression (parser, after);
-  stack[0].prec = prec;
+  stack[0].prec = PREC_NONE;
   sp = 0;
   while (true)
     {
@@ -5778,11 +5862,7 @@  c_parser_binary_expression (c_parser *pa
 	}
       binary_loc = c_parser_peek_token (parser)->location;
       while (oprec <= stack[sp].prec)
-	{
-	  if (sp == 0)
-	    goto out;
-	  POP;
-	}
+	POP;
       c_parser_consume_token (parser);
       switch (ocode)
 	{
@@ -7955,7 +8035,7 @@  c_parser_objc_methodprotolist (c_parser
 	    }
 	  else
 	    c_parser_declaration_or_fndef (parser, false, false, true,
-					   false, true, NULL);
+					   false, true, NULL, vNULL);
 	  break;
 	}
     }
@@ -8936,10 +9016,39 @@  c_parser_pragma (c_parser *parser, enum
       c_parser_omp_taskyield (parser);
       return false;
 
+    case PRAGMA_OMP_CANCEL:
+      if (context != pragma_compound)
+	{
+	  if (context == pragma_stmt)
+	    c_parser_error (parser, "%<#pragma omp cancel%> may only be "
+			    "used in compound statements");
+	  goto bad_stmt;
+	}
+      c_parser_omp_cancel (parser);
+      return false;
+
+    case PRAGMA_OMP_CANCELLATION_POINT:
+      if (context != pragma_compound)
+	{
+	  if (context == pragma_stmt)
+	    c_parser_error (parser, "%<#pragma omp cancellation point%> may "
+				    "only be used in compound statements");
+	  goto bad_stmt;
+	}
+      c_parser_omp_cancellation_point (parser);
+      return false;
+
     case PRAGMA_OMP_THREADPRIVATE:
       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 "
@@ -8947,6 +9056,10 @@  c_parser_pragma (c_parser *parser, enum
       c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
       return false;
 
+    case PRAGMA_OMP_DECLARE_REDUCTION:
+      c_parser_omp_declare (parser, context);
+      return false;
+
     case PRAGMA_GCC_PCH_PREPROCESS:
       c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first");
       c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
@@ -8955,7 +9068,7 @@  c_parser_pragma (c_parser *parser, enum
     default:
       if (id < PRAGMA_FIRST_EXTERNAL)
 	{
-	  if (context == pragma_external)
+	  if (context != pragma_stmt && context != pragma_compound)
 	    {
 	    bad_stmt:
 	      c_parser_error (parser, "expected declaration specifiers");
@@ -9020,7 +9133,7 @@  c_parser_pragma_pch_preprocess (c_parser
     c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name));
 }
 
-/* OpenMP 2.5 parsing routines.  */
+/* OpenMP 2.5 / 3.0 / 3.1 / 4.0 parsing routines.  */
 
 /* Returns name of the next clause.
    If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and
@@ -9036,12 +9149,18 @@  c_parser_omp_clause_name (c_parser *pars
     result = PRAGMA_OMP_CLAUSE_IF;
   else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT))
     result = PRAGMA_OMP_CLAUSE_DEFAULT;
+  else if (c_parser_next_token_is_keyword (parser, RID_FOR))
+    result = PRAGMA_OMP_CLAUSE_FOR;
   else if (c_parser_next_token_is (parser, CPP_NAME))
     {
       const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
 
       switch (p[0])
 	{
+	case 'a':
+	  if (!strcmp ("aligned", p))
+	    result = PRAGMA_OMP_CLAUSE_ALIGNED;
+	  break;
 	case 'c':
 	  if (!strcmp ("collapse", p))
 	    result = PRAGMA_OMP_CLAUSE_COLLAPSE;
@@ -9050,23 +9169,45 @@  c_parser_omp_clause_name (c_parser *pars
           else if (!strcmp ("copyprivate", p))
 	    result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
 	  break;
+	case 'd':
+	  if (!strcmp ("depend", p))
+	    result = PRAGMA_OMP_CLAUSE_DEPEND;
+	  else if (!strcmp ("device", p))
+	    result = PRAGMA_OMP_CLAUSE_DEVICE;
+	  else if (!strcmp ("dist_schedule", p))
+	    result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE;
+	  break;
 	case 'f':
 	  if (!strcmp ("final", p))
 	    result = PRAGMA_OMP_CLAUSE_FINAL;
 	  else if (!strcmp ("firstprivate", p))
 	    result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
+	  else if (!strcmp ("from", p))
+	    result = PRAGMA_OMP_CLAUSE_FROM;
+	  break;
+	case 'i':
+	  if (!strcmp ("inbranch", p))
+	    result = PRAGMA_OMP_CLAUSE_INBRANCH;
 	  break;
 	case 'l':
 	  if (!strcmp ("lastprivate", p))
 	    result = PRAGMA_OMP_CLAUSE_LASTPRIVATE;
+	  else if (!strcmp ("linear", p))
+	    result = PRAGMA_OMP_CLAUSE_LINEAR;
 	  break;
 	case 'm':
-	  if (!strcmp ("mergeable", p))
+	  if (!strcmp ("map", p))
+	    result = PRAGMA_OMP_CLAUSE_MAP;
+	  else if (!strcmp ("mergeable", p))
 	    result = PRAGMA_OMP_CLAUSE_MERGEABLE;
 	  break;
 	case 'n':
-	  if (!strcmp ("nowait", p))
+	  if (!strcmp ("notinbranch", p))
+	    result = PRAGMA_OMP_CLAUSE_NOTINBRANCH;
+	  else if (!strcmp ("nowait", p))
 	    result = PRAGMA_OMP_CLAUSE_NOWAIT;
+	  else if (!strcmp ("num_teams", p))
+	    result = PRAGMA_OMP_CLAUSE_NUM_TEAMS;
 	  else if (!strcmp ("num_threads", p))
 	    result = PRAGMA_OMP_CLAUSE_NUM_THREADS;
 	  break;
@@ -9075,21 +9216,41 @@  c_parser_omp_clause_name (c_parser *pars
 	    result = PRAGMA_OMP_CLAUSE_ORDERED;
 	  break;
 	case 'p':
-	  if (!strcmp ("private", p))
+	  if (!strcmp ("parallel", p))
+	    result = PRAGMA_OMP_CLAUSE_PARALLEL;
+	  else if (!strcmp ("private", p))
 	    result = PRAGMA_OMP_CLAUSE_PRIVATE;
+	  else if (!strcmp ("proc_bind", p))
+	    result = PRAGMA_OMP_CLAUSE_PROC_BIND;
 	  break;
 	case 'r':
 	  if (!strcmp ("reduction", p))
 	    result = PRAGMA_OMP_CLAUSE_REDUCTION;
 	  break;
 	case 's':
-	  if (!strcmp ("schedule", p))
+	  if (!strcmp ("safelen", p))
+	    result = PRAGMA_OMP_CLAUSE_SAFELEN;
+	  else if (!strcmp ("schedule", p))
 	    result = PRAGMA_OMP_CLAUSE_SCHEDULE;
+	  else if (!strcmp ("sections", p))
+	    result = PRAGMA_OMP_CLAUSE_SECTIONS;
 	  else if (!strcmp ("shared", p))
 	    result = PRAGMA_OMP_CLAUSE_SHARED;
+	  else if (!strcmp ("simdlen", p))
+	    result = PRAGMA_OMP_CLAUSE_SIMDLEN;
+	  break;
+	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;
 	case 'u':
-	  if (!strcmp ("untied", p))
+	  if (!strcmp ("uniform", p))
+	    result = PRAGMA_OMP_CLAUSE_UNIFORM;
+	  else if (!strcmp ("untied", p))
 	    result = PRAGMA_OMP_CLAUSE_UNTIED;
 	  break;
 	}
@@ -9133,8 +9294,7 @@  check_no_duplicate_clause (tree clauses,
 static tree
 c_parser_omp_variable_list (c_parser *parser,
 			    location_t clause_loc,
-			    enum omp_clause_code kind,
-                            tree list)
+			    enum omp_clause_code kind, tree list)
 {
   if (c_parser_next_token_is_not (parser, CPP_NAME)
       || c_parser_peek_token (parser)->id_kind != C_ID_ID)
@@ -9146,22 +9306,70 @@  c_parser_omp_variable_list (c_parser *pa
       tree 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;
 
@@ -9209,6 +9417,8 @@  c_parser_omp_clause_collapse (c_parser *
     }
   if (num == error_mark_node)
     return list;
+  mark_exp_read (num);
+  num = c_fully_fold (num, false, NULL);
   if (!INTEGRAL_TYPE_P (TREE_TYPE (num))
       || !host_integerp (num, 0)
       || (n = tree_low_cst (num, 0)) <= 0
@@ -9474,11 +9684,17 @@  c_parser_omp_clause_private (c_parser *p
 
    reduction-operator:
      One of: + * - & ^ | && ||
-     
+
    OpenMP 3.1:
    
    reduction-operator:
-     One of: + * - & ^ | && || max min  */
+     One of: + * - & ^ | && || max min
+
+   OpenMP 4.0:
+
+   reduction-operator:
+     One of: + * - & ^ | && ||
+     identifier  */
 
 static tree
 c_parser_omp_clause_reduction (c_parser *parser, tree list)
@@ -9486,7 +9702,8 @@  c_parser_omp_clause_reduction (c_parser
   location_t clause_loc = c_parser_peek_token (parser)->location;
   if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     {
-      enum tree_code code;
+      enum tree_code code = ERROR_MARK;
+      tree reduc_id = NULL_TREE;
 
       switch (c_parser_peek_token (parser)->type)
 	{
@@ -9528,8 +9745,9 @@  c_parser_omp_clause_reduction (c_parser
 		code = MAX_EXPR;
 		break;
 	      }
+	    reduc_id = c_parser_peek_token (parser)->value;
+	    break;
 	  }
-	  /* FALLTHRU */
 	default:
 	  c_parser_error (parser,
 			  "expected %<+%>, %<*%>, %<-%>, %<&%>, "
@@ -9538,6 +9756,7 @@  c_parser_omp_clause_reduction (c_parser
 	  return list;
 	}
       c_parser_consume_token (parser);
+      reduc_id = c_omp_reduction_id (code, reduc_id);
       if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
 	{
 	  tree nl, c;
@@ -9545,7 +9764,17 @@  c_parser_omp_clause_reduction (c_parser
 	  nl = c_parser_omp_variable_list (parser, clause_loc,
 					   OMP_CLAUSE_REDUCTION, list);
 	  for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
-	    OMP_CLAUSE_REDUCTION_CODE (c) = code;
+	    {
+	      tree type = TREE_TYPE (OMP_CLAUSE_DECL (c));
+	      OMP_CLAUSE_REDUCTION_CODE (c) = code;
+	      if (code == ERROR_MARK
+		  || !(INTEGRAL_TYPE_P (type)
+		       || TREE_CODE (type) == REAL_TYPE
+		       || TREE_CODE (type) == COMPLEX_TYPE))
+		OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
+		  = c_omp_reduction_lookup (reduc_id,
+					    TYPE_MAIN_VARIANT (type));
+	    }
 
 	  list = nl;
 	}
@@ -9675,622 +9904,1280 @@  c_parser_omp_clause_untied (c_parser *pa
   return c;
 }
 
-/* Parse all OpenMP clauses.  The set clauses allowed by the directive
-   is a bitmask in MASK.  Return the list of clauses found; the result
-   of clause default goes in *pdefault.  */
+/* OpenMP 4.0:
+   inbranch
+   notinbranch */
 
 static tree
-c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
-			  const char *where)
+c_parser_omp_clause_branch (c_parser *parser ATTRIBUTE_UNUSED,
+			    enum omp_clause_code code, tree list)
 {
-  tree clauses = NULL;
-  bool first = true;
+  check_no_duplicate_clause (list, code, omp_clause_code_name[code]);
 
-  while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
-    {
-      location_t here;
-      pragma_omp_clause c_kind;
-      const char *c_name;
-      tree prev = clauses;
+  tree c = build_omp_clause (c_parser_peek_token (parser)->location, code);
+  OMP_CLAUSE_CHAIN (c) = list;
 
-      if (!first && c_parser_next_token_is (parser, CPP_COMMA))
-	c_parser_consume_token (parser);
+  return c;
+}
 
-      first = false;
-      here = c_parser_peek_token (parser)->location;
-      c_kind = c_parser_omp_clause_name (parser);
+/* OpenMP 4.0:
+   parallel
+   for
+   sections
+   taskgroup */
 
-      switch (c_kind)
+static tree
+c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED,
+				enum omp_clause_code code, tree list)
+{
+  tree c = build_omp_clause (c_parser_peek_token (parser)->location, code);
+  OMP_CLAUSE_CHAIN (c) = list;
+
+  return c;
+}
+
+/* OpenMP 4.0:
+   num_teams ( expression ) */
+
+static tree
+c_parser_omp_clause_num_teams (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)))
 	{
-	case PRAGMA_OMP_CLAUSE_COLLAPSE:
-	  clauses = c_parser_omp_clause_collapse (parser, clauses);
-	  c_name = "collapse";
-	  break;
-	case PRAGMA_OMP_CLAUSE_COPYIN:
-	  clauses = c_parser_omp_clause_copyin (parser, clauses);
-	  c_name = "copyin";
-	  break;
-	case PRAGMA_OMP_CLAUSE_COPYPRIVATE:
-	  clauses = c_parser_omp_clause_copyprivate (parser, clauses);
-	  c_name = "copyprivate";
-	  break;
-	case PRAGMA_OMP_CLAUSE_DEFAULT:
-	  clauses = c_parser_omp_clause_default (parser, clauses);
-	  c_name = "default";
-	  break;
-	case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
-	  clauses = c_parser_omp_clause_firstprivate (parser, clauses);
-	  c_name = "firstprivate";
-	  break;
-	case PRAGMA_OMP_CLAUSE_FINAL:
-	  clauses = c_parser_omp_clause_final (parser, clauses);
-	  c_name = "final";
-	  break;
-	case PRAGMA_OMP_CLAUSE_IF:
-	  clauses = c_parser_omp_clause_if (parser, clauses);
-	  c_name = "if";
-	  break;
-	case PRAGMA_OMP_CLAUSE_LASTPRIVATE:
-	  clauses = c_parser_omp_clause_lastprivate (parser, clauses);
-	  c_name = "lastprivate";
-	  break;
-	case PRAGMA_OMP_CLAUSE_MERGEABLE:
-	  clauses = c_parser_omp_clause_mergeable (parser, clauses);
-	  c_name = "mergeable";
-	  break;
-	case PRAGMA_OMP_CLAUSE_NOWAIT:
-	  clauses = c_parser_omp_clause_nowait (parser, clauses);
-	  c_name = "nowait";
-	  break;
-	case PRAGMA_OMP_CLAUSE_NUM_THREADS:
-	  clauses = c_parser_omp_clause_num_threads (parser, clauses);
-	  c_name = "num_threads";
-	  break;
-	case PRAGMA_OMP_CLAUSE_ORDERED:
-	  clauses = c_parser_omp_clause_ordered (parser, clauses);
-	  c_name = "ordered";
-	  break;
-	case PRAGMA_OMP_CLAUSE_PRIVATE:
-	  clauses = c_parser_omp_clause_private (parser, clauses);
-	  c_name = "private";
-	  break;
-	case PRAGMA_OMP_CLAUSE_REDUCTION:
-	  clauses = c_parser_omp_clause_reduction (parser, clauses);
-	  c_name = "reduction";
-	  break;
-	case PRAGMA_OMP_CLAUSE_SCHEDULE:
-	  clauses = c_parser_omp_clause_schedule (parser, clauses);
-	  c_name = "schedule";
-	  break;
-	case PRAGMA_OMP_CLAUSE_SHARED:
-	  clauses = c_parser_omp_clause_shared (parser, clauses);
-	  c_name = "shared";
-	  break;
-	case PRAGMA_OMP_CLAUSE_UNTIED:
-	  clauses = c_parser_omp_clause_untied (parser, clauses);
-	  c_name = "untied";
-	  break;
-	default:
-	  c_parser_error (parser, "expected %<#pragma omp%> clause");
-	  goto saw_error;
+	  c_parser_error (parser, "expected integer expression");
+	  return list;
 	}
 
-      if (((mask >> c_kind) & 1) == 0 && !parser->error)
+      /* 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)
 	{
-	  /* Remove the invalid clause(s) from the list to avoid
-	     confusing the rest of the compiler.  */
-	  clauses = prev;
-	  error_at (here, "%qs is not valid for %qs", c_name, where);
+	  warning_at (expr_loc, 0, "%<num_teams%> value must be positive");
+	  t = integer_one_node;
 	}
-    }
 
- saw_error:
-  c_parser_skip_to_pragma_eol (parser);
+      check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TEAMS, "num_teams");
 
-  return c_finish_omp_clauses (clauses);
-}
+      c = build_omp_clause (num_teams_loc, OMP_CLAUSE_NUM_TEAMS);
+      OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t;
+      OMP_CLAUSE_CHAIN (c) = list;
+      list = c;
+    }
 
-/* OpenMP 2.5:
-   structured-block:
-     statement
+  return list;
+}
 
-   In practice, we're also interested in adding the statement to an
-   outer node.  So it is convenient if we work around the fact that
-   c_parser_statement calls add_stmt.  */
+/* OpenMP 4.0:
+   thread_limit ( expression ) */
 
 static tree
-c_parser_omp_structured_block (c_parser *parser)
+c_parser_omp_clause_thread_limit (c_parser *parser, tree list)
 {
-  tree stmt = push_stmt_list ();
-  c_parser_statement (parser);
-  return pop_stmt_list (stmt);
-}
+  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);
 
-/* OpenMP 2.5:
-   # pragma omp atomic new-line
-     expression-stmt
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
 
-   expression-stmt:
-     x binop= expr | x++ | ++x | x-- | --x
-   binop:
-     +, *, -, /, &, ^, |, <<, >>
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+	{
+	  c_parser_error (parser, "expected integer expression");
+	  return list;
+	}
 
-  where x is an lvalue expression with scalar type.
+      /* 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;
+	}
 
-   OpenMP 3.1:
-   # pragma omp atomic new-line
-     update-stmt
+      check_no_duplicate_clause (list, OMP_CLAUSE_THREAD_LIMIT,
+				 "thread_limit");
 
-   # pragma omp atomic read new-line
-     read-stmt
+      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;
+    }
 
-   # pragma omp atomic write new-line
-     write-stmt
+  return list;
+}
 
-   # pragma omp atomic update new-line
-     update-stmt
+/* OpenMP 4.0:
+   aligned ( variable-list )
+   aligned ( variable-list : constant-expression ) */
 
-   # pragma omp atomic capture new-line
-     capture-stmt
+static tree
+c_parser_omp_clause_aligned (c_parser *parser, tree list)
+{
+  location_t clause_loc = c_parser_peek_token (parser)->location;
+  tree nl, c;
 
-   # pragma omp atomic capture new-line
-     capture-block
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
 
-   read-stmt:
-     v = x
-   write-stmt:
-     x = expr
-   update-stmt:
-     expression-stmt | x = x binop expr
-   capture-stmt:
-     v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x
-   capture-block:
-     { v = x; update-stmt; } | { update-stmt; v = x; }
+  nl = c_parser_omp_variable_list (parser, clause_loc,
+				   OMP_CLAUSE_ALIGNED, list);
 
-  where x and v are lvalue expressions with scalar type.
+  if (c_parser_next_token_is (parser, CPP_COLON))
+    {
+      c_parser_consume_token (parser);
+      tree alignment = c_parser_expr_no_commas (parser, NULL).value;
+      mark_exp_read (alignment);
+      alignment = c_fully_fold (alignment, false, NULL);
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (alignment))
+	  && TREE_CODE (alignment) != INTEGER_CST
+	  && tree_int_cst_sgn (alignment) != 1)
+	{
+	  error_at (clause_loc, "%<aligned%> clause alignment expression must "
+				"be positive constant integer expression");
+	  alignment = NULL_TREE;
+	}
 
-  LOC is the location of the #pragma token.  */
+      for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+	OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment;
+    }
 
-static void
-c_parser_omp_atomic (location_t loc, c_parser *parser)
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  return nl;
+}
+
+/* OpenMP 4.0:
+   linear ( variable-list )
+   linear ( variable-list : expression ) */
+
+static tree
+c_parser_omp_clause_linear (c_parser *parser, tree list)
 {
-  tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE;
-  tree lhs1 = NULL_TREE, rhs1 = NULL_TREE;
-  tree stmt, orig_lhs;
-  enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR;
-  struct c_expr rhs_expr;
-  bool structured_block = false;
+  location_t clause_loc = c_parser_peek_token (parser)->location;
+  tree nl, c, step;
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
+
+  nl = c_parser_omp_variable_list (parser, clause_loc,
+				   OMP_CLAUSE_LINEAR, list);
+
+  if (c_parser_next_token_is (parser, CPP_COLON))
+    {
+      c_parser_consume_token (parser);
+      step = c_parser_expression (parser).value;
+      mark_exp_read (step);
+      step = c_fully_fold (step, false, NULL);
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (step)))
+	{
+	  error_at (clause_loc, "%<linear%> clause step expression must "
+				"be integral");
+	  step = integer_one_node;
+	}
+
+    }
+  else
+    step = integer_one_node;
+
+  for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+    {
+      OMP_CLAUSE_LINEAR_STEP (c) = step;
+    }
+
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  return nl;
+}
+
+/* OpenMP 4.0:
+   safelen ( constant-expression ) */
+
+static tree
+c_parser_omp_clause_safelen (c_parser *parser, tree list)
+{
+  location_t clause_loc = c_parser_peek_token (parser)->location;
+  tree c, t;
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
+
+  t = c_parser_expr_no_commas (parser, NULL).value;
+  mark_exp_read (t);
+  t = c_fully_fold (t, false, NULL);
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+      && TREE_CODE (t) != INTEGER_CST
+      && tree_int_cst_sgn (t) != 1)
+    {
+      error_at (clause_loc, "%<safelen%> clause expression must "
+			    "be positive constant integer expression");
+      t = NULL_TREE;
+    }
+
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  if (t == NULL_TREE || t == error_mark_node)
+    return list;
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_SAFELEN, "safelen");
+
+  c = build_omp_clause (clause_loc, OMP_CLAUSE_SAFELEN);
+  OMP_CLAUSE_SAFELEN_EXPR (c) = t;
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
+}
+
+/* OpenMP 4.0:
+   simdlen ( constant-expression ) */
+
+static tree
+c_parser_omp_clause_simdlen (c_parser *parser, tree list)
+{
+  location_t clause_loc = c_parser_peek_token (parser)->location;
+  tree c, t;
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
+
+  t = c_parser_expr_no_commas (parser, NULL).value;
+  mark_exp_read (t);
+  t = c_fully_fold (t, false, NULL);
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+      && TREE_CODE (t) != INTEGER_CST
+      && tree_int_cst_sgn (t) != 1)
+    {
+      error_at (clause_loc, "%<simdlen%> clause expression must "
+			    "be positive constant integer expression");
+      t = NULL_TREE;
+    }
+
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  if (t == NULL_TREE || t == error_mark_node)
+    return list;
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen");
+
+  c = build_omp_clause (clause_loc, OMP_CLAUSE_SIMDLEN);
+  OMP_CLAUSE_SIMDLEN_EXPR (c) = t;
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
+}
+
+/* OpenMP 4.0:
+   depend ( depend-kind: variable-list )
+
+   depend-kind:
+     in | out | inout  */
+
+static tree
+c_parser_omp_clause_depend (c_parser *parser, tree list)
+{
+  location_t clause_loc = c_parser_peek_token (parser)->location;
+  enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT;
+  tree nl, c;
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
 
   if (c_parser_next_token_is (parser, CPP_NAME))
     {
       const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
-
-      if (!strcmp (p, "read"))
-	code = OMP_ATOMIC_READ;
-      else if (!strcmp (p, "write"))
-	code = NOP_EXPR;
-      else if (!strcmp (p, "update"))
-	code = OMP_ATOMIC;
-      else if (!strcmp (p, "capture"))
-	code = OMP_ATOMIC_CAPTURE_NEW;
+      if (strcmp ("in", p) == 0)
+	kind = OMP_CLAUSE_DEPEND_IN;
+      else if (strcmp ("inout", p) == 0)
+	kind = OMP_CLAUSE_DEPEND_INOUT;
+      else if (strcmp ("out", p) == 0)
+	kind = OMP_CLAUSE_DEPEND_OUT;
       else
-	p = NULL;
-      if (p)
-	c_parser_consume_token (parser);
+	goto invalid_kind;
     }
-  c_parser_skip_to_pragma_eol (parser);
+  else
+    goto invalid_kind;
 
-  switch (code)
+  c_parser_consume_token (parser);
+  if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+    goto resync_fail;
+
+  nl = c_parser_omp_variable_list (parser, clause_loc,
+				   OMP_CLAUSE_DEPEND, list);
+
+  for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+    OMP_CLAUSE_DEPEND_KIND (c) = kind;
+
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  return nl;
+
+ invalid_kind:
+  c_parser_error (parser, "invalid depend kind");
+ resync_fail:
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  return list;
+}
+
+/* OpenMP 4.0:
+   map ( map-kind: variable-list )
+   map ( variable-list )
+
+   map-kind:
+     alloc | to | from | tofrom  */
+
+static tree
+c_parser_omp_clause_map (c_parser *parser, tree list)
+{
+  location_t clause_loc = c_parser_peek_token (parser)->location;
+  enum omp_clause_map_kind kind = OMP_CLAUSE_MAP_TOFROM;
+  tree nl, c;
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
+
+  if (c_parser_next_token_is (parser, CPP_NAME)
+      && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
     {
-    case OMP_ATOMIC_READ:
-    case NOP_EXPR: /* atomic write */
-      v = c_parser_unary_expression (parser).value;
-      v = c_fully_fold (v, false, NULL);
-      if (v == error_mark_node)
-	goto saw_error;
-      loc = c_parser_peek_token (parser)->location;
-      if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
-	goto saw_error;
-      if (code == NOP_EXPR)
-	lhs = c_parser_expression (parser).value;
-      else
-	lhs = c_parser_unary_expression (parser).value;
-      lhs = c_fully_fold (lhs, false, NULL);
-      if (lhs == error_mark_node)
-	goto saw_error;
-      if (code == NOP_EXPR)
-	{
-	  /* atomic write is represented by OMP_ATOMIC with NOP_EXPR
-	     opcode.  */
-	  code = OMP_ATOMIC;
-	  rhs = lhs;
-	  lhs = v;
-	  v = NULL_TREE;
-	}
-      goto done;
-    case OMP_ATOMIC_CAPTURE_NEW:
-      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
-	{
-	  c_parser_consume_token (parser);
-	  structured_block = true;
-	}
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (strcmp ("alloc", p) == 0)
+	kind = OMP_CLAUSE_MAP_ALLOC;
+      else if (strcmp ("to", p) == 0)
+	kind = OMP_CLAUSE_MAP_TO;
+      else if (strcmp ("from", p) == 0)
+	kind = OMP_CLAUSE_MAP_FROM;
+      else if (strcmp ("tofrom", p) == 0)
+	kind = OMP_CLAUSE_MAP_TOFROM;
       else
 	{
-	  v = c_parser_unary_expression (parser).value;
-	  v = c_fully_fold (v, false, NULL);
-	  if (v == error_mark_node)
-	    goto saw_error;
-	  if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
-	    goto saw_error;
+	  c_parser_error (parser, "invalid map kind");
+	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				     "expected %<)%>");
+	  return list;
 	}
-      break;
-    default:
-      break;
+      c_parser_consume_token (parser);
+      c_parser_consume_token (parser);
     }
 
-  /* For structured_block case we don't know yet whether
-     old or new x should be captured.  */
-restart:
-  lhs = c_parser_unary_expression (parser).value;
-  lhs = c_fully_fold (lhs, false, NULL);
-  orig_lhs = lhs;
-  switch (TREE_CODE (lhs))
+  nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list);
+
+  for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+    OMP_CLAUSE_MAP_KIND (c) = kind;
+
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  return nl;
+}
+
+/* OpenMP 4.0:
+   device ( expression ) */
+
+static tree
+c_parser_omp_clause_device (c_parser *parser, tree list)
+{
+  location_t clause_loc = c_parser_peek_token (parser)->location;
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     {
-    case ERROR_MARK:
-    saw_error:
-      c_parser_skip_to_end_of_block_or_statement (parser);
-      if (structured_block)
+      tree c, t = c_parser_expr_no_commas (parser, NULL).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)))
 	{
-	  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
-	    c_parser_consume_token (parser);
-	  else if (code == OMP_ATOMIC_CAPTURE_NEW)
-	    {
-	      c_parser_skip_to_end_of_block_or_statement (parser);
-	      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
-		c_parser_consume_token (parser);
-	    }
+	  c_parser_error (parser, "expected integer expression");
+	  return list;
 	}
-      return;
 
-    case POSTINCREMENT_EXPR:
-      if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
-	code = OMP_ATOMIC_CAPTURE_OLD;
-      /* FALLTHROUGH */
-    case PREINCREMENT_EXPR:
-      lhs = TREE_OPERAND (lhs, 0);
-      opcode = PLUS_EXPR;
-      rhs = integer_one_node;
-      break;
+      check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE, "device");
 
-    case POSTDECREMENT_EXPR:
-      if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
-	code = OMP_ATOMIC_CAPTURE_OLD;
-      /* FALLTHROUGH */
-    case PREDECREMENT_EXPR:
-      lhs = TREE_OPERAND (lhs, 0);
-      opcode = MINUS_EXPR;
-      rhs = integer_one_node;
-      break;
+      c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE);
+      OMP_CLAUSE_DEVICE_ID (c) = t;
+      OMP_CLAUSE_CHAIN (c) = list;
+      list = c;
+    }
 
-    case COMPOUND_EXPR:
-      if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR
-	  && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR
-	  && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR
-	  && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0)
-	  && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND
-					      (TREE_OPERAND (lhs, 1), 0), 0)))
-	     == BOOLEAN_TYPE)
-	/* Undo effects of boolean_increment for post {in,de}crement.  */
-	lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0);
-      /* FALLTHRU */
-    case MODIFY_EXPR:
-      if (TREE_CODE (lhs) == MODIFY_EXPR
-	  && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE)
-	{
-	  /* Undo effects of boolean_increment.  */
-	  if (integer_onep (TREE_OPERAND (lhs, 1)))
-	    {
-	      /* This is pre or post increment.  */
-	      rhs = TREE_OPERAND (lhs, 1);
-	      lhs = TREE_OPERAND (lhs, 0);
-	      opcode = NOP_EXPR;
-	      if (code == OMP_ATOMIC_CAPTURE_NEW
-		  && !structured_block
-		  && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
-		code = OMP_ATOMIC_CAPTURE_OLD;
-	      break;
-	    }
-	  if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR
-	      && TREE_OPERAND (lhs, 0)
-		 == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0))
-	    {
-	      /* This is pre or post decrement.  */
-	      rhs = TREE_OPERAND (lhs, 1);
-	      lhs = TREE_OPERAND (lhs, 0);
-	      opcode = NOP_EXPR;
-	      if (code == OMP_ATOMIC_CAPTURE_NEW
-		  && !structured_block
-		  && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
-		code = OMP_ATOMIC_CAPTURE_OLD;
-	      break;
-	    }
-	}
-      /* FALLTHRU */
-    default:
-      switch (c_parser_peek_token (parser)->type)
-	{
-	case CPP_MULT_EQ:
-	  opcode = MULT_EXPR;
-	  break;
-	case CPP_DIV_EQ:
-	  opcode = TRUNC_DIV_EXPR;
-	  break;
-	case CPP_PLUS_EQ:
-	  opcode = PLUS_EXPR;
-	  break;
-	case CPP_MINUS_EQ:
-	  opcode = MINUS_EXPR;
-	  break;
-	case CPP_LSHIFT_EQ:
-	  opcode = LSHIFT_EXPR;
-	  break;
-	case CPP_RSHIFT_EQ:
-	  opcode = RSHIFT_EXPR;
-	  break;
-	case CPP_AND_EQ:
-	  opcode = BIT_AND_EXPR;
-	  break;
-	case CPP_OR_EQ:
-	  opcode = BIT_IOR_EXPR;
-	  break;
-	case CPP_XOR_EQ:
-	  opcode = BIT_XOR_EXPR;
-	  break;
-	case CPP_EQ:
-	  if (structured_block || code == OMP_ATOMIC)
-	    {
-	      location_t aloc = c_parser_peek_token (parser)->location;
-	      location_t rhs_loc;
-	      enum c_parser_prec oprec = PREC_NONE;
+  return list;
+}
 
-	      c_parser_consume_token (parser);
-	      rhs1 = c_parser_unary_expression (parser).value;
-	      rhs1 = c_fully_fold (rhs1, false, NULL);
-	      if (rhs1 == error_mark_node)
-		goto saw_error;
-	      switch (c_parser_peek_token (parser)->type)
-		{
-		case CPP_SEMICOLON:
-		  if (code == OMP_ATOMIC_CAPTURE_NEW)
-		    {
-		      code = OMP_ATOMIC_CAPTURE_OLD;
-		      v = lhs;
-		      lhs = NULL_TREE;
-		      lhs1 = rhs1;
-		      rhs1 = NULL_TREE;
-		      c_parser_consume_token (parser);
-		      goto restart;
-		    }
-		  c_parser_error (parser,
-				  "invalid form of %<#pragma omp atomic%>");
-		  goto saw_error;
-		case CPP_MULT:
-		  opcode = MULT_EXPR;
-		  oprec = PREC_MULT;
-		  break;
-		case CPP_DIV:
-		  opcode = TRUNC_DIV_EXPR;
-		  oprec = PREC_MULT;
-		  break;
-		case CPP_PLUS:
-		  opcode = PLUS_EXPR;
-		  oprec = PREC_ADD;
-		  break;
-		case CPP_MINUS:
-		  opcode = MINUS_EXPR;
-		  oprec = PREC_ADD;
-		  break;
-		case CPP_LSHIFT:
-		  opcode = LSHIFT_EXPR;
-		  oprec = PREC_SHIFT;
-		  break;
-		case CPP_RSHIFT:
-		  opcode = RSHIFT_EXPR;
-		  oprec = PREC_SHIFT;
-		  break;
-		case CPP_AND:
-		  opcode = BIT_AND_EXPR;
-		  oprec = PREC_BITAND;
-		  break;
-		case CPP_OR:
-		  opcode = BIT_IOR_EXPR;
-		  oprec = PREC_BITOR;
-		  break;
-		case CPP_XOR:
-		  opcode = BIT_XOR_EXPR;
-		  oprec = PREC_BITXOR;
-		  break;
-		default:
-		  c_parser_error (parser,
-				  "invalid operator for %<#pragma omp atomic%>");
-		  goto saw_error;
-		}
-	      loc = aloc;
-	      c_parser_consume_token (parser);
-	      rhs_loc = c_parser_peek_token (parser)->location;
-	      if (commutative_tree_code (opcode))
-		oprec = (enum c_parser_prec) (oprec - 1);
-	      rhs_expr = c_parser_binary_expression (parser, NULL, oprec);
-	      rhs_expr = default_function_array_read_conversion (rhs_loc,
-								 rhs_expr);
-	      rhs = rhs_expr.value;
-	      rhs = c_fully_fold (rhs, false, NULL);
-	      goto stmt_done; 
-	    }
-	  /* FALLTHROUGH */
-	default:
-	  c_parser_error (parser,
-			  "invalid operator for %<#pragma omp atomic%>");
-	  goto saw_error;
-	}
+/* OpenMP 4.0:
+   dist_schedule ( static )
+   dist_schedule ( static , expression ) */
 
-      /* Arrange to pass the location of the assignment operator to
-	 c_finish_omp_atomic.  */
-      loc = c_parser_peek_token (parser)->location;
-      c_parser_consume_token (parser);
-      {
-	location_t rhs_loc = c_parser_peek_token (parser)->location;
-	rhs_expr = c_parser_expression (parser);
-	rhs_expr = default_function_array_read_conversion (rhs_loc, rhs_expr);
-      }
-      rhs = rhs_expr.value;
-      rhs = c_fully_fold (rhs, false, NULL);
-      break;
-    }
-stmt_done:
-  if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
-    {
-      if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
-	goto saw_error;
-      v = c_parser_unary_expression (parser).value;
-      v = c_fully_fold (v, false, NULL);
-      if (v == error_mark_node)
-	goto saw_error;
-      if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
-	goto saw_error;
-      lhs1 = c_parser_unary_expression (parser).value;
-      lhs1 = c_fully_fold (lhs1, false, NULL);
-      if (lhs1 == error_mark_node)
-	goto saw_error;
-    }
-  if (structured_block)
+static tree
+c_parser_omp_clause_dist_schedule (c_parser *parser, tree list)
+{
+  tree c, t = NULL_TREE;
+  location_t loc = c_parser_peek_token (parser)->location;
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
+
+  if (!c_parser_next_token_is_keyword (parser, RID_STATIC))
     {
-      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
-      c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+      c_parser_error (parser, "invalid dist_schedule kind");
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				 "expected %<)%>");
+      return list;
     }
-done:
-  stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1);
-  if (stmt != error_mark_node)
-    add_stmt (stmt);
-
-  if (!structured_block)
-    c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
-}
 
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is (parser, CPP_COMMA))
+    {
+      c_parser_consume_token (parser);
 
-/* OpenMP 2.5:
-   # pragma omp barrier new-line
-*/
+      t = c_parser_expr_no_commas (parser, NULL).value;
+      mark_exp_read (t);
+      t = c_fully_fold (t, false, NULL);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  else
+    c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+			       "expected %<,%> or %<)%>");
 
-static void
-c_parser_omp_barrier (c_parser *parser)
-{
-  location_t loc = c_parser_peek_token (parser)->location;
-  c_parser_consume_pragma (parser);
-  c_parser_skip_to_pragma_eol (parser);
+  check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule");
+  if (t == error_mark_node)
+    return list;
 
-  c_finish_omp_barrier (loc);
+  c = build_omp_clause (loc, OMP_CLAUSE_DIST_SCHEDULE);
+  OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t;
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
 }
 
-/* OpenMP 2.5:
-   # pragma omp critical [(name)] new-line
-     structured-block
+/* OpenMP 4.0:
+   proc_bind ( proc-bind-kind )
 
-  LOC is the location of the #pragma itself.  */
+   proc-bind-kind:
+     master | close | spread  */
 
 static tree
-c_parser_omp_critical (location_t loc, c_parser *parser)
+c_parser_omp_clause_proc_bind (c_parser *parser, tree list)
 {
-  tree stmt, name = NULL;
+  location_t clause_loc = c_parser_peek_token (parser)->location;
+  enum omp_clause_proc_bind_kind kind;
+  tree c;
 
-  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
+
+  if (c_parser_next_token_is (parser, CPP_NAME))
     {
-      c_parser_consume_token (parser);
-      if (c_parser_next_token_is (parser, CPP_NAME))
-	{
-	  name = c_parser_peek_token (parser)->value;
-	  c_parser_consume_token (parser);
-	  c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
-	}
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (strcmp ("master", p) == 0)
+	kind = OMP_CLAUSE_PROC_BIND_MASTER;
+      else if (strcmp ("close", p) == 0)
+	kind = OMP_CLAUSE_PROC_BIND_CLOSE;
+      else if (strcmp ("spread", p) == 0)
+	kind = OMP_CLAUSE_PROC_BIND_SPREAD;
       else
-	c_parser_error (parser, "expected identifier");
+	goto invalid_kind;
     }
-  else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
-    c_parser_error (parser, "expected %<(%> or end of line");
-  c_parser_skip_to_pragma_eol (parser);
+  else
+    goto invalid_kind;
 
-  stmt = c_parser_omp_structured_block (parser);
-  return c_finish_omp_critical (loc, stmt, name);
-}
+  c_parser_consume_token (parser);
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  c = build_omp_clause (clause_loc, OMP_CLAUSE_PROC_BIND);
+  OMP_CLAUSE_PROC_BIND_KIND (c) = kind;
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
 
-/* OpenMP 2.5:
-   # pragma omp flush flush-vars[opt] new-line
+ invalid_kind:
+  c_parser_error (parser, "invalid proc_bind kind");
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  return list;
+}
 
-   flush-vars:
-     ( variable-list ) */
+/* OpenMP 4.0:
+   to ( variable-list ) */
 
-static void
-c_parser_omp_flush (c_parser *parser)
+static tree
+c_parser_omp_clause_to (c_parser *parser, tree list)
 {
-  location_t loc = c_parser_peek_token (parser)->location;
-  c_parser_consume_pragma (parser);
-  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
-    c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
-  else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
-    c_parser_error (parser, "expected %<(%> or end of line");
-  c_parser_skip_to_pragma_eol (parser);
-
-  c_finish_omp_flush (loc);
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list);
 }
 
-/* Parse the restricted form of the for statement allowed by OpenMP.
-   The real trick here is to determine the loop control variable early
-   so that we can push a new decl if necessary to make it private.
-   LOC is the location of the OMP in "#pragma omp".  */
+/* OpenMP 4.0:
+   from ( variable-list ) */
 
 static tree
-c_parser_omp_for_loop (location_t loc,
-		       c_parser *parser, tree clauses, tree *par_clauses)
+c_parser_omp_clause_from (c_parser *parser, tree list)
 {
-  tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
-  tree declv, condv, incrv, initv, ret = NULL;
-  bool fail = false, open_brace_parsed = false;
-  int i, collapse = 1, nbraces = 0;
-  location_t for_loc;
-  vec<tree, va_gc> *for_block = make_tree_vector ();
-
-  for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
-    if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
-      collapse = tree_low_cst (OMP_CLAUSE_COLLAPSE_EXPR (cl), 0);
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list);
+}
 
-  gcc_assert (collapse >= 1);
+/* OpenMP 4.0:
+   uniform ( variable-list ) */
 
-  declv = make_tree_vec (collapse);
-  initv = make_tree_vec (collapse);
-  condv = make_tree_vec (collapse);
-  incrv = make_tree_vec (collapse);
+static tree
+c_parser_omp_clause_uniform (c_parser *parser, tree list)
+{
+  /* The clauses location.  */
+  location_t loc = c_parser_peek_token (parser)->location;
 
-  if (!c_parser_next_token_is_keyword (parser, RID_FOR))
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     {
-      c_parser_error (parser, "for statement expected");
-      return NULL;
+      list = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_UNIFORM,
+					 list);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
     }
-  for_loc = c_parser_peek_token (parser)->location;
-  c_parser_consume_token (parser);
+  return list;
+}
 
-  for (i = 0; i < collapse; i++)
-    {
-      int bracecount = 0;
+/* Parse all OpenMP clauses.  The set clauses allowed by the directive
+   is a bitmask in MASK.  Return the list of clauses found; the result
+   of clause default goes in *pdefault.  */
 
-      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-	goto pop_scopes;
+static tree
+c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
+			  const char *where, bool finish_p = true)
+{
+  tree clauses = NULL;
+  bool first = true;
+
+  while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+    {
+      location_t here;
+      pragma_omp_clause c_kind;
+      const char *c_name;
+      tree prev = clauses;
+
+      if (!first && c_parser_next_token_is (parser, CPP_COMMA))
+	c_parser_consume_token (parser);
+
+      here = c_parser_peek_token (parser)->location;
+      c_kind = c_parser_omp_clause_name (parser);
+
+      switch (c_kind)
+	{
+	case PRAGMA_OMP_CLAUSE_COLLAPSE:
+	  clauses = c_parser_omp_clause_collapse (parser, clauses);
+	  c_name = "collapse";
+	  break;
+	case PRAGMA_OMP_CLAUSE_COPYIN:
+	  clauses = c_parser_omp_clause_copyin (parser, clauses);
+	  c_name = "copyin";
+	  break;
+	case PRAGMA_OMP_CLAUSE_COPYPRIVATE:
+	  clauses = c_parser_omp_clause_copyprivate (parser, clauses);
+	  c_name = "copyprivate";
+	  break;
+	case PRAGMA_OMP_CLAUSE_DEFAULT:
+	  clauses = c_parser_omp_clause_default (parser, clauses);
+	  c_name = "default";
+	  break;
+	case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
+	  clauses = c_parser_omp_clause_firstprivate (parser, clauses);
+	  c_name = "firstprivate";
+	  break;
+	case PRAGMA_OMP_CLAUSE_FINAL:
+	  clauses = c_parser_omp_clause_final (parser, clauses);
+	  c_name = "final";
+	  break;
+	case PRAGMA_OMP_CLAUSE_IF:
+	  clauses = c_parser_omp_clause_if (parser, clauses);
+	  c_name = "if";
+	  break;
+	case PRAGMA_OMP_CLAUSE_LASTPRIVATE:
+	  clauses = c_parser_omp_clause_lastprivate (parser, clauses);
+	  c_name = "lastprivate";
+	  break;
+	case PRAGMA_OMP_CLAUSE_MERGEABLE:
+	  clauses = c_parser_omp_clause_mergeable (parser, clauses);
+	  c_name = "mergeable";
+	  break;
+	case PRAGMA_OMP_CLAUSE_NOWAIT:
+	  clauses = c_parser_omp_clause_nowait (parser, clauses);
+	  c_name = "nowait";
+	  break;
+	case PRAGMA_OMP_CLAUSE_NUM_THREADS:
+	  clauses = c_parser_omp_clause_num_threads (parser, clauses);
+	  c_name = "num_threads";
+	  break;
+	case PRAGMA_OMP_CLAUSE_ORDERED:
+	  clauses = c_parser_omp_clause_ordered (parser, clauses);
+	  c_name = "ordered";
+	  break;
+	case PRAGMA_OMP_CLAUSE_PRIVATE:
+	  clauses = c_parser_omp_clause_private (parser, clauses);
+	  c_name = "private";
+	  break;
+	case PRAGMA_OMP_CLAUSE_REDUCTION:
+	  clauses = c_parser_omp_clause_reduction (parser, clauses);
+	  c_name = "reduction";
+	  break;
+	case PRAGMA_OMP_CLAUSE_SCHEDULE:
+	  clauses = c_parser_omp_clause_schedule (parser, clauses);
+	  c_name = "schedule";
+	  break;
+	case PRAGMA_OMP_CLAUSE_SHARED:
+	  clauses = c_parser_omp_clause_shared (parser, clauses);
+	  c_name = "shared";
+	  break;
+	case PRAGMA_OMP_CLAUSE_UNTIED:
+	  clauses = c_parser_omp_clause_untied (parser, clauses);
+	  c_name = "untied";
+	  break;
+	case PRAGMA_OMP_CLAUSE_INBRANCH:
+	  clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH,
+						clauses);
+	  c_name = "inbranch";
+	  break;
+	case PRAGMA_OMP_CLAUSE_NOTINBRANCH:
+	  clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_NOTINBRANCH,
+						clauses);
+	  c_name = "notinbranch";
+	  break;
+	case PRAGMA_OMP_CLAUSE_PARALLEL:
+	  clauses
+	    = 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);
+	  c_name = "to";
+	  break;
+	case PRAGMA_OMP_CLAUSE_FROM:
+	  clauses = c_parser_omp_clause_from (parser, clauses);
+	  c_name = "from";
+	  break;
+	case PRAGMA_OMP_CLAUSE_UNIFORM:
+	  clauses = c_parser_omp_clause_uniform (parser, clauses);
+	  c_name = "uniform";
+	  break;
+	case PRAGMA_OMP_CLAUSE_NUM_TEAMS:
+	  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);
+	  c_name = "aligned";
+	  break;
+	case PRAGMA_OMP_CLAUSE_LINEAR:
+	  clauses = c_parser_omp_clause_linear (parser, clauses);
+	  c_name = "linear";
+	  break;
+	case PRAGMA_OMP_CLAUSE_DEPEND:
+	  clauses = c_parser_omp_clause_depend (parser, clauses);
+	  c_name = "depend";
+	  break;
+	case PRAGMA_OMP_CLAUSE_MAP:
+	  clauses = c_parser_omp_clause_map (parser, clauses);
+	  c_name = "map";
+	  break;
+	case PRAGMA_OMP_CLAUSE_DEVICE:
+	  clauses = c_parser_omp_clause_device (parser, clauses);
+	  c_name = "device";
+	  break;
+	case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE:
+	  clauses = c_parser_omp_clause_dist_schedule (parser, clauses);
+	  c_name = "dist_schedule";
+	  break;
+	case PRAGMA_OMP_CLAUSE_PROC_BIND:
+	  clauses = c_parser_omp_clause_proc_bind (parser, clauses);
+	  c_name = "proc_bind";
+	  break;
+	case PRAGMA_OMP_CLAUSE_SAFELEN:
+	  clauses = c_parser_omp_clause_safelen (parser, clauses);
+	  c_name = "safelen";
+	  break;
+	case PRAGMA_OMP_CLAUSE_SIMDLEN:
+	  clauses = c_parser_omp_clause_simdlen (parser, clauses);
+	  c_name = "simdlen";
+	  break;
+	default:
+	  c_parser_error (parser, "expected %<#pragma omp%> clause");
+	  goto saw_error;
+	}
+
+      first = false;
+
+      if (((mask >> c_kind) & 1) == 0 && !parser->error)
+	{
+	  /* Remove the invalid clause(s) from the list to avoid
+	     confusing the rest of the compiler.  */
+	  clauses = prev;
+	  error_at (here, "%qs is not valid for %qs", c_name, where);
+	}
+    }
+
+ saw_error:
+  c_parser_skip_to_pragma_eol (parser);
+
+  if (finish_p)
+    return c_finish_omp_clauses (clauses);
+
+  return clauses;
+}
+
+/* OpenMP 2.5:
+   structured-block:
+     statement
+
+   In practice, we're also interested in adding the statement to an
+   outer node.  So it is convenient if we work around the fact that
+   c_parser_statement calls add_stmt.  */
+
+static tree
+c_parser_omp_structured_block (c_parser *parser)
+{
+  tree stmt = push_stmt_list ();
+  c_parser_statement (parser);
+  return pop_stmt_list (stmt);
+}
+
+/* OpenMP 2.5:
+   # pragma omp atomic new-line
+     expression-stmt
+
+   expression-stmt:
+     x binop= expr | x++ | ++x | x-- | --x
+   binop:
+     +, *, -, /, &, ^, |, <<, >>
+
+  where x is an lvalue expression with scalar type.
+
+   OpenMP 3.1:
+   # pragma omp atomic new-line
+     update-stmt
+
+   # pragma omp atomic read new-line
+     read-stmt
+
+   # pragma omp atomic write new-line
+     write-stmt
+
+   # pragma omp atomic update new-line
+     update-stmt
+
+   # pragma omp atomic capture new-line
+     capture-stmt
+
+   # pragma omp atomic capture new-line
+     capture-block
+
+   read-stmt:
+     v = x
+   write-stmt:
+     x = expr
+   update-stmt:
+     expression-stmt | x = x binop expr
+   capture-stmt:
+     v = expression-stmt
+   capture-block:
+     { v = x; update-stmt; } | { update-stmt; v = x; }
+
+   OpenMP 4.0:
+   update-stmt:
+     expression-stmt | x = x binop expr | x = expr binop x
+   capture-stmt:
+     v = update-stmt
+   capture-block:
+     { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; }
+
+  where x and v are lvalue expressions with scalar type.
+
+  LOC is the location of the #pragma token.  */
+
+static void
+c_parser_omp_atomic (location_t loc, c_parser *parser)
+{
+  tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE;
+  tree lhs1 = NULL_TREE, rhs1 = NULL_TREE;
+  tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE;
+  enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR;
+  struct c_expr expr;
+  location_t eloc;
+  bool structured_block = false;
+  bool swapped = false;
+  bool seq_cst = false;
+
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+      if (!strcmp (p, "read"))
+	code = OMP_ATOMIC_READ;
+      else if (!strcmp (p, "write"))
+	code = NOP_EXPR;
+      else if (!strcmp (p, "update"))
+	code = OMP_ATOMIC;
+      else if (!strcmp (p, "capture"))
+	code = OMP_ATOMIC_CAPTURE_NEW;
+      else
+	p = NULL;
+      if (p)
+	c_parser_consume_token (parser);
+    }
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (!strcmp (p, "seq_cst"))
+	{
+	  seq_cst = true;
+	  c_parser_consume_token (parser);
+	}
+    }
+  c_parser_skip_to_pragma_eol (parser);
+
+  switch (code)
+    {
+    case OMP_ATOMIC_READ:
+    case NOP_EXPR: /* atomic write */
+      v = c_parser_unary_expression (parser).value;
+      v = c_fully_fold (v, false, NULL);
+      if (v == error_mark_node)
+	goto saw_error;
+      loc = c_parser_peek_token (parser)->location;
+      if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+	goto saw_error;
+      if (code == NOP_EXPR)
+	lhs = c_parser_expression (parser).value;
+      else
+	lhs = c_parser_unary_expression (parser).value;
+      lhs = c_fully_fold (lhs, false, NULL);
+      if (lhs == error_mark_node)
+	goto saw_error;
+      if (code == NOP_EXPR)
+	{
+	  /* atomic write is represented by OMP_ATOMIC with NOP_EXPR
+	     opcode.  */
+	  code = OMP_ATOMIC;
+	  rhs = lhs;
+	  lhs = v;
+	  v = NULL_TREE;
+	}
+      goto done;
+    case OMP_ATOMIC_CAPTURE_NEW:
+      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+	{
+	  c_parser_consume_token (parser);
+	  structured_block = true;
+	}
+      else
+	{
+	  v = c_parser_unary_expression (parser).value;
+	  v = c_fully_fold (v, false, NULL);
+	  if (v == error_mark_node)
+	    goto saw_error;
+	  if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+	    goto saw_error;
+	}
+      break;
+    default:
+      break;
+    }
+
+  /* For structured_block case we don't know yet whether
+     old or new x should be captured.  */
+restart:
+  eloc = c_parser_peek_token (parser)->location;
+  expr = c_parser_unary_expression (parser);
+  lhs = expr.value;
+  expr = default_function_array_conversion (eloc, expr);
+  unfolded_lhs = expr.value;
+  lhs = c_fully_fold (lhs, false, NULL);
+  orig_lhs = lhs;
+  switch (TREE_CODE (lhs))
+    {
+    case ERROR_MARK:
+    saw_error:
+      c_parser_skip_to_end_of_block_or_statement (parser);
+      if (structured_block)
+	{
+	  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+	    c_parser_consume_token (parser);
+	  else if (code == OMP_ATOMIC_CAPTURE_NEW)
+	    {
+	      c_parser_skip_to_end_of_block_or_statement (parser);
+	      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+		c_parser_consume_token (parser);
+	    }
+	}
+      return;
+
+    case POSTINCREMENT_EXPR:
+      if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+	code = OMP_ATOMIC_CAPTURE_OLD;
+      /* FALLTHROUGH */
+    case PREINCREMENT_EXPR:
+      lhs = TREE_OPERAND (lhs, 0);
+      unfolded_lhs = NULL_TREE;
+      opcode = PLUS_EXPR;
+      rhs = integer_one_node;
+      break;
+
+    case POSTDECREMENT_EXPR:
+      if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+	code = OMP_ATOMIC_CAPTURE_OLD;
+      /* FALLTHROUGH */
+    case PREDECREMENT_EXPR:
+      lhs = TREE_OPERAND (lhs, 0);
+      unfolded_lhs = NULL_TREE;
+      opcode = MINUS_EXPR;
+      rhs = integer_one_node;
+      break;
+
+    case COMPOUND_EXPR:
+      if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR
+	  && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR
+	  && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR
+	  && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0)
+	  && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND
+					      (TREE_OPERAND (lhs, 1), 0), 0)))
+	     == BOOLEAN_TYPE)
+	/* Undo effects of boolean_increment for post {in,de}crement.  */
+	lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0);
+      /* FALLTHRU */
+    case MODIFY_EXPR:
+      if (TREE_CODE (lhs) == MODIFY_EXPR
+	  && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE)
+	{
+	  /* Undo effects of boolean_increment.  */
+	  if (integer_onep (TREE_OPERAND (lhs, 1)))
+	    {
+	      /* This is pre or post increment.  */
+	      rhs = TREE_OPERAND (lhs, 1);
+	      lhs = TREE_OPERAND (lhs, 0);
+	      unfolded_lhs = NULL_TREE;
+	      opcode = NOP_EXPR;
+	      if (code == OMP_ATOMIC_CAPTURE_NEW
+		  && !structured_block
+		  && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+		code = OMP_ATOMIC_CAPTURE_OLD;
+	      break;
+	    }
+	  if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR
+	      && TREE_OPERAND (lhs, 0)
+		 == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0))
+	    {
+	      /* This is pre or post decrement.  */
+	      rhs = TREE_OPERAND (lhs, 1);
+	      lhs = TREE_OPERAND (lhs, 0);
+	      unfolded_lhs = NULL_TREE;
+	      opcode = NOP_EXPR;
+	      if (code == OMP_ATOMIC_CAPTURE_NEW
+		  && !structured_block
+		  && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+		code = OMP_ATOMIC_CAPTURE_OLD;
+	      break;
+	    }
+	}
+      /* FALLTHRU */
+    default:
+      switch (c_parser_peek_token (parser)->type)
+	{
+	case CPP_MULT_EQ:
+	  opcode = MULT_EXPR;
+	  break;
+	case CPP_DIV_EQ:
+	  opcode = TRUNC_DIV_EXPR;
+	  break;
+	case CPP_PLUS_EQ:
+	  opcode = PLUS_EXPR;
+	  break;
+	case CPP_MINUS_EQ:
+	  opcode = MINUS_EXPR;
+	  break;
+	case CPP_LSHIFT_EQ:
+	  opcode = LSHIFT_EXPR;
+	  break;
+	case CPP_RSHIFT_EQ:
+	  opcode = RSHIFT_EXPR;
+	  break;
+	case CPP_AND_EQ:
+	  opcode = BIT_AND_EXPR;
+	  break;
+	case CPP_OR_EQ:
+	  opcode = BIT_IOR_EXPR;
+	  break;
+	case CPP_XOR_EQ:
+	  opcode = BIT_XOR_EXPR;
+	  break;
+	case CPP_EQ:
+	  c_parser_consume_token (parser);
+	  eloc = c_parser_peek_token (parser)->location;
+	  expr = c_parser_expr_no_commas (parser, NULL, unfolded_lhs);
+	  rhs1 = expr.value;
+	  switch (TREE_CODE (rhs1))
+	    {
+	    case MULT_EXPR:
+	    case TRUNC_DIV_EXPR:
+	    case PLUS_EXPR:
+	    case MINUS_EXPR:
+	    case LSHIFT_EXPR:
+	    case RSHIFT_EXPR:
+	    case BIT_AND_EXPR:
+	    case BIT_IOR_EXPR:
+	    case BIT_XOR_EXPR:
+	      if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs))
+		{
+		  opcode = TREE_CODE (rhs1);
+		  rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL);
+		  rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL);
+		  goto stmt_done;
+		}
+	      if (c_tree_equal (TREE_OPERAND (rhs1, 1), unfolded_lhs))
+		{
+		  opcode = TREE_CODE (rhs1);
+		  rhs = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL);
+		  rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL);
+		  swapped = !commutative_tree_code (opcode);
+		  goto stmt_done;
+		}
+	      break;
+	    case ERROR_MARK:
+	      goto saw_error;
+	    default:
+	      break;
+	    }
+	  if (c_parser_peek_token (parser)->type == CPP_SEMICOLON)
+	    {
+	      if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+		{
+		  code = OMP_ATOMIC_CAPTURE_OLD;
+		  v = lhs;
+		  lhs = NULL_TREE;
+		  expr = default_function_array_read_conversion (eloc, expr);
+		  unfolded_lhs1 = expr.value;
+		  lhs1 = c_fully_fold (unfolded_lhs1, false, NULL);
+		  rhs1 = NULL_TREE;
+		  c_parser_consume_token (parser);
+		  goto restart;
+		}
+	      if (structured_block)
+		{
+		  opcode = NOP_EXPR;
+		  expr = default_function_array_read_conversion (eloc, expr);
+		  rhs = c_fully_fold (expr.value, false, NULL);
+		  rhs1 = NULL_TREE;
+		  goto stmt_done;
+		}
+	    }
+	  c_parser_error (parser, "invalid form of %<#pragma omp atomic%>");
+	  goto saw_error;
+	default:
+	  c_parser_error (parser,
+			  "invalid operator for %<#pragma omp atomic%>");
+	  goto saw_error;
+	}
+
+      /* Arrange to pass the location of the assignment operator to
+	 c_finish_omp_atomic.  */
+      loc = c_parser_peek_token (parser)->location;
+      c_parser_consume_token (parser);
+      eloc = c_parser_peek_token (parser)->location;
+      expr = c_parser_expression (parser);
+      expr = default_function_array_read_conversion (eloc, expr);
+      rhs = expr.value;
+      rhs = c_fully_fold (rhs, false, NULL);
+      break;
+    }
+stmt_done:
+  if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+    {
+      if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+	goto saw_error;
+      v = c_parser_unary_expression (parser).value;
+      v = c_fully_fold (v, false, NULL);
+      if (v == error_mark_node)
+	goto saw_error;
+      if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+	goto saw_error;
+      eloc = c_parser_peek_token (parser)->location;
+      expr = c_parser_unary_expression (parser);
+      lhs1 = expr.value;
+      expr = default_function_array_read_conversion (eloc, expr);
+      unfolded_lhs1 = expr.value;
+      lhs1 = c_fully_fold (lhs1, false, NULL);
+      if (lhs1 == error_mark_node)
+	goto saw_error;
+    }
+  if (structured_block)
+    {
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+      c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+    }
+done:
+  if (unfolded_lhs && unfolded_lhs1
+      && !c_tree_equal (unfolded_lhs, unfolded_lhs1))
+    {
+      error ("%<#pragma omp atomic capture%> uses two different "
+	     "expressions for memory");
+      stmt = error_mark_node;
+    }
+  else
+    stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1,
+				swapped, seq_cst);
+  if (stmt != error_mark_node)
+    add_stmt (stmt);
+
+  if (!structured_block)
+    c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+}
+
+
+/* OpenMP 2.5:
+   # pragma omp barrier new-line
+*/
+
+static void
+c_parser_omp_barrier (c_parser *parser)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_pragma (parser);
+  c_parser_skip_to_pragma_eol (parser);
+
+  c_finish_omp_barrier (loc);
+}
+
+/* OpenMP 2.5:
+   # pragma omp critical [(name)] new-line
+     structured-block
+
+  LOC is the location of the #pragma itself.  */
+
+static tree
+c_parser_omp_critical (location_t loc, c_parser *parser)
+{
+  tree stmt, name = NULL;
+
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_NAME))
+	{
+	  name = c_parser_peek_token (parser)->value;
+	  c_parser_consume_token (parser);
+	  c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+	}
+      else
+	c_parser_error (parser, "expected identifier");
+    }
+  else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+    c_parser_error (parser, "expected %<(%> or end of line");
+  c_parser_skip_to_pragma_eol (parser);
+
+  stmt = c_parser_omp_structured_block (parser);
+  return c_finish_omp_critical (loc, stmt, name);
+}
+
+/* OpenMP 2.5:
+   # pragma omp flush flush-vars[opt] new-line
+
+   flush-vars:
+     ( variable-list ) */
+
+static void
+c_parser_omp_flush (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_OPEN_PAREN))
+    c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
+  else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+    c_parser_error (parser, "expected %<(%> or end of line");
+  c_parser_skip_to_pragma_eol (parser);
+
+  c_finish_omp_flush (loc);
+}
+
+/* Parse the restricted form of the for statement allowed by OpenMP.
+   The real trick here is to determine the loop control variable early
+   so that we can push a new decl if necessary to make it private.
+   LOC is the location of the OMP in "#pragma omp".  */
+
+static tree
+c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
+		       tree clauses, tree *cclauses)
+{
+  tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
+  tree declv, condv, incrv, initv, ret = NULL;
+  bool fail = false, open_brace_parsed = false;
+  int i, collapse = 1, nbraces = 0;
+  location_t for_loc;
+  vec<tree, va_gc> *for_block = make_tree_vector ();
+
+  for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
+    if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
+      collapse = tree_low_cst (OMP_CLAUSE_COLLAPSE_EXPR (cl), 0);
+
+  gcc_assert (collapse >= 1);
+
+  declv = make_tree_vec (collapse);
+  initv = make_tree_vec (collapse);
+  condv = make_tree_vec (collapse);
+  incrv = make_tree_vec (collapse);
+
+  if (!c_parser_next_token_is_keyword (parser, RID_FOR))
+    {
+      c_parser_error (parser, "for statement expected");
+      return NULL;
+    }
+  for_loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_token (parser);
+
+  for (i = 0; i < collapse; i++)
+    {
+      int bracecount = 0;
+
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+	goto pop_scopes;
 
       /* Parse the initialization declaration or expression.  */
       if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  if (i > 0)
 	    vec_safe_push (for_block, c_begin_compound_stmt (true));
-	  c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL);
+	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
+					 NULL, vNULL);
 	  decl = check_for_loop_decls (for_loc, flag_isoc99);
 	  if (decl == NULL)
 	    goto error_init;
@@ -10310,574 +11197,1639 @@  c_parser_omp_for_loop (location_t loc,
 
 	  c_parser_require (parser, CPP_EQ, "expected %<=%>");
 
-	  init_loc = c_parser_peek_token (parser)->location;
-	  init_exp = c_parser_expr_no_commas (parser, NULL);
-	  init_exp = default_function_array_read_conversion (init_loc,
-							     init_exp);
-	  init = build_modify_expr (init_loc, decl, decl_exp.original_type,
-				    NOP_EXPR, init_loc, init_exp.value,
-				    init_exp.original_type);
-	  init = c_process_expr_stmt (init_loc, init);
+	  init_loc = c_parser_peek_token (parser)->location;
+	  init_exp = c_parser_expr_no_commas (parser, NULL);
+	  init_exp = default_function_array_read_conversion (init_loc,
+							     init_exp);
+	  init = build_modify_expr (init_loc, decl, decl_exp.original_type,
+				    NOP_EXPR, init_loc, init_exp.value,
+				    init_exp.original_type);
+	  init = c_process_expr_stmt (init_loc, init);
+
+	  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+	}
+      else
+	{
+	error_init:
+	  c_parser_error (parser,
+			  "expected iteration declaration or initialization");
+	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				     "expected %<)%>");
+	  fail = true;
+	  goto parse_next;
+	}
+
+      /* Parse the loop condition.  */
+      cond = NULL_TREE;
+      if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+	{
+	  location_t cond_loc = c_parser_peek_token (parser)->location;
+	  struct c_expr cond_expr
+	    = c_parser_binary_expression (parser, NULL, NULL_TREE);
+
+	  cond = cond_expr.value;
+	  cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
+	  cond = c_fully_fold (cond, false, NULL);
+	  switch (cond_expr.original_code)
+	    {
+	    case GT_EXPR:
+	    case GE_EXPR:
+	    case LT_EXPR:
+	    case LE_EXPR:
+	      break;
+	    default:
+	      /* Can't be cond = error_mark_node, because we want to preserve
+		 the location until c_finish_omp_for.  */
+	      cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node);
+	      break;
+	    }
+	  protected_set_expr_location (cond, cond_loc);
+	}
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+
+      /* Parse the increment expression.  */
+      incr = NULL_TREE;
+      if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+	{
+	  location_t incr_loc = c_parser_peek_token (parser)->location;
+
+	  incr = c_process_expr_stmt (incr_loc,
+				      c_parser_expression (parser).value);
+	}
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+      if (decl == NULL || decl == error_mark_node || init == error_mark_node)
+	fail = true;
+      else
+	{
+	  TREE_VEC_ELT (declv, i) = decl;
+	  TREE_VEC_ELT (initv, i) = init;
+	  TREE_VEC_ELT (condv, i) = cond;
+	  TREE_VEC_ELT (incrv, i) = incr;
+	}
+
+    parse_next:
+      if (i == collapse - 1)
+	break;
+
+      /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed
+	 in between the collapsed for loops to be still considered perfectly
+	 nested.  Hopefully the final version clarifies this.
+	 For now handle (multiple) {'s and empty statements.  */
+      do
+	{
+	  if (c_parser_next_token_is_keyword (parser, RID_FOR))
+	    {
+	      c_parser_consume_token (parser);
+	      break;
+	    }
+	  else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+	    {
+	      c_parser_consume_token (parser);
+	      bracecount++;
+	    }
+	  else if (bracecount
+		   && c_parser_next_token_is (parser, CPP_SEMICOLON))
+	    c_parser_consume_token (parser);
+	  else
+	    {
+	      c_parser_error (parser, "not enough perfectly nested loops");
+	      if (bracecount)
+		{
+		  open_brace_parsed = true;
+		  bracecount--;
+		}
+	      fail = true;
+	      collapse = 0;
+	      break;
+	    }
+	}
+      while (1);
+
+      nbraces += bracecount;
+    }
+
+  save_break = c_break_label;
+  c_break_label = size_one_node;
+  save_cont = c_cont_label;
+  c_cont_label = NULL_TREE;
+  body = push_stmt_list ();
+
+  if (open_brace_parsed)
+    {
+      location_t here = c_parser_peek_token (parser)->location;
+      stmt = c_begin_compound_stmt (true);
+      c_parser_compound_statement_nostart (parser);
+      add_stmt (c_end_compound_stmt (here, stmt, true));
+    }
+  else
+    add_stmt (c_parser_c99_block_statement (parser));
+  if (c_cont_label)
+    {
+      tree t = build1 (LABEL_EXPR, void_type_node, c_cont_label);
+      SET_EXPR_LOCATION (t, loc);
+      add_stmt (t);
+    }
+
+  body = pop_stmt_list (body);
+  c_break_label = save_break;
+  c_cont_label = save_cont;
 
-	  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+  while (nbraces)
+    {
+      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+	{
+	  c_parser_consume_token (parser);
+	  nbraces--;
 	}
+      else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+	c_parser_consume_token (parser);
       else
 	{
-	error_init:
-	  c_parser_error (parser,
-			  "expected iteration declaration or initialization");
-	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
-				     "expected %<)%>");
-	  fail = true;
-	  goto parse_next;
+	  c_parser_error (parser, "collapsed loops not perfectly nested");
+	  while (nbraces)
+	    {
+	      location_t here = c_parser_peek_token (parser)->location;
+	      stmt = c_begin_compound_stmt (true);
+	      add_stmt (body);
+	      c_parser_compound_statement_nostart (parser);
+	      body = c_end_compound_stmt (here, stmt, true);
+	      nbraces--;
+	    }
+	  goto pop_scopes;
 	}
+    }
 
-      /* Parse the loop condition.  */
-      cond = NULL_TREE;
-      if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+  /* Only bother calling c_finish_omp_for if we haven't already generated
+     an error from the initialization parsing.  */
+  if (!fail)
+    {
+      stmt = c_finish_omp_for (loc, code, declv, initv, condv,
+			       incrv, body, NULL);
+      if (stmt)
 	{
-	  location_t cond_loc = c_parser_peek_token (parser)->location;
-	  struct c_expr cond_expr = c_parser_binary_expression (parser, NULL,
-								PREC_NONE);
-
-	  cond = cond_expr.value;
-	  cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
-	  cond = c_fully_fold (cond, false, NULL);
-	  switch (cond_expr.original_code)
+	  if (cclauses != NULL
+	      && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL)
 	    {
-	    case GT_EXPR:
-	    case GE_EXPR:
-	    case LT_EXPR:
-	    case LE_EXPR:
-	      break;
-	    default:
-	      /* Can't be cond = error_mark_node, because we want to preserve
-		 the location until c_finish_omp_for.  */
-	      cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node);
-	      break;
+	      tree *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);
+		else
+		  {
+		    for (i = 0; i < collapse; i++)
+		      if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c))
+			break;
+		    if (i == collapse)
+		      c = &OMP_CLAUSE_CHAIN (*c);
+		    else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE)
+		      {
+			error_at (loc,
+				  "iteration variable %qD should not be firstprivate",
+				  OMP_CLAUSE_DECL (*c));
+			*c = OMP_CLAUSE_CHAIN (*c);
+		      }
+		    else
+		      {
+			/* Copy lastprivate (decl) clause to OMP_FOR_CLAUSES,
+			   change it to shared (decl) in
+			   OMP_PARALLEL_CLAUSES.  */
+			tree l = build_omp_clause (OMP_CLAUSE_LOCATION (*c),
+						   OMP_CLAUSE_LASTPRIVATE);
+			OMP_CLAUSE_DECL (l) = OMP_CLAUSE_DECL (*c);
+			OMP_CLAUSE_CHAIN (l) = clauses;
+			clauses = l;
+			OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED);
+		      }
+		  }
 	    }
-	  protected_set_expr_location (cond, cond_loc);
+	  OMP_FOR_CLAUSES (stmt) = clauses;
 	}
-      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+      ret = stmt;
+    }
+pop_scopes:
+  while (!for_block->is_empty ())
+    {
+      /* FIXME diagnostics: LOC below should be the actual location of
+	 this particular for block.  We need to build a list of
+	 locations to go along with FOR_BLOCK.  */
+      stmt = c_end_compound_stmt (loc, for_block->pop (), true);
+      add_stmt (stmt);
+    }
+  release_tree_vector (for_block);
+  return ret;
+}
 
-      /* Parse the increment expression.  */
-      incr = NULL_TREE;
-      if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+/* 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
+
+   LOC is the location of the #pragma token.
+*/
+
+#define OMP_SIMD_CLAUSE_MASK					\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE))
+
+static tree
+c_parser_omp_simd (location_t loc, c_parser *parser,
+		   char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+  tree block, clauses, ret;
+
+  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, cclauses);
+  block = c_end_compound_stmt (loc, block, true);
+  add_stmt (block);
+
+  return ret;
+}
+
+/* OpenMP 2.5:
+   #pragma omp for for-clause[optseq] new-line
+     for-loop
+
+   OpenMP 4.0:
+   #pragma omp for simd for-simd-clause[optseq] new-line
+     for-loop
+
+   LOC is the location of the #pragma token.
+*/
+
+#define OMP_FOR_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_LASTPRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_for (location_t loc, c_parser *parser,
+		  char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+  tree block, clauses, ret;
+
+  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))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+      if (strcmp (p, "simd") == 0)
 	{
-	  location_t incr_loc = c_parser_peek_token (parser)->location;
+	  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, 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, OMP_FOR, clauses, cclauses);
+  block = c_end_compound_stmt (loc, block, true);
+  add_stmt (block);
+
+  return ret;
+}
+
+/* OpenMP 2.5:
+   # pragma omp master new-line
+     structured-block
+
+   LOC is the location of the #pragma token.
+*/
+
+static tree
+c_parser_omp_master (location_t loc, c_parser *parser)
+{
+  c_parser_skip_to_pragma_eol (parser);
+  return c_finish_omp_master (loc, c_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 2.5:
+   # pragma omp ordered new-line
+     structured-block
+
+   LOC is the location of the #pragma itself.
+*/
+
+static tree
+c_parser_omp_ordered (location_t loc, c_parser *parser)
+{
+  c_parser_skip_to_pragma_eol (parser);
+  return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 2.5:
+
+   section-scope:
+     { section-sequence }
+
+   section-sequence:
+     section-directive[opt] structured-block
+     section-sequence section-directive structured-block
+
+    SECTIONS_LOC is the location of the #pragma omp sections.  */
+
+static tree
+c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser)
+{
+  tree stmt, substmt;
+  bool error_suppress = false;
+  location_t loc;
+
+  loc = c_parser_peek_token (parser)->location;
+  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+    {
+      /* Avoid skipping until the end of the block.  */
+      parser->error = false;
+      return NULL_TREE;
+    }
+
+  stmt = push_stmt_list ();
+
+  if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION)
+    {
+      substmt = c_parser_omp_structured_block (parser);
+      substmt = build1 (OMP_SECTION, void_type_node, substmt);
+      SET_EXPR_LOCATION (substmt, loc);
+      add_stmt (substmt);
+    }
+
+  while (1)
+    {
+      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+	break;
+      if (c_parser_next_token_is (parser, CPP_EOF))
+	break;
 
-	  incr = c_process_expr_stmt (incr_loc,
-				      c_parser_expression (parser).value);
+      loc = c_parser_peek_token (parser)->location;
+      if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
+	{
+	  c_parser_consume_pragma (parser);
+	  c_parser_skip_to_pragma_eol (parser);
+	  error_suppress = false;
 	}
-      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
-
-      if (decl == NULL || decl == error_mark_node || init == error_mark_node)
-	fail = true;
-      else
+      else if (!error_suppress)
 	{
-	  TREE_VEC_ELT (declv, i) = decl;
-	  TREE_VEC_ELT (initv, i) = init;
-	  TREE_VEC_ELT (condv, i) = cond;
-	  TREE_VEC_ELT (incrv, i) = incr;
+	  error_at (loc, "expected %<#pragma omp section%> or %<}%>");
+	  error_suppress = true;
 	}
 
-    parse_next:
-      if (i == collapse - 1)
-	break;
+      substmt = c_parser_omp_structured_block (parser);
+      substmt = build1 (OMP_SECTION, void_type_node, substmt);
+      SET_EXPR_LOCATION (substmt, loc);
+      add_stmt (substmt);
+    }
+  c_parser_skip_until_found (parser, CPP_CLOSE_BRACE,
+			     "expected %<#pragma omp section%> or %<}%>");
 
-      /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed
-	 in between the collapsed for loops to be still considered perfectly
-	 nested.  Hopefully the final version clarifies this.
-	 For now handle (multiple) {'s and empty statements.  */
-      do
-	{
-	  if (c_parser_next_token_is_keyword (parser, RID_FOR))
-	    {
-	      c_parser_consume_token (parser);
-	      break;
-	    }
-	  else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
-	    {
-	      c_parser_consume_token (parser);
-	      bracecount++;
-	    }
-	  else if (bracecount
-		   && c_parser_next_token_is (parser, CPP_SEMICOLON))
-	    c_parser_consume_token (parser);
-	  else
-	    {
-	      c_parser_error (parser, "not enough perfectly nested loops");
-	      if (bracecount)
-		{
-		  open_brace_parsed = true;
-		  bracecount--;
-		}
-	      fail = true;
-	      collapse = 0;
-	      break;
-	    }
-	}
-      while (1);
+  substmt = pop_stmt_list (stmt);
 
-      nbraces += bracecount;
+  stmt = make_node (OMP_SECTIONS);
+  SET_EXPR_LOCATION (stmt, sections_loc);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_SECTIONS_BODY (stmt) = substmt;
+
+  return add_stmt (stmt);
+}
+
+/* OpenMP 2.5:
+   # pragma omp sections sections-clause[optseq] newline
+     sections-scope
+
+   LOC is the location of the #pragma token.
+*/
+
+#define OMP_SECTIONS_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_LASTPRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_sections (location_t loc, c_parser *parser,
+		       char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+  tree block, clauses, ret;
+
+  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];
     }
 
-  save_break = c_break_label;
-  c_break_label = size_one_node;
-  save_cont = c_cont_label;
-  c_cont_label = NULL_TREE;
-  body = push_stmt_list ();
+  block = c_begin_compound_stmt (true);
+  ret = c_parser_omp_sections_scope (loc, parser);
+  if (ret)
+    OMP_SECTIONS_CLAUSES (ret) = clauses;
+  block = c_end_compound_stmt (loc, block, true);
+  add_stmt (block);
 
-  if (open_brace_parsed)
+  return ret;
+}
+
+/* OpenMP 2.5:
+   # pragma parallel parallel-clause new-line
+   # pragma parallel for parallel-for-clause new-line
+   # pragma parallel sections parallel-sections-clause new-line
+
+   LOC is the location of the #pragma token.
+*/
+
+#define OMP_PARALLEL_CLAUSE_MASK				\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND))
+
+static tree
+c_parser_omp_parallel (location_t loc, c_parser *parser,
+		       char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+  tree stmt, clauses, block;
+
+  strcat (p_name, " parallel");
+  mask |= OMP_PARALLEL_CLAUSE_MASK;
+
+  if (c_parser_next_token_is_keyword (parser, RID_FOR))
     {
-      location_t here = c_parser_peek_token (parser)->location;
-      stmt = c_begin_compound_stmt (true);
-      c_parser_compound_statement_nostart (parser);
-      add_stmt (c_end_compound_stmt (here, stmt, true));
+      tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+      if (cclauses == NULL)
+	cclauses = cclauses_buf;
+
+      c_parser_consume_token (parser);
+      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
-    add_stmt (c_parser_c99_block_statement (parser));
-  if (c_cont_label)
+  else if (cclauses)
     {
-      tree t = build1 (LABEL_EXPR, void_type_node, c_cont_label);
-      SET_EXPR_LOCATION (t, loc);
-      add_stmt (t);
+      error_at (loc, "expected %<for%> after %qs", p_name);
+      c_parser_skip_to_pragma_eol (parser);
+      return NULL_TREE;
     }
-
-  body = pop_stmt_list (body);
-  c_break_label = save_break;
-  c_cont_label = save_cont;
-
-  while (nbraces)
+  else if (c_parser_next_token_is (parser, CPP_NAME))
     {
-      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+      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);
-	  nbraces--;
-	}
-      else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
-	c_parser_consume_token (parser);
-      else
-	{
-	  c_parser_error (parser, "collapsed loops not perfectly nested");
-	  while (nbraces)
-	    {
-	      location_t here = c_parser_peek_token (parser)->location;
-	      stmt = c_begin_compound_stmt (true);
-	      add_stmt (body);
-	      c_parser_compound_statement_nostart (parser);
-	      body = c_end_compound_stmt (here, stmt, true);
-	      nbraces--;
-	    }
-	  goto pop_scopes;
+	  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;
 	}
     }
 
-  /* Only bother calling c_finish_omp_for if we haven't already generated
-     an error from the initialization parsing.  */
-  if (!fail)
+  clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+
+  block = c_begin_omp_parallel ();
+  c_parser_statement (parser);
+  stmt = c_finish_omp_parallel (loc, clauses, block);
+
+  return stmt;
+}
+
+/* OpenMP 2.5:
+   # pragma omp single single-clause[optseq] new-line
+     structured-block
+
+   LOC is the location of the #pragma.
+*/
+
+#define OMP_SINGLE_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_COPYPRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_single (location_t loc, c_parser *parser)
+{
+  tree stmt = make_node (OMP_SINGLE);
+  SET_EXPR_LOCATION (stmt, loc);
+  TREE_TYPE (stmt) = void_type_node;
+
+  OMP_SINGLE_CLAUSES (stmt)
+    = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK,
+				"#pragma omp single");
+  OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser);
+
+  return add_stmt (stmt);
+}
+
+/* OpenMP 3.0:
+   # pragma omp task task-clause[optseq] new-line
+
+   LOC is the location of the #pragma.
+*/
+
+#define OMP_TASK_CLAUSE_MASK					\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)	\
+	| (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_FINAL)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND))
+
+static tree
+c_parser_omp_task (location_t loc, c_parser *parser)
+{
+  tree clauses, block;
+
+  clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK,
+				      "#pragma omp task");
+
+  block = c_begin_omp_task ();
+  c_parser_statement (parser);
+  return c_finish_omp_task (loc, clauses, block);
+}
+
+/* OpenMP 3.0:
+   # pragma omp taskwait new-line
+*/
+
+static void
+c_parser_omp_taskwait (c_parser *parser)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_pragma (parser);
+  c_parser_skip_to_pragma_eol (parser);
+
+  c_finish_omp_taskwait (loc);
+}
+
+/* OpenMP 3.1:
+   # pragma omp taskyield new-line
+*/
+
+static void
+c_parser_omp_taskyield (c_parser *parser)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_pragma (parser);
+  c_parser_skip_to_pragma_eol (parser);
+
+  c_finish_omp_taskyield (loc);
+}
+
+/* OpenMP 4.0:
+   # pragma omp taskgroup new-line
+*/
+
+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);
+  return c_finish_omp_taskgroup (loc, c_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 4.0:
+   # pragma omp cancel cancel-clause[optseq] new-line
+
+   LOC is the location of the #pragma.
+*/
+
+#define OMP_CANCEL_CLAUSE_MASK					\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static void
+c_parser_omp_cancel (c_parser *parser)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+
+  c_parser_consume_pragma (parser);
+  tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK,
+					   "#pragma omp cancel");
+
+  c_finish_omp_cancel (loc, clauses);
+}
+
+/* OpenMP 4.0:
+   # pragma omp cancellation point cancelpt-clause[optseq] new-line
+
+   LOC is the location of the #pragma.
+*/
+
+#define OMP_CANCELLATION_POINT_CLAUSE_MASK			\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP))
+
+static void
+c_parser_omp_cancellation_point (c_parser *parser)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  tree clauses;
+  bool point_seen = false;
+
+  c_parser_consume_pragma (parser);
+  if (c_parser_next_token_is (parser, CPP_NAME))
     {
-      stmt = c_finish_omp_for (loc, declv, initv, condv, incrv, body, NULL);
-      if (stmt)
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (strcmp (p, "point") == 0)
 	{
-	  if (par_clauses != NULL)
-	    {
-	      tree *c;
-	      for (c = par_clauses; *c ; )
-		if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE
-		    && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE)
-		  c = &OMP_CLAUSE_CHAIN (*c);
-		else
-		  {
-		    for (i = 0; i < collapse; i++)
-		      if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c))
-			break;
-		    if (i == collapse)
-		      c = &OMP_CLAUSE_CHAIN (*c);
-		    else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE)
-		      {
-			error_at (loc,
-				  "iteration variable %qD should not be firstprivate",
-				  OMP_CLAUSE_DECL (*c));
-			*c = OMP_CLAUSE_CHAIN (*c);
-		      }
-		    else
-		      {
-			/* Copy lastprivate (decl) clause to OMP_FOR_CLAUSES,
-			   change it to shared (decl) in
-			   OMP_PARALLEL_CLAUSES.  */
-			tree l = build_omp_clause (OMP_CLAUSE_LOCATION (*c),
-						   OMP_CLAUSE_LASTPRIVATE);
-			OMP_CLAUSE_DECL (l) = OMP_CLAUSE_DECL (*c);
-			OMP_CLAUSE_CHAIN (l) = clauses;
-			clauses = l;
-			OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED);
-		      }
-		  }
-	    }
-	  OMP_FOR_CLAUSES (stmt) = clauses;
+	  c_parser_consume_token (parser);
+	  point_seen = true;
 	}
-      ret = stmt;
     }
-pop_scopes:
-  while (!for_block->is_empty ())
+  if (!point_seen)
     {
-      /* FIXME diagnostics: LOC below should be the actual location of
-	 this particular for block.  We need to build a list of
-	 locations to go along with FOR_BLOCK.  */
-      stmt = c_end_compound_stmt (loc, for_block->pop (), true);
-      add_stmt (stmt);
+      c_parser_error (parser, "expected %<point%>");
+      c_parser_skip_to_pragma_eol (parser);
+      return;
     }
-  release_tree_vector (for_block);
-  return ret;
-}
 
-/* OpenMP 2.5:
-   #pragma omp for for-clause[optseq] new-line
-     for-loop
+  clauses
+    = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK,
+				"#pragma omp cancellation point");
 
-   LOC is the location of the #pragma token.
-*/
+  c_finish_omp_cancellation_point (loc, clauses);
+}
+
+/* OpenMP 4.0:
+   #pragma omp distribute distribute-clause[optseq] new-line
+     for-loop  */
 
-#define OMP_FOR_CLAUSE_MASK				\
-	( (1u << PRAGMA_OMP_CLAUSE_PRIVATE)		\
-	| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
-	| (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE)		\
-	| (1u << PRAGMA_OMP_CLAUSE_REDUCTION)		\
-	| (1u << PRAGMA_OMP_CLAUSE_ORDERED)		\
-	| (1u << PRAGMA_OMP_CLAUSE_SCHEDULE)		\
-	| (1u << PRAGMA_OMP_CLAUSE_COLLAPSE)		\
-	| (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+#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_for (location_t loc, c_parser *parser)
+c_parser_omp_distribute (location_t loc, c_parser *parser,
+			 char *p_name, omp_clause_mask mask, tree *cclauses)
 {
-  tree block, clauses, ret;
+  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, OMP_FOR_CLAUSE_MASK,
-				      "#pragma omp for");
+  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, clauses, NULL);
+  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 2.5:
-   # pragma omp master new-line
-     structured-block
-
-   LOC is the location of the #pragma token.
-*/
+/* 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_master (location_t loc, c_parser *parser)
+c_parser_omp_teams (location_t loc, c_parser *parser,
+		    char *p_name, omp_clause_mask mask, tree *cclauses)
 {
-  c_parser_skip_to_pragma_eol (parser);
-  return c_finish_omp_master (loc, c_parser_omp_structured_block (parser));
+  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 2.5:
-   # pragma omp ordered new-line
-     structured-block
+/* OpenMP 4.0:
+   # pragma omp target data target-data-clause[optseq] new-line
+     structured-block  */
 
-   LOC is the location of the #pragma itself.
-*/
+#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_ordered (location_t loc, c_parser *parser)
+c_parser_omp_target_data (location_t loc, c_parser *parser)
 {
-  c_parser_skip_to_pragma_eol (parser);
-  return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser));
-}
+  tree stmt = make_node (OMP_TARGET_DATA);
+  TREE_TYPE (stmt) = void_type_node;
 
-/* OpenMP 2.5:
+  OMP_TARGET_DATA_CLAUSES (stmt)
+    = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
+				"#pragma omp target data");
+  keep_next_level ();
+  tree block = c_begin_compound_stmt (true);
+  add_stmt (c_parser_omp_structured_block (parser));
+  OMP_TARGET_DATA_BODY (stmt) = c_end_compound_stmt (loc, block, true);
 
-   section-scope:
-     { section-sequence }
+  SET_EXPR_LOCATION (stmt, loc);
+  return add_stmt (stmt);
+}
 
-   section-sequence:
-     section-directive[opt] structured-block
-     section-sequence section-directive structured-block
+/* OpenMP 4.0:
+   # pragma omp target update target-update-clause[optseq] new-line */
 
-    SECTIONS_LOC is the location of the #pragma omp sections.  */
+#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 tree
-c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser)
+static bool
+c_parser_omp_target_update (location_t loc, c_parser *parser,
+			    enum pragma_context context)
 {
-  tree stmt, substmt;
-  bool error_suppress = false;
-  location_t loc;
-
-  loc = c_parser_peek_token (parser)->location;
-  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+  if (context == pragma_stmt)
     {
-      /* Avoid skipping until the end of the block.  */
-      parser->error = false;
-      return NULL_TREE;
+      error_at (loc,
+		"%<#pragma omp target update%> may only be "
+		"used in compound statements");
+      c_parser_skip_to_pragma_eol (parser);
+      return false;
     }
 
-  stmt = push_stmt_list ();
-
-  if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION)
+  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)
     {
-      substmt = push_stmt_list ();
+      error_at (loc,
+		"%<#pragma omp target update must contain at least one "
+		"%<from%> or %<to%> clauses");
+      return false;
+    }
 
-      while (1)
-	{
-          c_parser_statement (parser);
+  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;
+}
 
-	  if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
-	    break;
-	  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
-	    break;
-	  if (c_parser_next_token_is (parser, CPP_EOF))
-	    break;
-	}
+/* 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))
 
-      substmt = pop_stmt_list (substmt);
-      substmt = build1 (OMP_SECTION, void_type_node, substmt);
-      SET_EXPR_LOCATION (substmt, loc);
-      add_stmt (substmt);
+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;
     }
 
-  while (1)
+  if (c_parser_next_token_is (parser, CPP_NAME))
     {
-      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
-	break;
-      if (c_parser_next_token_is (parser, CPP_EOF))
-	break;
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
 
-      loc = c_parser_peek_token (parser)->location;
-      if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
+      if (strcmp (p, "data") == 0)
 	{
-	  c_parser_consume_pragma (parser);
-	  c_parser_skip_to_pragma_eol (parser);
-	  error_suppress = false;
+	  c_parser_consume_token (parser);
+	  c_parser_omp_target_data (loc, parser);
+	  return true;
 	}
-      else if (!error_suppress)
+      else if (strcmp (p, "update") == 0)
 	{
-	  error_at (loc, "expected %<#pragma omp section%> or %<}%>");
-	  error_suppress = true;
+	  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");
+	  keep_next_level ();
+	  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;
 	}
+    }
 
-      substmt = c_parser_omp_structured_block (parser);
-      substmt = build1 (OMP_SECTION, void_type_node, substmt);
-      SET_EXPR_LOCATION (substmt, loc);
-      add_stmt (substmt);
+  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");
+  keep_next_level ();
+  tree block = c_begin_compound_stmt (true);
+  add_stmt (c_parser_omp_structured_block (parser));
+  OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true);
+
+  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				\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN)	\
+	| (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_INBRANCH)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH))
+
+static void
+c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
+{
+  vec<c_token> clauses = vNULL;
+  while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+    {
+      c_token *token = c_parser_peek_token (parser);
+      if (token->type == CPP_EOF)
+	{
+	  c_parser_skip_to_pragma_eol (parser);
+	  clauses.release ();
+	  return;
+	}
+      clauses.safe_push (*token);
+      c_parser_consume_token (parser);
     }
-  c_parser_skip_until_found (parser, CPP_CLOSE_BRACE,
-			     "expected %<#pragma omp section%> or %<}%>");
+  clauses.safe_push (*c_parser_peek_token (parser));
+  c_parser_skip_to_pragma_eol (parser);
 
-  substmt = pop_stmt_list (stmt);
+  while (c_parser_next_token_is (parser, CPP_PRAGMA))
+    {
+      if (c_parser_peek_token (parser)->pragma_kind
+	  != PRAGMA_OMP_DECLARE_REDUCTION
+	  || c_parser_peek_2nd_token (parser)->type != CPP_NAME
+	  || strcmp (IDENTIFIER_POINTER
+				(c_parser_peek_2nd_token (parser)->value),
+		     "simd") != 0)
+	{
+	  c_parser_error (parser,
+			  "%<#pragma omp declare simd%> must be followed by "
+			  "function declaration or definition or another "
+			  "%<#pragma omp declare simd%>");
+	  clauses.release ();
+	  return;
+	}
+      c_parser_consume_pragma (parser);
+      while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+	{
+	  c_token *token = c_parser_peek_token (parser);
+	  if (token->type == CPP_EOF)
+	    {
+	      c_parser_skip_to_pragma_eol (parser);
+	      clauses.release ();
+	      return;
+	    }
+	  clauses.safe_push (*token);
+	  c_parser_consume_token (parser);
+	}
+      clauses.safe_push (*c_parser_peek_token (parser));
+      c_parser_skip_to_pragma_eol (parser);
+    }
 
-  stmt = make_node (OMP_SECTIONS);
-  SET_EXPR_LOCATION (stmt, sections_loc);
-  TREE_TYPE (stmt) = void_type_node;
-  OMP_SECTIONS_BODY (stmt) = substmt;
+  /* Make sure nothing tries to read past the end of the tokens.  */
+  c_token eof_token;
+  memset (&eof_token, 0, sizeof (eof_token));
+  eof_token.type = CPP_EOF;
+  clauses.safe_push (eof_token);
+  clauses.safe_push (eof_token);
 
-  return add_stmt (stmt);
+  switch (context)
+    {
+    case pragma_external:
+      if (c_parser_next_token_is (parser, CPP_KEYWORD)
+	  && c_parser_peek_token (parser)->keyword == RID_EXTENSION)
+	{
+	  int ext = disable_extension_diagnostics ();
+	  do
+	    c_parser_consume_token (parser);
+	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
+		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
+	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
+					 NULL, clauses);
+	  restore_extension_diagnostics (ext);
+	}
+      else
+	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
+				       NULL, clauses);
+      break;
+    case pragma_struct:
+    case pragma_param:
+      c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by "
+			      "function declaration or definition");
+      break;
+    case pragma_compound:
+    case pragma_stmt:
+      if (c_parser_next_token_is (parser, CPP_KEYWORD)
+	  && c_parser_peek_token (parser)->keyword == RID_EXTENSION)
+	{
+	  int ext = disable_extension_diagnostics ();
+	  do
+	    c_parser_consume_token (parser);
+	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
+		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
+	  if (c_parser_next_tokens_start_declaration (parser))
+	    {
+	      c_parser_declaration_or_fndef (parser, true, true, true, true,
+					     true, NULL, clauses);
+	      restore_extension_diagnostics (ext);
+	      break;
+	    }
+	  restore_extension_diagnostics (ext);
+	}
+      else if (c_parser_next_tokens_start_declaration (parser))
+	{
+	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
+					 NULL, clauses);
+	  break;
+	}
+      c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by "
+			      "function declaration or definition");
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  clauses.release ();
 }
 
-/* OpenMP 2.5:
-   # pragma omp sections sections-clause[optseq] newline
-     sections-scope
+/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed,
+   and put that into "omp declare simd" attribute.  */
 
-   LOC is the location of the #pragma token.
-*/
+static void
+c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
+			   vec<c_token> clauses)
+{
+  /* Normally first token is CPP_NAME "simd".  CPP_EOF there indicates
+     error has been reported and CPP_PRAGMA that c_finish_omp_declare_simd
+     has already processed the tokens.  */
+  if (clauses[0].type == CPP_EOF)
+    return;
+  if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL)
+    {
+      error ("%<#pragma omp declare simd%> not immediately followed by "
+	     "a function declaration or definition");
+      clauses[0].type = CPP_EOF;
+      return;
+    }
+  if (clauses[0].type != CPP_NAME)
+    {
+      error_at (DECL_SOURCE_LOCATION (fndecl),
+		"%<#pragma omp declare simd%> not immediately followed by "
+		"a single function declaration or definition");
+      clauses[0].type = CPP_EOF;
+      return;
+    }
 
-#define OMP_SECTIONS_CLAUSE_MASK			\
-	( (1u << PRAGMA_OMP_CLAUSE_PRIVATE)		\
-	| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
-	| (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE)		\
-	| (1u << PRAGMA_OMP_CLAUSE_REDUCTION)		\
-	| (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+  if (parms == NULL_TREE)
+    parms = DECL_ARGUMENTS (fndecl);
 
-static tree
-c_parser_omp_sections (location_t loc, c_parser *parser)
-{
-  tree block, clauses, ret;
+  unsigned int tokens_avail = parser->tokens_avail;
+  gcc_assert (parser->tokens == &parser->tokens_buf[0]);
+  parser->tokens = clauses.address ();
+  parser->tokens_avail = clauses.length ();
 
-  clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK,
-				      "#pragma omp sections");
+  /* c_parser_omp_declare_simd pushed 2 extra CPP_EOF tokens at the end.  */
+  while (parser->tokens_avail > 3)
+    {
+      c_token *token = c_parser_peek_token (parser);
+      gcc_assert (token->type == CPP_NAME
+		  && strcmp (IDENTIFIER_POINTER (token->value), "simd") == 0);
+      c_parser_consume_token (parser);
+      parser->in_pragma = true;
 
-  block = c_begin_compound_stmt (true);
-  ret = c_parser_omp_sections_scope (loc, parser);
-  if (ret)
-    OMP_SECTIONS_CLAUSES (ret) = clauses;
-  block = c_end_compound_stmt (loc, block, true);
-  add_stmt (block);
+      tree c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
+					 "#pragma omp declare simd");
+      c = c_omp_declare_simd_clauses_to_numbers (parms, c);
+      c = build_tree_list (get_identifier ("omp declare simd"), c);
+      TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl);
+      DECL_ATTRIBUTES (fndecl) = c;
+    }
 
-  return ret;
+  parser->tokens = &parser->tokens_buf[0];
+  parser->tokens_avail = tokens_avail;
+  clauses[0].type = CPP_PRAGMA;
 }
 
-/* OpenMP 2.5:
-   # pragma parallel parallel-clause new-line
-   # pragma parallel for parallel-for-clause new-line
-   # pragma parallel sections parallel-sections-clause new-line
 
-   LOC is the location of the #pragma token.
-*/
+/* OpenMP 4.0:
+   # pragma omp declare target new-line
+   declarations and definitions
+   # pragma omp end declare target new-line  */
 
-#define OMP_PARALLEL_CLAUSE_MASK			\
-	( (1u << PRAGMA_OMP_CLAUSE_IF)			\
-	| (1u << PRAGMA_OMP_CLAUSE_PRIVATE)		\
-	| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
-	| (1u << PRAGMA_OMP_CLAUSE_DEFAULT)		\
-	| (1u << PRAGMA_OMP_CLAUSE_SHARED)		\
-	| (1u << PRAGMA_OMP_CLAUSE_COPYIN)		\
-	| (1u << PRAGMA_OMP_CLAUSE_REDUCTION)		\
-	| (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS))
-
-static tree
-c_parser_omp_parallel (location_t loc, c_parser *parser)
-{
-  enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL;
-  const char *p_name = "#pragma omp parallel";
-  tree stmt, clauses, par_clause, ws_clause, block;
-  unsigned int mask = OMP_PARALLEL_CLAUSE_MASK;
+static void
+c_parser_omp_declare_target (c_parser *parser)
+{
+  c_parser_skip_to_pragma_eol (parser);
+  current_omp_declare_target_attribute++;
+}
 
-  if (c_parser_next_token_is_keyword (parser, RID_FOR))
+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);
-      p_kind = PRAGMA_OMP_PARALLEL_FOR;
-      p_name = "#pragma omp parallel for";
-      mask |= OMP_FOR_CLAUSE_MASK;
-      mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
-    }
-  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)
+      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_consume_token (parser);
-	  p_kind = PRAGMA_OMP_PARALLEL_SECTIONS;
-	  p_name = "#pragma omp parallel sections";
-	  mask |= OMP_SECTIONS_CLAUSE_MASK;
-	  mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+	  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--;
+}
 
-  clauses = c_parser_omp_all_clauses (parser, mask, p_name);
 
-  switch (p_kind)
+/* OpenMP 4.0
+   #pragma omp declare reduction (reduction-id : typename-list : expression) \
+      initializer-clause[opt] new-line
+
+   initializer-clause:
+      initializer (omp_priv = initializer)
+      initializer (function-name (argument-list))  */
+
+static void
+c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context)
+{
+  unsigned int tokens_avail = 0, i;
+  vec<tree> types = vNULL;
+  vec<c_token> clauses = vNULL;
+  enum tree_code reduc_code = ERROR_MARK;
+  tree reduc_id = NULL_TREE;
+  tree type;
+  location_t rloc = c_parser_peek_token (parser)->location;
+
+  if (context == pragma_struct || context == pragma_param)
     {
-    case PRAGMA_OMP_PARALLEL:
-      block = c_begin_omp_parallel ();
-      c_parser_statement (parser);
-      stmt = c_finish_omp_parallel (loc, clauses, block);
-      break;
+      error ("%<#pragma omp declare reduction%> not at file or block scope");
+      goto fail;
+    }
 
-    case PRAGMA_OMP_PARALLEL_FOR:
-      block = c_begin_omp_parallel ();
-      c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
-      c_parser_omp_for_loop (loc, parser, ws_clause, &par_clause);
-      stmt = c_finish_omp_parallel (loc, par_clause, block);
-      OMP_PARALLEL_COMBINED (stmt) = 1;
-      break;
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    goto fail;
 
-    case PRAGMA_OMP_PARALLEL_SECTIONS:
-      block = c_begin_omp_parallel ();
-      c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
-      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;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_PLUS:
+      reduc_code = PLUS_EXPR;
+      break;
+    case CPP_MULT:
+      reduc_code = MULT_EXPR;
+      break;
+    case CPP_MINUS:
+      reduc_code = MINUS_EXPR;
+      break;
+    case CPP_AND:
+      reduc_code = BIT_AND_EXPR;
+      break;
+    case CPP_XOR:
+      reduc_code = BIT_XOR_EXPR;
+      break;
+    case CPP_OR:
+      reduc_code = BIT_IOR_EXPR;
+      break;
+    case CPP_AND_AND:
+      reduc_code = TRUTH_ANDIF_EXPR;
+      break;
+    case CPP_OR_OR:
+      reduc_code = TRUTH_ORIF_EXPR;
+      break;
+    case CPP_NAME:
+      const char *p;
+      p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (strcmp (p, "min") == 0)
+	{
+	  reduc_code = MIN_EXPR;
+	  break;
+	}
+      if (strcmp (p, "max") == 0)
+	{
+	  reduc_code = MAX_EXPR;
+	  break;
+	}
+      reduc_id = c_parser_peek_token (parser)->value;
       break;
-
     default:
-      gcc_unreachable ();
+      c_parser_error (parser,
+		      "expected %<+%>, %<*%>, %<-%>, %<&%>, "
+		      "%<^%>, %<|%>, %<&&%>, %<||%>, %<min%> or identifier");
+      goto fail;
     }
 
-  return stmt;
-}
+  tree orig_reduc_id, reduc_decl;
+  orig_reduc_id = reduc_id;
+  reduc_id = c_omp_reduction_id (reduc_code, reduc_id);
+  reduc_decl = c_omp_reduction_decl (reduc_id);
+  c_parser_consume_token (parser);
 
-/* OpenMP 2.5:
-   # pragma omp single single-clause[optseq] new-line
-     structured-block
+  if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+    goto fail;
 
-   LOC is the location of the #pragma.
-*/
+  while (true)
+    {
+      location_t loc = c_parser_peek_token (parser)->location;
+      struct c_type_name *ctype = c_parser_type_name (parser);
+      if (ctype != NULL)
+	{
+	  type = groktypename (ctype, NULL, NULL);
+	  if (type == error_mark_node)
+	    ;
+	  else if ((INTEGRAL_TYPE_P (type)
+		    || TREE_CODE (type) == REAL_TYPE
+		    || TREE_CODE (type) == COMPLEX_TYPE)
+		   && orig_reduc_id == NULL_TREE)
+	    error_at (loc, "predeclared arithmetic type in "
+			   "%<#pragma omp declare reduction%>");
+	  else if (TREE_CODE (type) == FUNCTION_TYPE
+		   || TREE_CODE (type) == ARRAY_TYPE)
+	    error_at (loc, "function or array type in "
+		      "%<#pragma omp declare reduction%>");
+	  else if (TYPE_QUALS_NO_ADDR_SPACE (type))
+	    error_at (loc, "const, volatile or restrict qualified type in "
+			   "%<#pragma omp declare reduction%>");
+	  else
+	    {
+	      tree t;
+	      for (t = DECL_INITIAL (reduc_decl); t; t = TREE_CHAIN (t))
+		if (comptypes (TREE_PURPOSE (t), type))
+		  {
+		    error_at (loc, "redeclaration of %qs "
+				   "%<#pragma omp declare reduction%> for "
+				   "type %qT",
+				   IDENTIFIER_POINTER (reduc_id)
+				   + sizeof ("omp declare reduction ") - 1,
+				   type);
+		    location_t ploc
+		      = DECL_SOURCE_LOCATION (TREE_VEC_ELT (TREE_VALUE (t),
+							    0));
+		    error_at (ploc, "previous %<#pragma omp declare "
+				    "reduction%>");
+		    break;
+		  }
+	      if (t == NULL_TREE)
+		types.safe_push (type);
+	    }
+	  if (c_parser_next_token_is (parser, CPP_COMMA))
+	    c_parser_consume_token (parser);
+	  else
+	    break;
+	}
+      else
+	break;
+    }
 
-#define OMP_SINGLE_CLAUSE_MASK				\
-	( (1u << PRAGMA_OMP_CLAUSE_PRIVATE)		\
-	| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
-	| (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE)		\
-	| (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+  if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")
+      || types.is_empty ())
+    {
+     fail:
+      clauses.release ();
+      types.release ();
+      while (true)
+	{
+	  c_token *token = c_parser_peek_token (parser);
+	  if (token->type == CPP_EOF || token->type == CPP_PRAGMA_EOL)
+	    break;
+	  c_parser_consume_token (parser);
+	}
+      c_parser_skip_to_pragma_eol (parser);
+      return;
+    }
 
-static tree
-c_parser_omp_single (location_t loc, c_parser *parser)
-{
-  tree stmt = make_node (OMP_SINGLE);
-  SET_EXPR_LOCATION (stmt, loc);
-  TREE_TYPE (stmt) = void_type_node;
+  if (types.length () > 1)
+    {
+      while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+	{
+	  c_token *token = c_parser_peek_token (parser);
+	  if (token->type == CPP_EOF)
+	    goto fail;
+	  clauses.safe_push (*token);
+	  c_parser_consume_token (parser);
+	}
+      clauses.safe_push (*c_parser_peek_token (parser));
+      c_parser_skip_to_pragma_eol (parser);
 
-  OMP_SINGLE_CLAUSES (stmt)
-    = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK,
-				"#pragma omp single");
-  OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser);
+      /* Make sure nothing tries to read past the end of the tokens.  */
+      c_token eof_token;
+      memset (&eof_token, 0, sizeof (eof_token));
+      eof_token.type = CPP_EOF;
+      clauses.safe_push (eof_token);
+      clauses.safe_push (eof_token);
+    }
 
-  return add_stmt (stmt);
-}
+  int errs = errorcount;
+  FOR_EACH_VEC_ELT (types, i, type)
+    {
+      tokens_avail = parser->tokens_avail;
+      gcc_assert (parser->tokens == &parser->tokens_buf[0]);
+      if (!clauses.is_empty ())
+	{
+	  parser->tokens = clauses.address ();
+	  parser->tokens_avail = clauses.length ();
+	  parser->in_pragma = true;
+	}
 
-/* OpenMP 3.0:
-   # pragma omp task task-clause[optseq] new-line
+      bool nested = current_function_decl != NULL_TREE;
+      if (nested)
+	c_push_function_context ();
+      tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
+				reduc_id, default_function_type);
+      current_function_decl = fndecl;
+      allocate_struct_function (fndecl, true);
+      push_scope ();
+      tree stmt = push_stmt_list ();
+      /* Intentionally BUILTINS_LOCATION, so that -Wshadow doesn't
+	 warn about these.  */
+      tree omp_out = build_decl (BUILTINS_LOCATION, VAR_DECL,
+				 get_identifier ("omp_out"), type);
+      DECL_ARTIFICIAL (omp_out) = 1;
+      DECL_CONTEXT (omp_out) = fndecl;
+      pushdecl (omp_out);
+      tree omp_in = build_decl (BUILTINS_LOCATION, VAR_DECL,
+				get_identifier ("omp_in"), type);
+      DECL_ARTIFICIAL (omp_in) = 1;
+      DECL_CONTEXT (omp_in) = fndecl;
+      pushdecl (omp_in);
+      struct c_expr combiner = c_parser_expression (parser);
+      struct c_expr initializer;
+      tree omp_priv = NULL_TREE, omp_orig = NULL_TREE;
+      bool bad = false;
+      initializer.value = error_mark_node;
+      if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+	bad = true;
+      else if (c_parser_next_token_is (parser, CPP_NAME)
+	       && strcmp (IDENTIFIER_POINTER
+				(c_parser_peek_token (parser)->value),
+			  "initializer") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  pop_scope ();
+	  push_scope ();
+	  omp_priv = build_decl (BUILTINS_LOCATION, VAR_DECL,
+				 get_identifier ("omp_priv"), type);
+	  DECL_ARTIFICIAL (omp_priv) = 1;
+	  DECL_INITIAL (omp_priv) = error_mark_node;
+	  DECL_CONTEXT (omp_priv) = fndecl;
+	  pushdecl (omp_priv);
+	  omp_orig = build_decl (BUILTINS_LOCATION, VAR_DECL,
+				 get_identifier ("omp_orig"), type);
+	  DECL_ARTIFICIAL (omp_orig) = 1;
+	  DECL_CONTEXT (omp_orig) = fndecl;
+	  pushdecl (omp_orig);
+	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+	    bad = true;
+	  else if (!c_parser_next_token_is (parser, CPP_NAME))
+	    {
+	      c_parser_error (parser, "expected %<omp_priv%> or "
+				      "function-name");
+	      bad = true;
+	    }
+	  else if (strcmp (IDENTIFIER_POINTER
+				(c_parser_peek_token (parser)->value),
+			   "omp_priv") != 0)
+	    {
+	      if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN
+		  || c_parser_peek_token (parser)->id_kind != C_ID_ID)
+		{
+		  c_parser_error (parser, "expected function-name %<(%>");
+		  bad = true;
+		}
+	      else
+		initializer = c_parser_postfix_expression (parser);
+	      if (initializer.value
+		  && TREE_CODE (initializer.value) == CALL_EXPR)
+		{
+		  int j;
+		  tree c = initializer.value;
+		  for (j = 0; j < call_expr_nargs (c); j++)
+		    if (TREE_CODE (CALL_EXPR_ARG (c, j)) == ADDR_EXPR
+			&& TREE_OPERAND (CALL_EXPR_ARG (c, j), 0) == omp_priv)
+		      break;
+		  if (j == call_expr_nargs (c))
+		    error ("one of the initializer call arguments should be "
+			   "%<&omp_priv%>");
+		}
+	    }
+	  else
+	    {
+	      c_parser_consume_token (parser);
+	      if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+		bad = true;
+	      else
+		{
+		  tree st = push_stmt_list ();
+		  start_init (omp_priv, NULL_TREE, 0);
+		  location_t loc = c_parser_peek_token (parser)->location;
+		  struct c_expr init = c_parser_initializer (parser);
+		  finish_init ();
+		  finish_decl (omp_priv, loc, init.value,
+		      	       init.original_type, NULL_TREE);
+		  pop_stmt_list (st);
+		}
+	    }
+	  if (!bad
+	      && !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+	    bad = true;
+	}
 
-   LOC is the location of the #pragma.
-*/
+      if (!bad)
+	{
+	  c_parser_skip_to_pragma_eol (parser);
 
-#define OMP_TASK_CLAUSE_MASK				\
-	( (1u << PRAGMA_OMP_CLAUSE_IF)			\
-	| (1u << PRAGMA_OMP_CLAUSE_UNTIED)		\
-	| (1u << PRAGMA_OMP_CLAUSE_DEFAULT)		\
-	| (1u << PRAGMA_OMP_CLAUSE_PRIVATE)		\
-	| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
-	| (1u << PRAGMA_OMP_CLAUSE_SHARED)		\
-	| (1u << PRAGMA_OMP_CLAUSE_FINAL)		\
-	| (1u << PRAGMA_OMP_CLAUSE_MERGEABLE))
+	  tree t = tree_cons (type, make_tree_vec (omp_priv ? 6 : 3),
+			      DECL_INITIAL (reduc_decl));
+	  DECL_INITIAL (reduc_decl) = t;
+	  DECL_SOURCE_LOCATION (omp_out) = rloc;
+	  TREE_VEC_ELT (TREE_VALUE (t), 0) = omp_out;
+	  TREE_VEC_ELT (TREE_VALUE (t), 1) = omp_in;
+	  TREE_VEC_ELT (TREE_VALUE (t), 2) = combiner.value;
+	  walk_tree (&combiner.value, c_check_omp_declare_reduction_r,
+		     &TREE_VEC_ELT (TREE_VALUE (t), 0), NULL);
+	  if (omp_priv)
+	    {
+	      DECL_SOURCE_LOCATION (omp_priv) = rloc;
+	      TREE_VEC_ELT (TREE_VALUE (t), 3) = omp_priv;
+	      TREE_VEC_ELT (TREE_VALUE (t), 4) = omp_orig;
+	      TREE_VEC_ELT (TREE_VALUE (t), 5) = initializer.value;
+	      walk_tree (&initializer.value, c_check_omp_declare_reduction_r,
+			 &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL);
+	      walk_tree (&DECL_INITIAL (omp_priv),
+			 c_check_omp_declare_reduction_r,
+			 &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL);
+	    }
+	}
 
-static tree
-c_parser_omp_task (location_t loc, c_parser *parser)
-{
-  tree clauses, block;
+      pop_stmt_list (stmt);
+      pop_scope ();
+      if (cfun->language != NULL)
+	{
+	  ggc_free (cfun->language);
+	  cfun->language = NULL;
+	}
+      set_cfun (NULL);
+      current_function_decl = NULL_TREE;
+      if (nested)
+	c_pop_function_context ();
 
-  clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK,
-				      "#pragma omp task");
+      if (!clauses.is_empty ())
+	{
+	  parser->tokens = &parser->tokens_buf[0];
+	  parser->tokens_avail = tokens_avail;
+	}
+      if (bad)
+	goto fail;
+      if (errs != errorcount)
+	break;
+    }
 
-  block = c_begin_omp_task ();
-  c_parser_statement (parser);
-  return c_finish_omp_task (loc, clauses, block);
+  clauses.release ();
+  types.release ();
 }
 
-/* OpenMP 3.0:
-   # pragma omp taskwait new-line
-*/
-
-static void
-c_parser_omp_taskwait (c_parser *parser)
-{
-  location_t loc = c_parser_peek_token (parser)->location;
-  c_parser_consume_pragma (parser);
-  c_parser_skip_to_pragma_eol (parser);
-
-  c_finish_omp_taskwait (loc);
-}
 
-/* OpenMP 3.1:
-   # pragma omp taskyield new-line
-*/
+/* OpenMP 4.0
+   #pragma omp declare simd declare-simd-clauses[optseq] new-line
+   #pragma omp declare reduction (reduction-id : typename-list : expression) \
+      initializer-clause[opt] new-line
+   #pragma omp declare target new-line  */
 
 static void
-c_parser_omp_taskyield (c_parser *parser)
+c_parser_omp_declare (c_parser *parser, enum pragma_context context)
 {
-  location_t loc = c_parser_peek_token (parser)->location;
   c_parser_consume_pragma (parser);
-  c_parser_skip_to_pragma_eol (parser);
+  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); done in
+	     c_parser_omp_declare_simd.  */
+	  c_parser_omp_declare_simd (parser, context);
+	  return;
+	}
+      if (strcmp (p, "reduction") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  c_parser_omp_declare_reduction (parser, context);
+	  return;
+	}
+      if (strcmp (p, "target") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  c_parser_omp_declare_target (parser);
+	  return;
+	}
+    }
 
-  c_finish_omp_taskyield (loc);
+  c_parser_error (parser, "expected %<simd%> or %<reduction%> "
+			  "or %<target%>");
+  c_parser_skip_to_pragma_eol (parser);
 }
 
 /* Main entry point to parsing most OpenMP pragmas.  */
@@ -10888,6 +12840,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;
@@ -10901,8 +12855,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);
@@ -10911,10 +12870,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:
+      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);
@@ -10922,6 +12887,13 @@  c_parser_omp_construct (c_parser *parser
     case PRAGMA_OMP_TASK:
       stmt = c_parser_omp_task (loc, parser);
       break;
+    case PRAGMA_OMP_TASKGROUP:
+      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);
+      break;
     default:
       gcc_unreachable ();
     }
@@ -11148,7 +13120,7 @@  c_parser_transaction_expression (c_parse
 */
 
 static tree
-c_parser_transaction_cancel(c_parser *parser)
+c_parser_transaction_cancel (c_parser *parser)
 {
   location_t loc = c_parser_peek_token (parser)->location;
   tree attrs;
@@ -11208,6 +13180,7 @@  c_parse_file (void)
   c_parser tparser;
 
   memset (&tparser, 0, sizeof tparser);
+  tparser.tokens = &tparser.tokens_buf[0];
   the_parser = &tparser;
 
   if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS)
@@ -11215,6 +13188,8 @@  c_parse_file (void)
 
   the_parser = ggc_alloc_c_parser ();
   *the_parser = tparser;
+  if (tparser.tokens == &tparser.tokens_buf[0])
+    the_parser->tokens = &the_parser->tokens_buf[0];
 
   /* Initialize EH, if we've been told to do so.  */
   if (flag_exceptions)
--- gcc/c/c-tree.h	(.../trunk)	(revision 203241)
+++ gcc/c/c-tree.h	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -526,6 +526,8 @@  extern tree start_struct (location_t, en
 			  struct c_struct_parse_info **);
 extern void store_parm_decls (void);
 extern void store_parm_decls_from (struct c_arg_info *);
+extern void temp_store_parm_decls (tree, tree);
+extern void temp_pop_parm_decls (void);
 extern tree xref_tag (enum tree_code, tree);
 extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree);
 extern struct c_parm *build_c_parm (struct c_declspecs *, tree,
@@ -637,9 +639,12 @@  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 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);
 extern tree c_build_va_arg (location_t, tree, tree);
 extern tree c_finish_transaction (location_t, tree, int);
+extern bool c_tree_equal (tree, tree);
 
 /* Set to 0 at beginning of a function definition, set to 1 if
    a return statement that specifies a return value is seen.  */
@@ -663,6 +668,10 @@  extern enum machine_mode c_default_point
 /* In c-decl.c */
 extern void c_finish_incomplete_decl (tree);
 extern void c_write_global_declarations (void);
+extern tree c_omp_reduction_id (enum tree_code, tree);
+extern tree c_omp_reduction_decl (tree);
+extern tree c_omp_reduction_lookup (tree, tree);
+extern tree c_check_omp_declare_reduction_r (tree *, int *, void *);
 
 /* In c-errors.c */
 extern void pedwarn_c90 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
--- gcc/c/c-typeck.c	(.../trunk)	(revision 203241)
+++ gcc/c/c-typeck.c	(.../branches/gomp-4_0-branch)	(revision 203287)
@@ -37,6 +37,7 @@  along with GCC; see the file COPYING3.
 #include "tree-iterator.h"
 #include "bitmap.h"
 #include "gimple.h"
+#include "tree-inline.h"
 #include "c-family/c-objc.h"
 #include "c-family/c-common.h"
 #include "c-family/c-ubsan.h"
@@ -10692,6 +10693,537 @@  c_finish_omp_task (location_t loc, tree
   return add_stmt (stmt);
 }
 
+/* Generate GOMP_cancel call for #pragma omp cancel.  */
+
+void
+c_finish_omp_cancel (location_t loc, tree clauses)
+{
+  tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCEL);
+  int mask = 0;
+  if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL))
+    mask = 1;
+  else if (find_omp_clause (clauses, OMP_CLAUSE_FOR))
+    mask = 2;
+  else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS))
+    mask = 4;
+  else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP))
+    mask = 8;
+  else
+    {
+      error_at (loc, "%<#pragma omp cancel must specify one of "
+		     "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> "
+		     "clauses");
+      return;
+    }
+  tree ifc = find_omp_clause (clauses, OMP_CLAUSE_IF);
+  if (ifc != NULL_TREE)
+    {
+      tree type = TREE_TYPE (OMP_CLAUSE_IF_EXPR (ifc));
+      ifc = fold_build2_loc (OMP_CLAUSE_LOCATION (ifc), NE_EXPR,
+			     boolean_type_node, OMP_CLAUSE_IF_EXPR (ifc),
+			     build_zero_cst (type));
+    }
+  else
+    ifc = boolean_true_node;
+  tree stmt = build_call_expr_loc (loc, fn, 2,
+				   build_int_cst (integer_type_node, mask),
+				   ifc);
+  add_stmt (stmt);
+}
+
+/* Generate GOMP_cancellation_point call for
+   #pragma omp cancellation point.  */
+
+void
+c_finish_omp_cancellation_point (location_t loc, tree clauses)
+{
+  tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCELLATION_POINT);
+  int mask = 0;
+  if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL))
+    mask = 1;
+  else if (find_omp_clause (clauses, OMP_CLAUSE_FOR))
+    mask = 2;
+  else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS))
+    mask = 4;
+  else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP))
+    mask = 8;
+  else
+    {
+      error_at (loc, "%<#pragma omp cancellation point must specify one of "
+		     "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> "
+		     "clauses");
+      return;
+    }
+  tree stmt = build_call_expr_loc (loc, fn, 1,
+				   build_int_cst (integer_type_node, mask));
+  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)
+{
+  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;
+	}
+      return t;
+    }
+
+  ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types,
+				     maybe_zero_len, first_non_one);
+  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));
+  /* We will need to evaluate lb more than once.  */
+  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;
+  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);
+  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);
+      first = c_fully_fold (first, false, NULL);
+      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);
+      first = c_fully_fold (first, false, NULL);
+      OMP_CLAUSE_DECL (c) = first;
+      if (size)
+	size = c_fully_fold (size, false, NULL);
+      OMP_CLAUSE_SIZE (c) = size;
+      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+	return false;
+      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), ptrdiff_type_node, t);
+      tree ptr = OMP_CLAUSE_DECL (c2);
+      if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
+	ptr = build_fold_addr_expr (ptr);
+      t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
+			   ptrdiff_type_node, t,
+			   fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+					     ptrdiff_type_node, ptr));
+      t = c_fully_fold (t, false, NULL);
+      OMP_CLAUSE_SIZE (c2) = t;
+      OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
+      OMP_CLAUSE_CHAIN (c) = c2;
+    }
+  return false;
+}
+
+/* Helper function of finish_omp_clauses.  Clone STMT as if we were making
+   an inline call.  But, remap
+   the OMP_DECL1 VAR_DECL (omp_out resp. omp_orig) to PLACEHOLDER
+   and OMP_DECL2 VAR_DECL (omp_in resp. omp_priv) to DECL.  */
+
+static tree
+c_clone_omp_udr (tree stmt, tree omp_decl1, tree omp_decl2,
+		 tree decl, tree placeholder)
+{
+  copy_body_data id;
+  struct pointer_map_t *decl_map = pointer_map_create ();
+
+  *pointer_map_insert (decl_map, omp_decl1) = placeholder;
+  *pointer_map_insert (decl_map, omp_decl2) = decl;
+  memset (&id, 0, sizeof (id));
+  id.src_fn = DECL_CONTEXT (omp_decl1);
+  id.dst_fn = current_function_decl;
+  id.src_cfun = DECL_STRUCT_FUNCTION (id.src_fn);
+  id.decl_map = decl_map;
+
+  id.copy_decl = copy_decl_no_change;
+  id.transform_call_graph_edges = CB_CGE_DUPLICATE;
+  id.transform_new_cfg = true;
+  id.transform_return_to_modify = false;
+  id.transform_lang_insert_block = NULL;
+  id.eh_lp_nr = 0;
+  walk_tree (&stmt, copy_tree_body_r, &id, NULL);
+  pointer_map_destroy (decl_map);
+  return stmt;
+}
+
+/* Helper function of c_finish_omp_clauses, called via walk_tree.
+   Find OMP_CLAUSE_PLACEHOLDER (passed in DATA) in *TP.  */
+
+static tree
+c_find_omp_placeholder_r (tree *tp, int *, void *data)
+{
+  if (*tp == (tree) data)
+    return *tp;
+  return NULL_TREE;
+}
+
 /* For all elements of CLAUSES, validate them vs OpenMP constraints.
    Remove any elements from the list that are invalid.  */
 
@@ -10699,13 +11231,17 @@  tree
 c_finish_omp_clauses (tree clauses)
 {
   bitmap_head generic_head, firstprivate_head, lastprivate_head;
+  bitmap_head aligned_head;
   tree c, t, *pc = &clauses;
-  const char *name;
+  bool branch_seen = false;
+  bool copyprivate_seen = false;
+  tree *nowait_clause = NULL;
 
   bitmap_obstack_initialize (NULL);
   bitmap_initialize (&generic_head, &bitmap_default_obstack);
   bitmap_initialize (&firstprivate_head, &bitmap_default_obstack);
   bitmap_initialize (&lastprivate_head, &bitmap_default_obstack);
+  bitmap_initialize (&aligned_head, &bitmap_default_obstack);
 
   for (pc = &clauses, c = clauses; c ; c = *pc)
     {
@@ -10716,28 +11252,19 @@  c_finish_omp_clauses (tree clauses)
       switch (OMP_CLAUSE_CODE (c))
 	{
 	case OMP_CLAUSE_SHARED:
-	  name = "shared";
 	  need_implicitly_determined = true;
 	  goto check_dup_generic;
 
 	case OMP_CLAUSE_PRIVATE:
-	  name = "private";
 	  need_complete = true;
 	  need_implicitly_determined = true;
 	  goto check_dup_generic;
 
 	case OMP_CLAUSE_REDUCTION:
-	  name = "reduction";
 	  need_implicitly_determined = true;
 	  t = OMP_CLAUSE_DECL (c);
-	  if (AGGREGATE_TYPE_P (TREE_TYPE (t))
-	      || POINTER_TYPE_P (TREE_TYPE (t)))
-	    {
-	      error_at (OMP_CLAUSE_LOCATION (c),
-			"%qE has invalid type for %<reduction%>", t);
-	      remove = true;
-	    }
-	  else if (FLOAT_TYPE_P (TREE_TYPE (t)))
+	  if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == NULL_TREE
+	      && FLOAT_TYPE_P (TREE_TYPE (t)))
 	    {
 	      enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c);
 	      const char *r_name = NULL;
@@ -10776,14 +11303,88 @@  c_finish_omp_clauses (tree clauses)
 		  remove = true;
 		}
 	    }
+	  else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == error_mark_node)
+	    {
+	      error_at (OMP_CLAUSE_LOCATION (c),
+			"user defined reduction not found for %qD", t);
+	      remove = true;
+	    }
+	  else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
+	    {
+	      tree list = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
+	      tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t));
+	      tree placeholder = build_decl (OMP_CLAUSE_LOCATION (c),
+					     VAR_DECL, NULL_TREE, type);
+	      OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder;
+	      DECL_ARTIFICIAL (placeholder) = 1;
+	      DECL_IGNORED_P (placeholder) = 1;
+	      if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 0)))
+		c_mark_addressable (placeholder);
+	      if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 1)))
+		c_mark_addressable (OMP_CLAUSE_DECL (c));
+	      OMP_CLAUSE_REDUCTION_MERGE (c)
+		= c_clone_omp_udr (TREE_VEC_ELT (list, 2),
+				   TREE_VEC_ELT (list, 0),
+				   TREE_VEC_ELT (list, 1),
+				   OMP_CLAUSE_DECL (c), placeholder);
+	      OMP_CLAUSE_REDUCTION_MERGE (c)
+		= build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR,
+			      void_type_node, NULL_TREE,
+			       OMP_CLAUSE_REDUCTION_MERGE (c), NULL_TREE);
+	      TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_MERGE (c)) = 1;
+	      if (TREE_VEC_LENGTH (list) == 6)
+		{
+		  if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 3)))
+		    c_mark_addressable (OMP_CLAUSE_DECL (c));
+		  if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 4)))
+		    c_mark_addressable (placeholder);
+		  tree init = TREE_VEC_ELT (list, 5);
+		  if (init == error_mark_node)
+		    init = DECL_INITIAL (TREE_VEC_ELT (list, 3));
+		  OMP_CLAUSE_REDUCTION_INIT (c)
+		    = c_clone_omp_udr (init, TREE_VEC_ELT (list, 4),
+				       TREE_VEC_ELT (list, 3),
+				       OMP_CLAUSE_DECL (c), placeholder);
+		  if (TREE_VEC_ELT (list, 5) == error_mark_node)
+		    OMP_CLAUSE_REDUCTION_INIT (c)
+		      = build2 (INIT_EXPR, TREE_TYPE (t), t,
+				OMP_CLAUSE_REDUCTION_INIT (c));
+		  if (walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c),
+				 c_find_omp_placeholder_r,
+				 placeholder, NULL))
+		    OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c) = 1;
+		}
+	      else
+		{
+		  tree init;
+		  if (AGGREGATE_TYPE_P (TREE_TYPE (t)))
+		    init = build_constructor (TREE_TYPE (t), NULL);
+		  else
+		    init = fold_convert (TREE_TYPE (t), integer_zero_node);
+		  OMP_CLAUSE_REDUCTION_INIT (c)
+		    = build2 (INIT_EXPR, TREE_TYPE (t), t, init);
+		}
+	      OMP_CLAUSE_REDUCTION_INIT (c)
+		= build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR,
+			      void_type_node, NULL_TREE,
+			       OMP_CLAUSE_REDUCTION_INIT (c), NULL_TREE);
+	      TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_INIT (c)) = 1;
+	    }
 	  goto check_dup_generic;
 
 	case OMP_CLAUSE_COPYPRIVATE:
-	  name = "copyprivate";
+	  copyprivate_seen = true;
+	  if (nowait_clause)
+	    {
+	      error_at (OMP_CLAUSE_LOCATION (*nowait_clause),
+			"%<nowait%> clause must not be used together "
+			"with %<copyprivate%>");
+	      *nowait_clause = OMP_CLAUSE_CHAIN (*nowait_clause);
+	      nowait_clause = NULL;
+	    }
 	  goto check_dup_generic;
 
 	case OMP_CLAUSE_COPYIN:
-	  name = "copyin";
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) != VAR_DECL || !DECL_THREAD_LOCAL_P (t))
 	    {
@@ -10793,12 +11394,36 @@  c_finish_omp_clauses (tree clauses)
 	    }
 	  goto check_dup_generic;
 
+	case OMP_CLAUSE_LINEAR:
+	  t = OMP_CLAUSE_DECL (c);
+	  if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+	      && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
+	    {
+	      error_at (OMP_CLAUSE_LOCATION (c),
+			"linear clause applied to non-integral non-pointer");
+	      remove = true;
+	      break;
+	    }
+	  if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) == POINTER_TYPE)
+	    {
+	      tree s = OMP_CLAUSE_LINEAR_STEP (c);
+	      s = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR,
+				   OMP_CLAUSE_DECL (c), s);
+	      s = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
+				   sizetype, s, OMP_CLAUSE_DECL (c));
+	      if (s == error_mark_node)
+		s = size_one_node;
+	      OMP_CLAUSE_LINEAR_STEP (c) = s;
+	    }
+	  goto check_dup_generic;
+
 	check_dup_generic:
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
-			"%qE is not a variable in clause %qs", t, name);
+			"%qE is not a variable in clause %qs", t,
+			omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
 	      remove = true;
 	    }
 	  else if (bitmap_bit_p (&generic_head, DECL_UID (t))
@@ -10814,7 +11439,6 @@  c_finish_omp_clauses (tree clauses)
 	  break;
 
 	case OMP_CLAUSE_FIRSTPRIVATE:
-	  name = "firstprivate";
 	  t = OMP_CLAUSE_DECL (c);
 	  need_complete = true;
 	  need_implicitly_determined = true;
@@ -10836,7 +11460,6 @@  c_finish_omp_clauses (tree clauses)
 	  break;
 
 	case OMP_CLAUSE_LASTPRIVATE:
-	  name = "lastprivate";
 	  t = OMP_CLAUSE_DECL (c);
 	  need_complete = true;
 	  need_implicitly_determined = true;
@@ -10857,16 +11480,167 @@  c_finish_omp_clauses (tree clauses)
 	    bitmap_set_bit (&lastprivate_head, DECL_UID (t));
 	  break;
 
+	case OMP_CLAUSE_ALIGNED:
+	  t = OMP_CLAUSE_DECL (c);
+	  if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+	    {
+	      error_at (OMP_CLAUSE_LOCATION (c),
+			"%qE is not a variable in %<aligned%> clause", t);
+	      remove = true;
+	    }
+	  else if (bitmap_bit_p (&aligned_head, DECL_UID (t)))
+	    {
+	      error_at (OMP_CLAUSE_LOCATION (c),
+			"%qE appears more than once in %<aligned%> clauses",
+			t);
+	      remove = true;
+	    }
+	  else
+	    bitmap_set_bit (&aligned_head, DECL_UID (t));
+	  break;
+
+	case OMP_CLAUSE_DEPEND:
+	  t = OMP_CLAUSE_DECL (c);
+	  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);
+	  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,
+			omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+	      remove = true;
+	    }
+	  else if (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)]);
+	      remove = true;
+	    }
+	  else if (!c_mark_addressable (t))
+	    remove = true;
+	  else if (!COMPLETE_TYPE_P (TREE_TYPE (t))
+		   && !(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+			&& OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER))
+	    {
+	      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 (bitmap_bit_p (&generic_head, DECL_UID (t)))
+	    {
+	      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+		error ("%qD appears more than once in motion clauses", t);
+	      else
+		error ("%qD appears more than once in map clauses", t);
+	      remove = true;
+	    }
+	  else
+	    bitmap_set_bit (&generic_head, DECL_UID (t));
+	  break;
+
+	case OMP_CLAUSE_UNIFORM:
+	  t = OMP_CLAUSE_DECL (c);
+	  if (TREE_CODE (t) != PARM_DECL)
+	    {
+	      if (DECL_P (t))
+		error_at (OMP_CLAUSE_LOCATION (c),
+			  "%qD is not an argument in %<uniform%> clause", t);
+	      else
+		error_at (OMP_CLAUSE_LOCATION (c),
+			  "%qE is not an argument in %<uniform%> clause", t);
+	      remove = true;
+	    }
+	  break;
+
+	case OMP_CLAUSE_NOWAIT:
+	  if (copyprivate_seen)
+	    {
+	      error_at (OMP_CLAUSE_LOCATION (c),
+			"%<nowait%> clause must not be used together "
+			"with %<copyprivate%>");
+	      remove = true;
+	      break;
+	    }
+	  nowait_clause = pc;
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
+
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
+	case OMP_CLAUSE_NUM_TEAMS:
+	case OMP_CLAUSE_THREAD_LIMIT:
 	case OMP_CLAUSE_SCHEDULE:
-	case OMP_CLAUSE_NOWAIT:
 	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_DEFAULT:
 	case OMP_CLAUSE_UNTIED:
 	case OMP_CLAUSE_COLLAPSE:
 	case OMP_CLAUSE_FINAL:
 	case OMP_CLAUSE_MERGEABLE:
+	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_SIMDLEN:
+	case OMP_CLAUSE_DEVICE:
+	case OMP_CLAUSE_DIST_SCHEDULE:
+	case OMP_CLAUSE_PARALLEL:
+	case OMP_CLAUSE_FOR:
+	case OMP_CLAUSE_SECTIONS:
+	case OMP_CLAUSE_TASKGROUP:
+	case OMP_CLAUSE_PROC_BIND:
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
+
+	case OMP_CLAUSE_INBRANCH:
+	case OMP_CLAUSE_NOTINBRANCH:
+	  if (branch_seen)
+	    {
+	      error_at (OMP_CLAUSE_LOCATION (c),
+			"%<inbranch%> clause is incompatible with "
+			"%<notinbranch%>");
+	      remove = true;
+	      break;
+	    }
+	  branch_seen = true;
 	  pc = &OMP_CLAUSE_CHAIN (c);
 	  continue;
 
@@ -10912,7 +11686,8 @@  c_finish_omp_clauses (tree clauses)
 		{
 		  error_at (OMP_CLAUSE_LOCATION (c),
 			    "%qE is predetermined %qs for %qs",
-			    t, share_name, name);
+			    t, share_name,
+			    omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
 		  remove = true;
 		}
 	    }
@@ -11016,3 +11791,205 @@  c_build_va_arg (location_t loc, tree exp
 		"C++ requires promoted type, not enum type, in %<va_arg%>");
   return build_va_arg (loc, expr, type);
 }
+
+/* Return truthvalue of whether T1 is the same tree structure as T2.
+   Return 1 if they are the same. Return 0 if they are different.  */
+
+bool
+c_tree_equal (tree t1, tree t2)
+{
+  enum tree_code code1, code2;
+
+  if (t1 == t2)
+    return true;
+  if (!t1 || !t2)
+    return false;
+
+  for (code1 = TREE_CODE (t1);
+       CONVERT_EXPR_CODE_P (code1)
+	 || code1 == NON_LVALUE_EXPR;
+       code1 = TREE_CODE (t1))
+    t1 = TREE_OPERAND (t1, 0);
+  for (code2 = TREE_CODE (t2);
+       CONVERT_EXPR_CODE_P (code2)
+	 || code2 == NON_LVALUE_EXPR;
+       code2 = TREE_CODE (t2))
+    t2 = TREE_OPERAND (t2, 0);
+
+  /* They might have become equal now.  */
+  if (t1 == t2)
+    return true;
+
+  if (code1 != code2)
+    return false;
+
+  switch (code1)
+    {
+    case INTEGER_CST:
+      return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
+	&& TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2);
+
+    case REAL_CST:
+      return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
+
+    case STRING_CST:
+      return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
+	&& !memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
+		    TREE_STRING_LENGTH (t1));
+
+    case FIXED_CST:
+      return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1),
+				     TREE_FIXED_CST (t2));
+
+    case COMPLEX_CST:
+      return c_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2))
+	     && c_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2));
+
+    case VECTOR_CST:
+      return operand_equal_p (t1, t2, OEP_ONLY_CONST);
+
+    case CONSTRUCTOR:
+      /* We need to do this when determining whether or not two
+	 non-type pointer to member function template arguments
+	 are the same.  */
+      if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2))
+	  || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2))
+	return false;
+      {
+	tree field, value;
+	unsigned int i;
+	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value)
+	  {
+	    constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i);
+	    if (!c_tree_equal (field, elt2->index)
+		|| !c_tree_equal (value, elt2->value))
+	      return false;
+	  }
+      }
+      return true;
+
+    case TREE_LIST:
+      if (!c_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)))
+	return false;
+      if (!c_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2)))
+	return false;
+      return c_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2));
+
+    case SAVE_EXPR:
+      return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+
+    case CALL_EXPR:
+      {
+	tree arg1, arg2;
+	call_expr_arg_iterator iter1, iter2;
+	if (!c_tree_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
+	  return false;
+	for (arg1 = first_call_expr_arg (t1, &iter1),
+	       arg2 = first_call_expr_arg (t2, &iter2);
+	     arg1 && arg2;
+	     arg1 = next_call_expr_arg (&iter1),
+	       arg2 = next_call_expr_arg (&iter2))
+	  if (!c_tree_equal (arg1, arg2))
+	    return false;
+	if (arg1 || arg2)
+	  return false;
+	return true;
+      }
+
+    case TARGET_EXPR:
+      {
+	tree o1 = TREE_OPERAND (t1, 0);
+	tree o2 = TREE_OPERAND (t2, 0);
+
+	/* Special case: if either target is an unallocated VAR_DECL,
+	   it means that it's going to be unified with whatever the
+	   TARGET_EXPR is really supposed to initialize, so treat it
+	   as being equivalent to anything.  */
+	if (TREE_CODE (o1) == VAR_DECL && DECL_NAME (o1) == NULL_TREE
+	    && !DECL_RTL_SET_P (o1))
+	  /*Nop*/;
+	else if (TREE_CODE (o2) == VAR_DECL && DECL_NAME (o2) == NULL_TREE
+		 && !DECL_RTL_SET_P (o2))
+	  /*Nop*/;
+	else if (!c_tree_equal (o1, o2))
+	  return false;
+
+	return c_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+      }
+
+    case COMPONENT_REF:
+      if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1))
+	return false;
+      return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+
+    case PARM_DECL:
+    case VAR_DECL:
+    case CONST_DECL:
+    case FIELD_DECL:
+    case FUNCTION_DECL:
+    case IDENTIFIER_NODE:
+    case SSA_NAME:
+      return false;
+
+    case TREE_VEC:
+      {
+	unsigned ix;
+	if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2))
+	  return false;
+	for (ix = TREE_VEC_LENGTH (t1); ix--;)
+	  if (!c_tree_equal (TREE_VEC_ELT (t1, ix),
+			     TREE_VEC_ELT (t2, ix)))
+	    return false;
+	return true;
+      }
+
+    default:
+      break;
+    }
+
+  switch (TREE_CODE_CLASS (code1))
+    {
+    case tcc_unary:
+    case tcc_binary:
+    case tcc_comparison:
+    case tcc_expression:
+    case tcc_vl_exp:
+    case tcc_reference:
+    case tcc_statement:
+      {
+	int i, n = TREE_OPERAND_LENGTH (t1);
+
+	switch (code1)
+	  {
+	  case PREINCREMENT_EXPR:
+	  case PREDECREMENT_EXPR:
+	  case POSTINCREMENT_EXPR:
+	  case POSTDECREMENT_EXPR:
+	    n = 1;
+	    break;
+	  case ARRAY_REF:
+	    n = 2;
+	    break;
+	  default:
+	    break;
+	  }
+
+	if (TREE_CODE_CLASS (code1) == tcc_vl_exp
+	    && n != TREE_OPERAND_LENGTH (t2))
+	  return false;
+
+	for (i = 0; i < n; ++i)
+	  if (!c_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i)))
+	    return false;
+
+	return true;
+      }
+
+    case tcc_type:
+      return comptypes (t1, t2);
+    default:
+      gcc_unreachable ();
+    }
+  /* We can get here with --disable-checking.  */
+  return false;
+}