--- gcc/c-family/c-pragma.h.jj	2022-09-24 09:07:28.031761154 +0200
+++ gcc/c-family/c-pragma.h	2022-09-24 11:07:05.875000478 +0200
@@ -45,8 +45,11 @@ enum pragma_kind {
   /* PRAGMA_OMP__START_ should be equal to the first PRAGMA_OMP_* code.  */
   PRAGMA_OMP_ALLOCATE,
   PRAGMA_OMP__START_ = PRAGMA_OMP_ALLOCATE,
+  PRAGMA_OMP_ASSUME,
+  PRAGMA_OMP_ASSUMES,
   PRAGMA_OMP_ATOMIC,
   PRAGMA_OMP_BARRIER,
+  PRAGMA_OMP_BEGIN,
   PRAGMA_OMP_CANCEL,
   PRAGMA_OMP_CANCELLATION_POINT,
   PRAGMA_OMP_CRITICAL,
@@ -54,7 +57,7 @@ enum pragma_kind {
   PRAGMA_OMP_DEPOBJ,
   PRAGMA_OMP_DISTRIBUTE,
   PRAGMA_OMP_ERROR,
-  PRAGMA_OMP_END_DECLARE_TARGET,
+  PRAGMA_OMP_END,
   PRAGMA_OMP_FLUSH,
   PRAGMA_OMP_FOR,
   PRAGMA_OMP_LOOP,
--- gcc/c-family/c-pragma.cc.jj	2022-09-24 09:07:28.010761444 +0200
+++ gcc/c-family/c-pragma.cc	2022-09-24 11:07:05.876000464 +0200
@@ -1546,14 +1546,16 @@ static const struct omp_pragma_def oacc_
 };
 static const struct omp_pragma_def omp_pragmas[] = {
   { "allocate", PRAGMA_OMP_ALLOCATE },
+  { "assumes", PRAGMA_OMP_ASSUMES },
   { "atomic", PRAGMA_OMP_ATOMIC },
   { "barrier", PRAGMA_OMP_BARRIER },
+  { "begin", PRAGMA_OMP_BEGIN },
   { "cancel", PRAGMA_OMP_CANCEL },
   { "cancellation", PRAGMA_OMP_CANCELLATION_POINT },
   { "critical", PRAGMA_OMP_CRITICAL },
   { "depobj", PRAGMA_OMP_DEPOBJ },
   { "error", PRAGMA_OMP_ERROR },
-  { "end", PRAGMA_OMP_END_DECLARE_TARGET },
+  { "end", PRAGMA_OMP_END },
   { "flush", PRAGMA_OMP_FLUSH },
   { "nothing", PRAGMA_OMP_NOTHING },
   { "requires", PRAGMA_OMP_REQUIRES },
@@ -1568,6 +1570,7 @@ static const struct omp_pragma_def omp_p
   { "threadprivate", PRAGMA_OMP_THREADPRIVATE }
 };
 static const struct omp_pragma_def omp_pragmas_simd[] = {
+  { "assume", PRAGMA_OMP_ASSUME },
   { "declare", PRAGMA_OMP_DECLARE },
   { "distribute", PRAGMA_OMP_DISTRIBUTE },
   { "for", PRAGMA_OMP_FOR },
--- gcc/c-family/c-common.h.jj	2022-09-24 09:07:50.533450215 +0200
+++ gcc/c-family/c-common.h	2022-09-24 11:07:05.875000478 +0200
@@ -1286,6 +1286,7 @@ struct c_omp_directive {
   bool simd;
 };
 
+extern const struct c_omp_directive c_omp_directives[];
 extern const struct c_omp_directive *c_omp_categorize_directive (const char *,
 								 const char *,
 								 const char *);
--- gcc/c-family/c-omp.cc.jj	2022-09-24 09:07:27.974761942 +0200
+++ gcc/c-family/c-omp.cc	2022-09-24 11:07:05.876000464 +0200
@@ -3097,21 +3097,21 @@ c_omp_adjust_map_clauses (tree clauses,
     }
 }
 
-static const struct c_omp_directive omp_directives[] = {
+const struct c_omp_directive c_omp_directives[] = {
   /* Keep this alphabetically sorted by the first word.  Non-null second/third
      if any should precede null ones.  */
   { "allocate", nullptr, nullptr, PRAGMA_OMP_ALLOCATE,
     C_OMP_DIR_DECLARATIVE, false },
-  /* { "assume", nullptr, nullptr, PRAGMA_OMP_ASSUME,
-    C_OMP_DIR_INFORMATIONAL, false }, */
-  /* { "assumes", nullptr, nullptr, PRAGMA_OMP_ASSUMES,
-    C_OMP_DIR_INFORMATIONAL, false }, */
+  { "assume", nullptr, nullptr, PRAGMA_OMP_ASSUME,
+    C_OMP_DIR_INFORMATIONAL, false },
+  { "assumes", nullptr, nullptr, PRAGMA_OMP_ASSUMES,
+    C_OMP_DIR_INFORMATIONAL, false },
   { "atomic", nullptr, nullptr, PRAGMA_OMP_ATOMIC,
     C_OMP_DIR_CONSTRUCT, false },
   { "barrier", nullptr, nullptr, PRAGMA_OMP_BARRIER,
     C_OMP_DIR_STANDALONE, false },
-  /* { "begin", "assumes", nullptr, PRAGMA_OMP_BEGIN,
-    C_OMP_DIR_INFORMATIONAL, false }, */
+  { "begin", "assumes", nullptr, PRAGMA_OMP_BEGIN,
+    C_OMP_DIR_INFORMATIONAL, false },
   /* { "begin", "declare", "target", PRAGMA_OMP_BEGIN,
     C_OMP_DIR_DECLARATIVE, false }, */
   /* { "begin", "declare", "variant", PRAGMA_OMP_BEGIN,
@@ -3140,9 +3140,9 @@ static const struct c_omp_directive omp_
     C_OMP_DIR_CONSTRUCT, false },  */
   { "distribute", nullptr, nullptr, PRAGMA_OMP_DISTRIBUTE,
     C_OMP_DIR_CONSTRUCT, true },
-  /* { "end", "assumes", nullptr, PRAGMA_OMP_END,
-    C_OMP_DIR_INFORMATIONAL, false }, */
-  { "end", "declare", "target", PRAGMA_OMP_END_DECLARE_TARGET,
+  { "end", "assumes", nullptr, PRAGMA_OMP_END,
+    C_OMP_DIR_INFORMATIONAL, false },
+  { "end", "declare", "target", PRAGMA_OMP_END,
     C_OMP_DIR_DECLARATIVE, false },
   /* { "end", "declare", "variant", PRAGMA_OMP_END,
     C_OMP_DIR_DECLARATIVE, false }, */
@@ -3224,26 +3224,26 @@ const struct c_omp_directive *
 c_omp_categorize_directive (const char *first, const char *second,
 			    const char *third)
 {
-  const size_t n_omp_directives = ARRAY_SIZE (omp_directives);
+  const size_t n_omp_directives = ARRAY_SIZE (c_omp_directives);
   for (size_t i = 0; i < n_omp_directives; i++)
     {
-      if ((unsigned char) omp_directives[i].first[0]
+      if ((unsigned char) c_omp_directives[i].first[0]
 	  < (unsigned char) first[0])
 	continue;
-      if ((unsigned char) omp_directives[i].first[0]
+      if ((unsigned char) c_omp_directives[i].first[0]
 	  > (unsigned char) first[0])
 	break;
-      if (strcmp (omp_directives[i].first, first))
+      if (strcmp (c_omp_directives[i].first, first))
 	continue;
-      if (!omp_directives[i].second)
-	return &omp_directives[i];
-      if (!second || strcmp (omp_directives[i].second, second))
+      if (!c_omp_directives[i].second)
+	return &c_omp_directives[i];
+      if (!second || strcmp (c_omp_directives[i].second, second))
 	continue;
-      if (!omp_directives[i].third)
-	return &omp_directives[i];
-      if (!third || strcmp (omp_directives[i].third, third))
+      if (!c_omp_directives[i].third)
+	return &c_omp_directives[i];
+      if (!third || strcmp (c_omp_directives[i].third, third))
 	continue;
-      return &omp_directives[i];
+      return &c_omp_directives[i];
     }
   return NULL;
 }
--- gcc/c/c-lang.h.jj	2022-01-11 23:11:21.627300876 +0100
+++ gcc/c/c-lang.h	2022-09-24 11:16:42.771143910 +0200
@@ -63,5 +63,8 @@ struct GTY(()) language_function {
 /* If non-zero, implicit "omp declare target" attribute is added into the
    attribute lists.  */
 extern GTY(()) int current_omp_declare_target_attribute;
+/* Similarly whether we are in between #pragma omp begin assumes and
+   #pragma omp end assumes (and how many times when nested).  */
+extern GTY(()) int current_omp_begin_assumes;
 
 #endif /* ! GCC_C_LANG_H */
--- gcc/c/c-parser.cc.jj	2022-09-24 09:07:28.079760491 +0200
+++ gcc/c/c-parser.cc	2022-09-26 17:25:10.534079629 +0200
@@ -71,6 +71,7 @@ along with GCC; see the file COPYING3.
 #include "tree-pretty-print.h"
 #include "memmodel.h"
 #include "c-family/known-headers.h"
+#include "bitmap.h"
 
 /* We need to walk over decls with incomplete struct/union/enum types
    after parsing the whole translation unit.
@@ -1594,10 +1595,13 @@ enum pragma_context { pragma_external, p
 static bool c_parser_pragma (c_parser *, enum pragma_context, bool *);
 static bool c_parser_omp_cancellation_point (c_parser *, enum pragma_context);
 static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *);
-static void c_parser_omp_end_declare_target (c_parser *);
+static void c_parser_omp_begin (c_parser *);
+static void c_parser_omp_end (c_parser *);
 static bool c_parser_omp_declare (c_parser *, enum pragma_context);
 static void c_parser_omp_requires (c_parser *);
 static bool c_parser_omp_error (c_parser *, enum pragma_context);
+static void c_parser_omp_assumption_clauses (c_parser *, bool);
+static void c_parser_omp_assumes (c_parser *);
 static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *);
 static void c_parser_oacc_routine (c_parser *, enum pragma_context);
 
@@ -1678,6 +1682,13 @@ c_parser_translation_unit (c_parser *par
 	       "%<#pragma omp end declare target%>");
       current_omp_declare_target_attribute = 0;
     }
+  if (current_omp_begin_assumes)
+    {
+      if (!errorcount)
+	error ("%<#pragma omp begin assumes%> without corresponding "
+	       "%<#pragma omp end assumes%>");
+      current_omp_begin_assumes = 0;
+    }
 }
 
 /* Parse an external declaration (C90 6.7, C99 6.9, C11 6.9).
@@ -12594,8 +12605,12 @@ c_parser_pragma (c_parser *parser, enum
     case PRAGMA_OMP_TARGET:
       return c_parser_omp_target (parser, context, if_p);
 
-    case PRAGMA_OMP_END_DECLARE_TARGET:
-      c_parser_omp_end_declare_target (parser);
+    case PRAGMA_OMP_BEGIN:
+      c_parser_omp_begin (parser);
+      return false;
+
+    case PRAGMA_OMP_END:
+      c_parser_omp_end (parser);
       return false;
 
     case PRAGMA_OMP_SCAN:
@@ -12619,13 +12634,26 @@ c_parser_pragma (c_parser *parser, enum
       if (context != pragma_external)
 	{
 	  error_at (c_parser_peek_token (parser)->location,
-		    "%<#pragma omp requires%> may only be used at file scope");
+		    "%<#pragma %s%> may only be used at file scope",
+		    "omp requires");
 	  c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
 	  return false;
 	}
       c_parser_omp_requires (parser);
       return false;
 
+    case PRAGMA_OMP_ASSUMES:
+      if (context != pragma_external)
+	{
+	  error_at (c_parser_peek_token (parser)->location,
+		    "%<#pragma %s%> may only be used at file scope",
+		    "omp assumes");
+	  c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+	  return false;
+	}
+      c_parser_omp_assumes (parser);
+      return false;
+
     case PRAGMA_OMP_NOTHING:
       c_parser_omp_nothing (parser);
       return false;
@@ -22405,14 +22433,44 @@ c_parser_omp_declare_target (c_parser *p
 		"directive with only %<device_type%> clauses ignored");
 }
 
+/* OpenMP 5.1
+   #pragma omp begin assumes clauses[optseq] new-line  */
+
 static void
-c_parser_omp_end_declare_target (c_parser *parser)
+c_parser_omp_begin (c_parser *parser)
+{
+  const char *p = "";
+  c_parser_consume_pragma (parser);
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+  if (strcmp (p, "assumes") == 0)
+    {
+      c_parser_consume_token (parser);
+      c_parser_omp_assumption_clauses (parser, false);
+      current_omp_begin_assumes++;
+    }
+  else
+    {
+      c_parser_error (parser, "expected %<assumes%>");
+      c_parser_skip_to_pragma_eol (parser);
+    }
+}
+
+/* OpenMP 4.0
+   #pragma omp end declare target
+
+   OpenMP 5.1
+   #pragma omp end assumes  */
+
+static void
+c_parser_omp_end (c_parser *parser)
 {
   location_t loc = c_parser_peek_token (parser)->location;
+  const char *p = "";
   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)
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+  if (strcmp (p, "declare") == 0)
     {
       c_parser_consume_token (parser);
       if (c_parser_next_token_is (parser, CPP_NAME)
@@ -22425,22 +22483,30 @@ c_parser_omp_end_declare_target (c_parse
 	  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--;
     }
-  else
+  else if (strcmp (p, "assumes") == 0)
     {
-      c_parser_error (parser, "expected %<declare%>");
+      c_parser_consume_token (parser);
       c_parser_skip_to_pragma_eol (parser);
-      return;
+      if (!current_omp_begin_assumes)
+	error_at (loc, "%<#pragma omp end assumes%> without "
+		       "corresponding %<#pragma omp begin assumes%>");
+      else
+	current_omp_begin_assumes--;
     }
-  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--;
+    {
+      c_parser_error (parser, "expected %<declare%> or %<assumes%>");
+      c_parser_skip_to_pragma_eol (parser);
+    }
 }
 
-
 /* OpenMP 4.0
    #pragma omp declare reduction (reduction-id : typename-list : expression) \
       initializer-clause[opt] new-line
@@ -23299,6 +23365,211 @@ c_parser_omp_error (c_parser *parser, en
   return false;
 }
 
+/* Assumption clauses:
+   OpenMP 5.1
+   absent (directive-name-list)
+   contains (directive-name-list)
+   holds (expression)
+   no_openmp
+   no_openmp_routines
+   no_parallelism  */
+
+static void
+c_parser_omp_assumption_clauses (c_parser *parser, bool is_assume)
+{
+  bool first = true;
+  bool no_openmp = false;
+  bool no_openmp_routines = false;
+  bool no_parallelism = false;
+  bitmap_head absent_head, contains_head;
+
+  bitmap_obstack_initialize (NULL);
+  bitmap_initialize (&absent_head, &bitmap_default_obstack);
+  bitmap_initialize (&contains_head, &bitmap_default_obstack);
+
+  if (c_parser_next_token_is (parser, CPP_PRAGMA_EOL))
+    error_at (c_parser_peek_token (parser)->location,
+	      "expected at least one assumption clause");
+
+  while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+    {
+      if (!first
+	  && c_parser_next_token_is (parser, CPP_COMMA)
+	  && c_parser_peek_2nd_token (parser)->type == CPP_NAME)
+	c_parser_consume_token (parser);
+
+      first = false;
+
+      if (!c_parser_next_token_is (parser, CPP_NAME))
+	break;
+
+      const char *p
+	= IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      location_t cloc = c_parser_peek_token (parser)->location;
+
+      if (!strcmp (p, "no_openmp"))
+	{
+	  c_parser_consume_token (parser);
+	  if (no_openmp)
+	    error_at (cloc, "too many %qs clauses", "no_openmp");
+	  no_openmp = true;
+	}
+      else if (!strcmp (p, "no_openmp_routines"))
+	{
+	  c_parser_consume_token (parser);
+	  if (no_openmp_routines)
+	    error_at (cloc, "too many %qs clauses", "no_openmp_routines");
+	  no_openmp_routines = true;
+	}
+      else if (!strcmp (p, "no_parallelism"))
+	{
+	  c_parser_consume_token (parser);
+	  if (no_parallelism)
+	    error_at (cloc, "too many %qs clauses", "no_parallelism");
+	  no_parallelism = true;
+	}
+      else if (!strcmp (p, "holds"))
+	{
+	  c_parser_consume_token (parser);
+	  matching_parens parens;
+	  if (parens.require_open (parser))
+	    {
+	      location_t eloc = c_parser_peek_token (parser)->location;
+	      c_expr expr = c_parser_expr_no_commas (parser, NULL);
+	      tree t = convert_lvalue_to_rvalue (eloc, expr, true, true).value;
+	      t = c_objc_common_truthvalue_conversion (eloc, t);
+	      t = c_fully_fold (t, false, NULL);
+	      if (is_assume)
+		{
+		  /* FIXME: Emit .ASSUME (t) call here.  */
+		  (void) t;
+		}
+	      parens.skip_until_found_close (parser);
+	    }
+	}
+      else if (!strcmp (p, "absent") || !strcmp (p, "contains"))
+	{
+	  c_parser_consume_token (parser);
+	  matching_parens parens;
+	  if (parens.require_open (parser))
+	    {
+	      do
+		{
+		  const char *directive[3] = {};
+		  int i;
+		  location_t dloc = c_parser_peek_token (parser)->location;
+		  for (i = 0; i < 3; i++)
+		    {
+		      tree id;
+		      if (c_parser_peek_nth_token (parser, i + 1)->type
+			  == CPP_NAME)
+			id = c_parser_peek_nth_token (parser, i + 1)->value;
+		      else if (c_parser_peek_nth_token (parser, i + 1)->keyword
+			       != RID_MAX)
+			{
+			  enum rid rid
+			    = c_parser_peek_nth_token (parser, i + 1)->keyword;
+			  id = ridpointers[rid];
+			}
+		      else
+			break;
+		      directive[i] = IDENTIFIER_POINTER (id);
+		    }
+		  if (i == 0)
+		    error_at (dloc, "expected directive name");
+		  else
+		    {
+		      const struct c_omp_directive *dir
+			= c_omp_categorize_directive (directive[0],
+						      directive[1],
+						      directive[2]);
+		      if (dir == NULL
+			  || dir->kind == C_OMP_DIR_DECLARATIVE
+			  || dir->kind == C_OMP_DIR_INFORMATIONAL
+			  || dir->id == PRAGMA_OMP_END
+			  || (!dir->second && directive[1])
+			  || (!dir->third && directive[2]))
+			error_at (dloc, "unknown OpenMP directive name in "
+					"%qs clause argument", p);
+		      else
+			{
+			  int id = dir - c_omp_directives;
+			  if (bitmap_bit_p (p[0] == 'a' ? &contains_head
+							: &absent_head, id))
+			    error_at (dloc, "%<%s%s%s%s%s%> directive "
+					    "mentioned in both %<absent%> and "
+					    "%<contains%> clauses",
+				      directive[0],
+				      directive[1] ? " " : "",
+				      directive[1] ? directive[1] : "",
+				      directive[2] ? " " : "",
+				      directive[2] ? directive[2] : "");
+			  else if (!bitmap_set_bit (p[0] == 'a'
+						    ? &absent_head
+						    : &contains_head, id))
+			    error_at (dloc, "%<%s%s%s%s%s%> directive "
+					    "mentioned multiple times in %qs "
+					    "clauses",
+				      directive[0],
+				      directive[1] ? " " : "",
+				      directive[1] ? directive[1] : "",
+				      directive[2] ? " " : "",
+				      directive[2] ? directive[2] : "", p);
+			}
+		      for (; i; --i)
+			c_parser_consume_token (parser);
+		    }
+		  if (c_parser_next_token_is (parser, CPP_COMMA))
+		    c_parser_consume_token (parser);
+		  else
+		    break;
+		}
+	      while (1);
+	      parens.skip_until_found_close (parser);
+	    }
+	}
+      else if (startswith (p, "ext_"))
+	{
+	  warning_at (cloc, 0, "unknown assumption clause %qs", p);
+	  c_parser_consume_token (parser);
+	  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+	    {
+	      matching_parens parens;
+	      parens.consume_open (parser);
+	      c_parser_balanced_token_sequence (parser);
+	      parens.require_close (parser);
+	    }
+	}
+      else
+	{
+	  c_parser_consume_token (parser);
+	  error_at (cloc, "expected assumption clause");
+	  break;
+	}
+    }
+  c_parser_skip_to_pragma_eol (parser);
+}
+
+/* OpenMP 5.1
+   #pragma omp assume clauses[optseq] new-line  */
+
+static void
+c_parser_omp_assume (c_parser *parser, bool *if_p)
+{
+  c_parser_omp_assumption_clauses (parser, true);
+  add_stmt (c_parser_omp_structured_block (parser, if_p));
+}
+
+/* OpenMP 5.1
+   #pragma omp assumes clauses[optseq] new-line  */
+
+static void
+c_parser_omp_assumes (c_parser *parser)
+{
+  c_parser_consume_pragma (parser);
+  c_parser_omp_assumption_clauses (parser, false);
+}
+
 /* Main entry point to parsing most OpenMP pragmas.  */
 
 static void
@@ -23404,6 +23675,9 @@ c_parser_omp_construct (c_parser *parser
       strcpy (p_name, "#pragma omp");
       stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL, if_p);
       break;
+    case PRAGMA_OMP_ASSUME:
+      c_parser_omp_assume (parser, if_p);
+      return;
     default:
       gcc_unreachable ();
     }
--- gcc/c/c-decl.cc.jj	2022-09-16 20:40:13.526835296 +0200
+++ gcc/c/c-decl.cc	2022-09-24 11:17:55.048155042 +0200
@@ -156,6 +156,10 @@ static bool undef_nested_function;
 /* If non-zero, implicit "omp declare target" attribute is added into the
    attribute lists.  */
 int current_omp_declare_target_attribute;
+
+/* If non-zero, we are inside of
+   #pragma omp begin assumes ... #pragma omp end assumes region.  */
+int current_omp_begin_assumes;
 
 /* Each c_binding structure describes one binding of an identifier to
    a decl.  All the decls in a scope - irrespective of namespace - are
--- gcc/cp/cp-tree.h.jj	2022-09-24 09:07:50.647448640 +0200
+++ gcc/cp/cp-tree.h	2022-09-26 12:39:34.996659905 +0200
@@ -1834,6 +1834,10 @@ struct GTY(()) omp_declare_target_attr {
   bool attr_syntax;
 };
 
+struct GTY(()) omp_begin_assumes_data {
+  bool attr_syntax;
+};
+
 /* Global state.  */
 
 struct GTY(()) saved_scope {
@@ -1881,6 +1885,7 @@ struct GTY(()) saved_scope {
 
   hash_map<tree, tree> *GTY((skip)) x_local_specializations;
   vec<omp_declare_target_attr, va_gc> *omp_declare_target_attribute;
+  vec<omp_begin_assumes_data, va_gc> *omp_begin_assumes;
 
   struct saved_scope *prev;
 };
--- gcc/cp/parser.cc.jj	2022-09-24 09:07:50.688448074 +0200
+++ gcc/cp/parser.cc	2022-09-26 17:26:46.152798472 +0200
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3.
 #include "cp-name-hint.h"
 #include "memmodel.h"
 #include "c-family/known-headers.h"
+#include "bitmap.h"
 
 
 /* The lexer.  */
@@ -46018,6 +46019,218 @@ cp_parser_omp_context_selector_specifica
   return nreverse (ret);
 }
 
+/* Assumption clauses:
+   OpenMP 5.1
+   absent (directive-name-list)
+   contains (directive-name-list)
+   holds (expression)
+   no_openmp
+   no_openmp_routines
+   no_parallelism  */
+
+static void
+cp_parser_omp_assumption_clauses (cp_parser *parser, cp_token *pragma_tok,
+				  bool is_assume)
+{
+  bool first = true;
+  bool no_openmp = false;
+  bool no_openmp_routines = false;
+  bool no_parallelism = false;
+  bitmap_head absent_head, contains_head;
+
+  bitmap_obstack_initialize (NULL);
+  bitmap_initialize (&absent_head, &bitmap_default_obstack);
+  bitmap_initialize (&contains_head, &bitmap_default_obstack);
+
+  if (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA_EOL))
+    error_at (cp_lexer_peek_token (parser->lexer)->location,
+	      "expected at least one assumption clause");
+
+  while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
+    {
+      /* For now only in C++ attributes, do it always for OpenMP 5.1.  */
+      if ((!first || parser->lexer->in_omp_attribute_pragma)
+	  && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
+	  && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
+	cp_lexer_consume_token (parser->lexer);
+
+      first = false;
+
+      if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+	break;
+
+      const char *p
+	= IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value);
+      location_t cloc = cp_lexer_peek_token (parser->lexer)->location;
+
+      if (!strcmp (p, "no_openmp"))
+	{
+	  cp_lexer_consume_token (parser->lexer);
+	  if (no_openmp)
+	    error_at (cloc, "too many %qs clauses", "no_openmp");
+	  no_openmp = true;
+	}
+      else if (!strcmp (p, "no_openmp_routines"))
+	{
+	  cp_lexer_consume_token (parser->lexer);
+	  if (no_openmp_routines)
+	    error_at (cloc, "too many %qs clauses", "no_openmp_routines");
+	  no_openmp_routines = true;
+	}
+      else if (!strcmp (p, "no_parallelism"))
+	{
+	  cp_lexer_consume_token (parser->lexer);
+	  if (no_parallelism)
+	    error_at (cloc, "too many %qs clauses", "no_parallelism");
+	  no_parallelism = true;
+	}
+      else if (!strcmp (p, "holds"))
+	{
+	  cp_lexer_consume_token (parser->lexer);
+	  matching_parens parens;
+	  if (parens.require_open (parser))
+	    {
+	      tree t = cp_parser_assignment_expression (parser);
+	      if (!type_dependent_expression_p (t))
+		t = contextual_conv_bool (t, tf_warning_or_error);
+	      if (is_assume)
+		{
+		  /* FIXME: Emit .ASSUME (t) call here.  */
+		  (void) t;
+		}
+	      if (!parens.require_close (parser))
+		cp_parser_skip_to_closing_parenthesis (parser,
+						       /*recovering=*/true,
+						       /*or_comma=*/false,
+						       /*consume_paren=*/true);
+	    }
+	}
+      else if (!strcmp (p, "absent") || !strcmp (p, "contains"))
+	{
+	  cp_lexer_consume_token (parser->lexer);
+	  matching_parens parens;
+	  if (parens.require_open (parser))
+	    {
+	      do
+		{
+		  const char *directive[3] = {};
+		  int i;
+		  location_t dloc
+		    = cp_lexer_peek_token (parser->lexer)->location;
+		  for (i = 0; i < 3; i++)
+		    {
+		      tree id;
+		      if (cp_lexer_nth_token_is (parser->lexer, i + 1, CPP_NAME))
+			id = cp_lexer_peek_nth_token (parser->lexer,
+						      i + 1)->u.value;
+		      else if (cp_lexer_nth_token_is (parser->lexer, i + 1,
+						      CPP_KEYWORD))
+			{
+			  enum rid rid
+			    = cp_lexer_peek_nth_token (parser->lexer,
+						       i + 1)->keyword;
+			  id = ridpointers[rid];
+			}
+		      else
+			break;
+		      directive[i] = IDENTIFIER_POINTER (id);
+		    }
+		  if (i == 0)
+		    error_at (dloc, "expected directive name");
+		  else
+		    {
+		      const struct c_omp_directive *dir
+			= c_omp_categorize_directive (directive[0],
+						      directive[1],
+						      directive[2]);
+		      if (dir == NULL
+			  || dir->kind == C_OMP_DIR_DECLARATIVE
+			  || dir->kind == C_OMP_DIR_INFORMATIONAL
+			  || dir->id == PRAGMA_OMP_END
+			  || (!dir->second && directive[1])
+			  || (!dir->third && directive[2]))
+			error_at (dloc, "unknown OpenMP directive name in "
+					"%qs clause argument", p);
+		      else
+			{
+			  int id = dir - c_omp_directives;
+			  if (bitmap_bit_p (p[0] == 'a' ? &contains_head
+							: &absent_head, id))
+			    error_at (dloc, "%<%s%s%s%s%s%> directive "
+					    "mentioned in both %<absent%> and "
+					    "%<contains%> clauses",
+				      directive[0],
+				      directive[1] ? " " : "",
+				      directive[1] ? directive[1] : "",
+				      directive[2] ? " " : "",
+				      directive[2] ? directive[2] : "");
+			  else if (!bitmap_set_bit (p[0] == 'a'
+						    ? &absent_head
+						    : &contains_head, id))
+			    error_at (dloc, "%<%s%s%s%s%s%> directive "
+					    "mentioned multiple times in %qs "
+					    "clauses",
+				      directive[0],
+				      directive[1] ? " " : "",
+				      directive[1] ? directive[1] : "",
+				      directive[2] ? " " : "",
+				      directive[2] ? directive[2] : "", p);
+			}
+		      for (; i; --i)
+			cp_lexer_consume_token (parser->lexer);
+		    }
+		  if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+		    cp_lexer_consume_token (parser->lexer);
+		  else
+		    break;
+		}
+	      while (1);
+	      if (!parens.require_close (parser))
+		cp_parser_skip_to_closing_parenthesis (parser,
+						       /*recovering=*/true,
+						       /*or_comma=*/false,
+						       /*consume_paren=*/true);
+	    }
+	}
+      else if (startswith (p, "ext_"))
+	{
+	  warning_at (cloc, 0, "unknown assumption clause %qs", p);
+	  cp_lexer_consume_token (parser->lexer);
+	  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+	    for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 1;
+		 n; --n)
+	      cp_lexer_consume_token (parser->lexer);
+	}
+      else
+	{
+	  cp_lexer_consume_token (parser->lexer);
+	  error_at (cloc, "expected assumption clause");
+	  break;
+	}
+    }
+  cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+}
+
+/* OpenMP 5.1
+   # pragma omp assume clauses[optseq] new-line  */
+
+static void
+cp_parser_omp_assume (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
+{
+  cp_parser_omp_assumption_clauses (parser, pragma_tok, true);
+  add_stmt (cp_parser_omp_structured_block (parser, if_p));
+}
+
+/* OpenMP 5.1
+   # pragma omp assumes clauses[optseq] new-line  */
+
+static bool
+cp_parser_omp_assumes (cp_parser *parser, cp_token *pragma_tok)
+{
+  cp_parser_omp_assumption_clauses (parser, pragma_tok, false);
+  return false;
+}
+
 /* Finalize #pragma omp declare variant after a fndecl has been parsed, and put
    that into "omp declare variant base" attribute.  */
 
@@ -46467,8 +46680,41 @@ cp_parser_omp_declare_target (cp_parser
 		"directive with only %<device_type%> clauses ignored");
 }
 
+/* OpenMP 5.1
+   #pragma omp begin assumes clauses[optseq] new-line  */
+
 static void
-cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok)
+cp_parser_omp_begin (cp_parser *parser, cp_token *pragma_tok)
+{
+  const char *p = "";
+  bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma;
+  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+    {
+      tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+      p = IDENTIFIER_POINTER (id);
+    }
+  if (strcmp (p, "assumes") == 0)
+    {
+      cp_lexer_consume_token (parser->lexer);
+      cp_parser_omp_assumption_clauses (parser, pragma_tok, false);
+      struct omp_begin_assumes_data a = { in_omp_attribute_pragma };
+      vec_safe_push (scope_chain->omp_begin_assumes, a);
+    }
+  else
+    {
+      cp_parser_error (parser, "expected %<assumes%>");
+      cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+    }
+}
+
+/* OpenMP 4.0:
+   # pragma omp end declare target new-line
+
+   OpenMP 5.1:
+   # pragma omp end assumes new-line  */
+
+static void
+cp_parser_omp_end (cp_parser *parser, cp_token *pragma_tok)
 {
   const char *p = "";
   bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma;
@@ -46494,34 +46740,59 @@ cp_parser_omp_end_declare_target (cp_par
 	  cp_parser_skip_to_pragma_eol (parser, pragma_tok);
 	  return;
 	}
+      cp_parser_require_pragma_eol (parser, pragma_tok);
+      if (!vec_safe_length (scope_chain->omp_declare_target_attribute))
+	error_at (pragma_tok->location,
+		  "%<#pragma omp end declare target%> without corresponding "
+		  "%<#pragma omp declare target%>");
+      else
+	{
+	  omp_declare_target_attr
+	    a = scope_chain->omp_declare_target_attribute->pop ();
+	  if (a.attr_syntax != in_omp_attribute_pragma)
+	    {
+	      if (a.attr_syntax)
+		error_at (pragma_tok->location,
+			  "%<declare target%> in attribute syntax terminated "
+			  "with %<end declare target%> in pragma syntax");
+	      else
+		error_at (pragma_tok->location,
+			  "%<declare target%> in pragma syntax terminated "
+			  "with %<end declare target%> in attribute syntax");
+	    }
+	}
+    }
+  else if (strcmp (p, "assumes") == 0)
+    {
+      cp_lexer_consume_token (parser->lexer);
+      cp_parser_require_pragma_eol (parser, pragma_tok);
+      if (!vec_safe_length (scope_chain->omp_begin_assumes))
+	error_at (pragma_tok->location,
+		  "%<#pragma omp end assumes%> without corresponding "
+		  "%<#pragma omp begin assumes%>");
+      else
+	{
+	  omp_begin_assumes_data
+	    a = scope_chain->omp_begin_assumes->pop ();
+	  if (a.attr_syntax != in_omp_attribute_pragma)
+	    {
+	      if (a.attr_syntax)
+		error_at (pragma_tok->location,
+			  "%<begin assumes%> in attribute syntax terminated "
+			  "with %<end assumes%> in pragma syntax");
+	      else
+		error_at (pragma_tok->location,
+			  "%<begin assumes%> in pragma syntax terminated "
+			  "with %<end assumes%> in attribute syntax");
+	    }
+	}
     }
   else
     {
-      cp_parser_error (parser, "expected %<declare%>");
+      cp_parser_error (parser, "expected %<declare%> or %<assumes%>");
       cp_parser_skip_to_pragma_eol (parser, pragma_tok);
       return;
     }
-  cp_parser_require_pragma_eol (parser, pragma_tok);
-  if (!vec_safe_length (scope_chain->omp_declare_target_attribute))
-    error_at (pragma_tok->location,
-	      "%<#pragma omp end declare target%> without corresponding "
-	      "%<#pragma omp declare target%>");
-  else
-    {
-      omp_declare_target_attr
-	a = scope_chain->omp_declare_target_attribute->pop ();
-      if (a.attr_syntax != in_omp_attribute_pragma)
-	{
-	  if (a.attr_syntax)
-	    error_at (pragma_tok->location,
-		      "%<declare target%> in attribute syntax terminated "
-		      "with %<end declare target%> in pragma syntax");
-	  else
-	    error_at (pragma_tok->location,
-		      "%<declare target%> in pragma syntax terminated "
-		      "with %<end declare target%> in attribute syntax");
-	}
-    }
 }
 
 /* Helper function of cp_parser_omp_declare_reduction.  Parse the combiner
@@ -47803,6 +48074,9 @@ cp_parser_omp_construct (cp_parser *pars
       stmt = cp_parser_omp_teams (parser, pragma_tok, p_name, mask, NULL,
 				  if_p);
       break;
+    case PRAGMA_OMP_ASSUME:
+      cp_parser_omp_assume (parser, pragma_tok, if_p);
+      return;
     default:
       gcc_unreachable ();
     }
@@ -48406,6 +48680,7 @@ cp_parser_pragma (cp_parser *parser, enu
     case PRAGMA_OACC_LOOP:
     case PRAGMA_OACC_PARALLEL:
     case PRAGMA_OACC_SERIAL:
+    case PRAGMA_OMP_ASSUME:
     case PRAGMA_OMP_ATOMIC:
     case PRAGMA_OMP_CRITICAL:
     case PRAGMA_OMP_DISTRIBUTE:
@@ -48440,6 +48715,17 @@ cp_parser_pragma (cp_parser *parser, enu
 	}
       return cp_parser_omp_requires (parser, pragma_tok);
 
+    case PRAGMA_OMP_ASSUMES:
+      if (context != pragma_external)
+	{
+	  error_at (pragma_tok->location,
+		    "%<#pragma omp assumes%> may only be used at file or "
+		    "namespace scope");
+	  ret = true;
+	  break;
+	}
+      return cp_parser_omp_assumes (parser, pragma_tok);
+
     case PRAGMA_OMP_NOTHING:
       cp_parser_omp_nothing (parser, pragma_tok);
       return false;
@@ -48463,8 +48749,12 @@ cp_parser_pragma (cp_parser *parser, enu
       pop_omp_privatization_clauses (stmt);
       return ret;
 
-    case PRAGMA_OMP_END_DECLARE_TARGET:
-      cp_parser_omp_end_declare_target (parser, pragma_tok);
+    case PRAGMA_OMP_BEGIN:
+      cp_parser_omp_begin (parser, pragma_tok);
+      return false;
+
+    case PRAGMA_OMP_END:
+      cp_parser_omp_end (parser, pragma_tok);
       return false;
 
     case PRAGMA_OMP_SCAN:
--- gcc/cp/pt.cc.jj	2022-09-23 09:02:31.224666847 +0200
+++ gcc/cp/pt.cc	2022-09-26 12:40:28.980934174 +0200
@@ -11945,6 +11945,7 @@ apply_late_template_attributes (tree *de
   auto o3 = make_temp_override (current_target_pragma, NULL_TREE);
   auto o4 = make_temp_override (scope_chain->omp_declare_target_attribute,
 				NULL);
+  auto o5 = make_temp_override (scope_chain->omp_begin_assumes, NULL);
 
   cplus_decl_attributes (decl_p, late_attrs, attr_flags);
 
--- gcc/cp/semantics.cc.jj	2022-09-24 09:07:50.691448032 +0200
+++ gcc/cp/semantics.cc	2022-09-26 12:41:14.075327965 +0200
@@ -3363,6 +3363,13 @@ finish_translation_unit (void)
 	       "%<#pragma omp end declare target%>");
       vec_safe_truncate (scope_chain->omp_declare_target_attribute, 0);
     }
+  if (vec_safe_length (scope_chain->omp_begin_assumes))
+    {
+      if (!errorcount)
+	error ("%<#pragma omp begin assumes%> without corresponding "
+	       "%<#pragma omp end assumes%>");
+      vec_safe_truncate (scope_chain->omp_begin_assumes, 0);
+    }
 }
 
 /* Finish a template type parameter, specified as AGGR IDENTIFIER.
--- gcc/testsuite/c-c++-common/gomp/assume-1.c.jj	2022-09-26 15:14:28.364091555 +0200
+++ gcc/testsuite/c-c++-common/gomp/assume-1.c	2022-09-26 15:26:27.277465276 +0200
@@ -0,0 +1,29 @@
+void
+foo (int i, int *a)
+{
+  #pragma omp assume no_openmp, absent (target, teams) holds (i < 32U) holds (i < 32U)
+  ;
+  #pragma omp assume no_openmp_routines, contains (simd)
+  {
+    #pragma omp simd
+    for (int j = 0; j < i; j++)
+      a[j] = j;
+  }
+  #pragma omp assume no_parallelism, contains (error)
+  {
+    if (i >= 32)
+      {
+	#pragma omp error at (execution) message ("Should not happen")
+      }
+  }
+  #pragma omp assume absent (for)
+  ;
+  #pragma omp assume absent (atomic, barrier, cancel, cancellation point) absent (critical, depobj)
+  ;
+  #pragma omp assume absent (distribute, flush, loop, masked, master, nothing, ordered)
+  ;
+  #pragma omp assume absent (parallel, scan, scope, section, sections, simd, single, task)
+  ;
+  #pragma omp assume absent (taskgroup, taskloop, taskwait, taskyield)
+  ;
+}
--- gcc/testsuite/c-c++-common/gomp/assume-2.c.jj	2022-09-26 15:16:25.857518323 +0200
+++ gcc/testsuite/c-c++-common/gomp/assume-2.c	2022-09-26 17:27:26.348259923 +0200
@@ -0,0 +1,46 @@
+void
+foo (int i, int *a)
+{
+  #pragma omp assume no_openmp no_openmp			/* { dg-error "too many 'no_openmp' clauses" } */
+  ;
+  #pragma omp assume no_openmp_routines, no_openmp_routines	/* { dg-error "too many 'no_openmp_routines' clauses" } */
+  ;
+  #pragma omp assume no_parallelism, no_parallelism		/* { dg-error "too many 'no_parallelism' clauses" } */
+  ;
+  #pragma omp assume absent (target, target)			/* { dg-error "'target' directive mentioned multiple times in 'absent' clauses" } */
+  ;
+  #pragma omp assume absent (target, teams) absent (teams, parallel)	/* { dg-error "'teams' directive mentioned multiple times in 'absent' clauses" } */
+  ;
+  #pragma omp assume contains (cancellation point, cancellation point)	/* { dg-error "'cancellation point' directive mentioned multiple times in 'contains' clauses" } */
+  ;
+  #pragma omp assume contains (target enter data, target exit data) contains (target exit data, parallel)	/* { dg-error "target exit data' directive mentioned multiple times in 'contains' clauses" } */
+  ;
+  #pragma omp assume absent (target enter data, target exit data) contains (target exit data, parallel)		/* { dg-error "'target exit data' directive mentioned in both 'absent' and 'contains' clauses" } */
+  ;
+  #pragma omp assume contains (target enter data, target exit data) absent (target enter data, parallel)	/* { dg-error "'target enter data' directive mentioned in both 'absent' and 'contains' clauses" } */
+  ;
+  #pragma omp assume contains (declare target)			/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+  ;
+  #pragma omp assume absent (parallel for simd)			/* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */
+  ;
+  #pragma omp assume contains (target parallel)			/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+  ;
+  #pragma omp assume absent (assume)				/* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */
+  ;
+  #pragma omp assume absent (assumes)				/* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */
+  ;
+  #pragma omp assume contains (begin assumes)			/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+  ;
+  #pragma omp assume contains (end assumes)			/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+  ;
+  #pragma omp assume contains (foo)				/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+  ;
+  #pragma omp assume absent (target enter something)		/* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */
+  ;
+  #pragma omp assume foobar					/* { dg-error "expected assumption clause" } */
+  ;
+  #pragma omp assume ext_GCC_foobarbaz, ext_GCC_baz (1, 12, 1 < 17), no_parallelism	/* { dg-warning "unknown assumption clause 'ext_GCC_foobarbaz'" } */
+  ;								/* { dg-warning "unknown assumption clause 'ext_GCC_baz'" "" { target *-*-* } .-1 } */
+  #pragma omp assume						/* { dg-error "expected at least one assumption clause" } */
+  ;
+}
--- gcc/testsuite/c-c++-common/gomp/assume-3.c.jj	2022-09-26 17:34:45.342378049 +0200
+++ gcc/testsuite/c-c++-common/gomp/assume-3.c	2022-09-26 17:37:05.792496230 +0200
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-options "-fno-openmp -fopenmp-simd" } */
+
+int i, j;
+
+int
+foo (void)
+{
+  j = 1;
+  return 1;
+}
+
+int
+main ()
+{
+  #pragma omp assume holds (i < 42)
+  ;
+  #pragma omp assume holds (++i == 1)
+  ;
+  if (i != 0)
+    __builtin_abort ();
+  #pragma omp assume holds (foo () == 1)
+  ;
+  if (j != 0)
+    __builtin_abort ();
+  return 0;
+}
--- gcc/testsuite/c-c++-common/gomp/assumes-1.c.jj	2022-09-26 16:26:29.271245995 +0200
+++ gcc/testsuite/c-c++-common/gomp/assumes-1.c	2022-09-26 16:56:35.985052013 +0200
@@ -0,0 +1,26 @@
+int i;
+
+#pragma omp assumes no_openmp, absent (target, teams) holds (i < 32U) holds (i < 32U)
+void
+bar (void)
+{
+}
+
+#pragma omp assumes no_openmp_routines
+
+#pragma omp assumes no_parallelism
+
+#pragma omp assumes absent (for)
+void
+fred (void)
+{
+}
+
+#pragma omp assumes absent (atomic, barrier, cancel, cancellation point) absent (critical, depobj) \
+		    absent (distribute, flush, loop, masked, master, nothing, ordered) \
+		    absent (parallel, scan, scope, section, sections, simd, single, task) \
+		    absent (taskgroup, taskloop, taskwait, taskyield)
+void
+foo (void)
+{
+}
--- gcc/testsuite/c-c++-common/gomp/assumes-2.c.jj	2022-09-26 16:26:33.066195182 +0200
+++ gcc/testsuite/c-c++-common/gomp/assumes-2.c	2022-09-26 17:27:53.924890428 +0200
@@ -0,0 +1,23 @@
+#pragma omp assumes no_openmp no_openmp				/* { dg-error "too many 'no_openmp' clauses" } */
+#pragma omp assumes no_openmp_routines, no_openmp_routines	/* { dg-error "too many 'no_openmp_routines' clauses" } */
+#pragma omp assumes no_parallelism, no_parallelism		/* { dg-error "too many 'no_parallelism' clauses" } */
+#pragma omp assumes absent (target, target)			/* { dg-error "'target' directive mentioned multiple times in 'absent' clauses" } */
+#pragma omp assumes absent (target, teams) absent (teams, parallel)	/* { dg-error "'teams' directive mentioned multiple times in 'absent' clauses" } */
+#pragma omp assumes contains (cancellation point, cancellation point)	/* { dg-error "'cancellation point' directive mentioned multiple times in 'contains' clauses" } */
+#pragma omp assumes contains (target enter data, target exit data) contains (target exit data, parallel)	/* { dg-error "target exit data' directive mentioned multiple times in 'contains' clauses" } */
+#pragma omp assumes absent (target enter data, target exit data) contains (target exit data, parallel)		/* { dg-error "'target exit data' directive mentioned in both 'absent' and 'contains' clauses" } */
+#pragma omp assumes contains (target enter data, target exit data) absent (target enter data, parallel)	/* { dg-error "'target enter data' directive mentioned in both 'absent' and 'contains' clauses" } */
+#pragma omp assumes contains (declare target)			/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+#pragma omp assumes absent (parallel for simd)			/* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */
+#pragma omp assumes contains (target parallel)			/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+#pragma omp assumes absent (assume)				/* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */
+#pragma omp assumes absent (assumes)				/* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */
+#pragma omp assumes contains (begin assumes)			/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+#pragma omp assumes contains (end assumes)			/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+#pragma omp assumes contains (foo)				/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+#pragma omp assumes absent (target enter something)		/* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */
+#pragma omp assumes foobar					/* { dg-error "expected assumption clause" } */
+#pragma omp assumes ext_GCC_foobarbaz, ext_GCC_baz (1, 12, 1 < 17), no_parallelism	/* { dg-warning "unknown assumption clause 'ext_GCC_foobarbaz'" } */
+								/* { dg-warning "unknown assumption clause 'ext_GCC_baz'" "" { target *-*-* } .-1 } */
+#pragma omp assumes						/* { dg-error "expected at least one assumption clause" } */
+int i;
--- gcc/testsuite/c-c++-common/gomp/assumes-3.c.jj	2022-09-26 16:36:25.073268965 +0200
+++ gcc/testsuite/c-c++-common/gomp/assumes-3.c	2022-09-26 16:43:17.178751397 +0200
@@ -0,0 +1,15 @@
+#pragma omp assumes contains (simd)
+#pragma omp assumes contains (error)
+#pragma omp assumes contains (simd)
+
+void
+foo (int i, int *a)
+{
+  #pragma omp simd
+  for (int j = 0; j < i; j++)
+    a[j] = j;
+  if (i >= 32)
+    {
+      #pragma omp error at (execution) message ("Should not happen")
+    }
+}
--- gcc/testsuite/c-c++-common/gomp/assumes-4.c.jj	2022-09-26 16:42:09.979651109 +0200
+++ gcc/testsuite/c-c++-common/gomp/assumes-4.c	2022-09-26 16:44:29.178787410 +0200
@@ -0,0 +1,6 @@
+void
+foo (void)
+{
+  #pragma omp assumes no_openmp		/* { dg-error "'#pragma omp assumes' may only be used at file scope" "" { target c } } */
+  ;					/* { dg-error "'#pragma omp assumes' may only be used at file or namespace scope" "" { target c++ } .-1 } */
+}
--- gcc/testsuite/c-c++-common/gomp/begin-assumes-1.c.jj	2022-09-26 15:14:45.395863505 +0200
+++ gcc/testsuite/c-c++-common/gomp/begin-assumes-1.c	2022-09-26 15:27:23.073718153 +0200
@@ -0,0 +1,46 @@
+int i;
+
+#pragma omp begin assumes no_openmp, absent (target, teams) holds (i < 32U) holds (i < 32U)
+void
+bar (void)
+{
+}
+#pragma omp end assumes
+
+#pragma omp begin assumes no_openmp_routines, contains (simd)
+void
+baz (int *a)
+{
+  #pragma omp simd
+  for (int j = 0; j < i; j++)
+    a[j] = j;
+}
+#pragma omp end assumes
+
+#pragma omp begin assumes no_parallelism, contains (error)
+void
+qux (void)
+{
+  if (i >= 32)
+    {
+      #pragma omp error at (execution) message ("Should not happen")
+    }
+}
+#pragma omp end assumes
+
+#pragma omp begin assumes absent (for)
+void
+fred (void)
+{
+}
+#pragma omp end assumes
+
+#pragma omp begin assumes absent (atomic, barrier, cancel, cancellation point) absent (critical, depobj) \
+			  absent (distribute, flush, loop, masked, master, nothing, ordered) \
+			  absent (parallel, scan, scope, section, sections, simd, single, task) \
+			  absent (taskgroup, taskloop, taskwait, taskyield)
+void
+foo (void)
+{
+}
+#pragma omp end assumes
--- gcc/testsuite/c-c++-common/gomp/begin-assumes-2.c.jj	2022-09-26 16:13:41.847520814 +0200
+++ gcc/testsuite/c-c++-common/gomp/begin-assumes-2.c	2022-09-26 17:28:34.184351014 +0200
@@ -0,0 +1,63 @@
+#pragma omp begin assumes no_openmp no_openmp			/* { dg-error "too many 'no_openmp' clauses" } */
+void f1 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes no_openmp_routines, no_openmp_routines	/* { dg-error "too many 'no_openmp_routines' clauses" } */
+void f2 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes no_parallelism, no_parallelism		/* { dg-error "too many 'no_parallelism' clauses" } */
+void f3 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes absent (target, target)			/* { dg-error "'target' directive mentioned multiple times in 'absent' clauses" } */
+void f4 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes absent (target, teams) absent (teams, parallel)	/* { dg-error "'teams' directive mentioned multiple times in 'absent' clauses" } */
+void f5 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes contains (cancellation point, cancellation point)	/* { dg-error "'cancellation point' directive mentioned multiple times in 'contains' clauses" } */
+void f6 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes contains (target enter data, target exit data) contains (target exit data, parallel)	/* { dg-error "target exit data' directive mentioned multiple times in 'contains' clauses" } */
+void f7 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes absent (target enter data, target exit data) contains (target exit data, parallel)		/* { dg-error "'target exit data' directive mentioned in both 'absent' and 'contains' clauses" } */
+void f8 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes contains (target enter data, target exit data) absent (target enter data, parallel)	/* { dg-error "'target enter data' directive mentioned in both 'absent' and 'contains' clauses" } */
+void f9 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes contains (declare target)			/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+void f10 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes absent (parallel for simd)			/* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */
+void f11 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes contains (target parallel)			/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+void f12 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes absent (assume)				/* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */
+void f13 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes absent (assumes)				/* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */
+void f14 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes contains (begin assumes)			/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+void f15 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes contains (end assumes)			/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+void f16 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes contains (foo)				/* { dg-error "unknown OpenMP directive name in 'contains' clause argument" } */
+void f17 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes absent (target enter something)		/* { dg-error "unknown OpenMP directive name in 'absent' clause argument" } */
+void f18 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes foobar					/* { dg-error "expected assumption clause" } */
+void f19 (void) {}
+#pragma omp end assumes
+#pragma omp begin assumes ext_GCC_foobarbaz, ext_GCC_baz (1, 12, 1 < 17), no_parallelism	/* { dg-warning "unknown assumption clause 'ext_GCC_foobarbaz'" } */
+void f20 (void) {}								/* { dg-warning "unknown assumption clause 'ext_GCC_baz'" "" { target *-*-* } .-1 } */
+#pragma omp end assumes
+#pragma omp begin assumes						/* { dg-error "expected at least one assumption clause" } */
+void f21 (void) {}
+#pragma omp end assumes
--- gcc/testsuite/c-c++-common/gomp/begin-assumes-3.c.jj	2022-09-26 16:46:28.904184438 +0200
+++ gcc/testsuite/c-c++-common/gomp/begin-assumes-3.c	2022-09-26 16:46:59.872769823 +0200
@@ -0,0 +1,2 @@
+#pragma omp begin assumes no_openmp_routines
+void foo (void);	/* { dg-error "'#pragma omp begin assumes' without corresponding '#pragma omp end assumes'" } */
--- gcc/testsuite/c-c++-common/gomp/begin-assumes-4.c.jj	2022-09-26 16:46:32.031142575 +0200
+++ gcc/testsuite/c-c++-common/gomp/begin-assumes-4.c	2022-09-26 16:48:41.407410403 +0200
@@ -0,0 +1,2 @@
+#pragma omp end assumes	/* { dg-error "'#pragma omp end assumes' without corresponding '#pragma omp begin assumes'" } */
+void foo (void);
--- gcc/testsuite/c-c++-common/gomp/declare-target-6.c.jj	2022-09-26 16:45:46.964745953 +0200
+++ gcc/testsuite/c-c++-common/gomp/declare-target-6.c	2022-09-26 16:48:56.645206381 +0200
@@ -0,0 +1,2 @@
+#pragma omp end declare target	/* { dg-error "'#pragma omp end declare target' without corresponding '#pragma omp declare target'" } */
+void foo (void);
--- gcc/testsuite/g++.dg/gomp/attrs-1.C.jj	2022-05-31 11:41:41.412206156 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-1.C	2022-09-26 17:14:00.266060212 +0200
@@ -123,7 +123,7 @@ baz (int d, int m, int i1, int i2, int p
 void
 bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s,
      int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q, int *dd, int ntm,
-     const char *msg)
+     const char *msg, int n1, int n2)
 {
   [[omp::directive (nothing)]];
   [[omp::directive (error at (execution) severity (warning) message (msg))]];
@@ -612,6 +612,19 @@ bar (int d, int m, int i1, int i2, int i
     ;
   [[omp::directive (parallel)]]
   switch (0) { case 1: break; default: break; }
+  [[omp::directive (assume no_openmp no_openmp_routines no_parallelism
+			   absent (atomic, barrier, cancel, cancellation point)
+			   absent (critical, depobj)
+			   absent (distribute, flush, loop, masked, master, nothing, ordered)
+			   absent (parallel, scan, scope, section, sections, simd, single, task)
+			   absent (taskgroup, taskloop, taskwait, taskyield)
+			   absent (target, teams, for, error) holds (n1 < n2))]]
+  if (0)
+    ;
+  [[omp::sequence (omp::directive (assume contains (simd)),
+		   omp::directive (for simd))]]
+  for (int i = 0; i < 64; i++)
+    ;
 }
 
 void corge1 ();
--- gcc/testsuite/g++.dg/gomp/attrs-2.C.jj	2022-05-31 11:41:41.424206027 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-2.C	2022-09-26 17:14:24.676733147 +0200
@@ -123,7 +123,7 @@ baz (int d, int m, int i1, int i2, int p
 void
 bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s,
      int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q, int *dd, int ntm,
-     const char *msg)
+     const char *msg, int n1, int n2)
 {
   [[omp::directive (nothing)]];
   [[omp::directive (error, at (execution), severity (warning), message (msg))]];
@@ -604,6 +604,19 @@ bar (int d, int m, int i1, int i2, int i
   extern int t2;
   [[omp::directive (declare reduction (dr: int: omp_out += omp_in),initializer (omp_priv = 0))]]
   ;
+  [[omp::directive (assume, no_openmp, no_openmp_routines, no_parallelism,
+			    absent (atomic, barrier, cancel, cancellation point),
+			    absent (critical, depobj),
+			    absent (distribute, flush, loop, masked, master, nothing, ordered),
+			    absent (parallel, scan, scope, section, sections, simd, single, task),
+			    absent (taskgroup, taskloop, taskwait, taskyield),
+			    absent (target, teams, for, error), holds (n1 < n2))]]
+  if (0)
+    ;
+  [[omp::sequence (omp::directive (assume, contains (simd)),
+		   omp::directive (for simd))]]
+  for (int i = 0; i < 64; i++)
+    ;
 }
 
 void corge1 ();
--- gcc/testsuite/g++.dg/gomp/attrs-9.C.jj	2022-05-27 12:48:40.726484137 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-9.C	2022-09-26 17:20:09.535112559 +0200
@@ -1,5 +1,6 @@
 // { dg-do compile { target c++11 } }
 
+int n1 = 0, n2 = 42;
 [[omp::sequence (directive (requires, atomic_default_mem_order (seq_cst)))]];
 [[omp::directive (declare reduction (plus: int: omp_out += omp_in) initializer (omp_priv = 0))]];
 int a;
@@ -14,3 +15,22 @@ int d;
 [[omp::directive (end declare target)]];
 [[omp::directive (end declare target)]];
 [[omp::directive (nothing)]];
+[[omp::directive (begin assumes no_openmp no_openmp_routines no_parallelism
+				absent (atomic, barrier, cancel, cancellation point)
+				absent (critical, depobj)
+				absent (distribute, flush, loop, masked, master, nothing, ordered)
+				absent (parallel, scan, scope, section, sections, simd, single, task)
+				absent (taskgroup, taskloop, taskwait, taskyield)
+				absent (target, teams, for, error) holds (n1 < n2))]];
+void foo (void) {}
+[[omp::directive (end assumes)]];
+[[omp::directive (begin assumes, no_openmp, no_openmp_routines, no_parallelism,
+				 absent (atomic, barrier, cancel, cancellation point),
+				 absent (critical, depobj),
+				 absent (distribute, flush, loop, masked, master, nothing, ordered),
+				 absent (parallel, scan, scope, section, sections, simd, single, task),
+				 absent (taskgroup, taskloop, taskwait, taskyield),
+				 absent (target, teams, for, error), holds (n1 < n2))]];
+[[omp::directive (begin assumes no_openmp)]];
+void bar (void) {}
+[[omp::sequence (omp::directive (end assumes), omp::directive (end assumes))]];
--- gcc/testsuite/g++.dg/gomp/attrs-15.C.jj	2022-09-26 17:29:43.639420416 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-15.C	2022-09-26 17:30:59.774400322 +0200
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++11 } }
+
+#pragma omp begin assumes absent (target)
+#pragma omp begin assumes absent (target)
+[[omp::directive (begin assumes absent (target))]];
+int a;
+[[omp::directive (end assumes)]];
+#pragma omp end assumes
+#pragma omp end assumes
+[[omp::directive (begin assumes absent (target))]];
+int b;
+#pragma omp end assumes		// { dg-error "'begin assumes' in attribute syntax terminated with 'end assumes' in pragma syntax" }
+#pragma omp begin assumes absent (target)
+int c;
+[[omp::directive (end assumes)]];// { dg-error "'begin assumes' in pragma syntax terminated with 'end assumes' in attribute syntax" }
+#pragma omp begin assumes absent (target)
+[[omp::directive (begin assumes absent (target))]];
+int d;
+#pragma omp end assumes		// { dg-error "'begin assumes' in attribute syntax terminated with 'end assumes' in pragma syntax" }
+#pragma omp begin assumes absent (target)
+int e;
+[[omp::directive (end assumes)]];// { dg-error "'begin assumes' in pragma syntax terminated with 'end assumes' in attribute syntax" }
+#pragma omp end assumes
+[[omp::directive (begin assumes absent (target))]];
+[[omp::directive (begin assumes absent (target))]];
+int f;
+#pragma omp end assumes		// { dg-error "'begin assumes' in attribute syntax terminated with 'end assumes' in pragma syntax" }
+#pragma omp begin assumes absent (target)
+int g;
+[[omp::directive (end assumes)]];// { dg-error "'begin assumes' in pragma syntax terminated with 'end assumes' in attribute syntax" }
+[[omp::directive (end assumes)]];
+[[omp::directive (begin assumes absent (target))]];
+#pragma omp begin assumes absent (target)
+int h;
+#pragma omp end assumes
+#pragma omp end assumes		// { dg-error "'begin assumes' in attribute syntax terminated with 'end assumes' in pragma syntax" }
+#pragma omp begin assumes absent (target)
+[[omp::directive (begin assumes absent (target))]];
+int i;
+[[omp::directive (end assumes)]];
+[[omp::directive (end assumes)]];// { dg-error "'begin assumes' in pragma syntax terminated with 'end assumes' in attribute syntax" }
--- gcc/testsuite/g++.dg/gomp/attrs-16.C.jj	2022-09-26 18:12:14.334626390 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-16.C	2022-09-26 18:16:51.666914397 +0200
@@ -0,0 +1,26 @@
+// { dg-do compile { target c++11 } }
+
+int i;
+
+[[omp::directive (assumes no_openmp, absent (target, teams) holds (i < 32U) holds (i < 32U))]];
+void
+bar (void)
+{
+}
+
+[[omp::directive (assumes no_openmp_routines)]];
+[[omp::directive (assumes no_parallelism)]];
+[[omp::directive (assumes absent (for))]];
+void
+fred (void)
+{
+}
+
+[[omp::directive (assumes absent (atomic, barrier, cancel, cancellation point) absent (critical, depobj)
+		    absent (distribute, flush, loop, masked, master, nothing, ordered)
+		    absent (parallel, scan, scope, section, sections, simd, single, task)
+		    absent (taskgroup, taskloop, taskwait, taskyield))]];
+void
+foo (void)
+{
+}
--- gcc/testsuite/g++.dg/gomp/attrs-17.C.jj	2022-09-26 18:12:17.154588650 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-17.C	2022-09-26 18:17:07.939696591 +0200
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++11 } }
+
+[[omp::directive (assumes contains (simd))]];
+[[omp::directive (assumes contains (error))]];
+[[omp::directive (assumes, contains (simd))]];
+
+void
+foo (int i, int *a)
+{
+  [[omp::directive (simd)]]
+  for (int j = 0; j < i; j++)
+    a[j] = j;
+  if (i >= 32)
+    {
+      [[omp::directive (error at (execution) message ("Should not happen"))]];
+    }
+}
