--- gcc/c-family/c-omp.cc.jj	2022-09-28 13:47:00.256269262 +0200
+++ gcc/c-family/c-omp.cc	2022-09-30 14:46:08.270564545 +0200
@@ -3112,8 +3112,8 @@ const struct c_omp_directive c_omp_direc
     C_OMP_DIR_STANDALONE, 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", "target", PRAGMA_OMP_BEGIN,
+    C_OMP_DIR_DECLARATIVE, false },
   /* { "begin", "declare", "variant", PRAGMA_OMP_BEGIN,
     C_OMP_DIR_DECLARATIVE, false }, */
   /* { "begin", "metadirective", nullptr, PRAGMA_OMP_BEGIN,
--- gcc/c/c-lang.h.jj	2022-09-28 13:47:00.258269235 +0200
+++ gcc/c/c-lang.h	2022-09-30 17:08:47.260880045 +0200
@@ -60,9 +60,14 @@ struct GTY(()) language_function {
   int warn_about_return_type;
 };
 
+struct GTY(()) c_omp_declare_target_attr {
+  int device_type;
+};
+
 /* If non-zero, implicit "omp declare target" attribute is added into the
    attribute lists.  */
-extern GTY(()) int current_omp_declare_target_attribute;
+extern GTY(()) vec<c_omp_declare_target_attr, va_gc>
+  *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;
--- gcc/c/c-parser.cc.jj	2022-09-28 13:47:00.260269208 +0200
+++ gcc/c/c-parser.cc	2022-09-30 17:17:24.875790544 +0200
@@ -1675,18 +1675,22 @@ c_parser_translation_unit (c_parser *par
     if (DECL_SIZE (decl) == NULL_TREE && TREE_TYPE (decl) != error_mark_node)
       error ("storage size of %q+D isn%'t known", decl);
 
-  if (current_omp_declare_target_attribute)
+  if (vec_safe_length (current_omp_declare_target_attribute))
     {
+      c_omp_declare_target_attr
+	a = current_omp_declare_target_attribute->pop ();
       if (!errorcount)
-        error ("%<#pragma omp declare target%> without corresponding "
-	       "%<#pragma omp end declare target%>");
-      current_omp_declare_target_attribute = 0;
+	error ("%qs without corresponding %qs",
+	       a.device_type >= 0 ? "#pragma omp begin declare target"
+				  : "#pragma omp declare target",
+	       "#pragma omp end declare target");
+      vec_safe_truncate (current_omp_declare_target_attribute, 0);
     }
   if (current_omp_begin_assumes)
     {
       if (!errorcount)
-	error ("%<#pragma omp begin assumes%> without corresponding "
-	       "%<#pragma omp end assumes%>");
+	error ("%qs without corresponding %qs",
+	       "#pragma omp begin assumes", "#pragma omp end assumes");
       current_omp_begin_assumes = 0;
     }
 }
@@ -16818,8 +16822,8 @@ c_parser_omp_clause_device_type (c_parse
   else
     goto invalid_kind;
 
-  /* check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE_TYPE,
-				"device_type");  */
+  check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE_TYPE,
+			     "device_type");
   c_parser_consume_token (parser);
   parens.skip_until_found_close (parser);
   c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE_TYPE);
@@ -22351,7 +22355,8 @@ c_parser_omp_declare_target (c_parser *p
   else
     {
       c_parser_skip_to_pragma_eol (parser);
-      current_omp_declare_target_attribute++;
+      c_omp_declare_target_attr attr = { -1 };
+      vec_safe_push (current_omp_declare_target_attribute, attr);
       return;
     }
   for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
@@ -22429,12 +22434,17 @@ c_parser_omp_declare_target (c_parser *p
 	}
     }
   if (device_type && only_device_type)
-    warning_at (OMP_CLAUSE_LOCATION (clauses), 0,
-		"directive with only %<device_type%> clauses ignored");
+    error_at (OMP_CLAUSE_LOCATION (clauses),
+	      "directive with only %<device_type%> clause");
 }
 
 /* OpenMP 5.1
-   #pragma omp begin assumes clauses[optseq] new-line  */
+   #pragma omp begin assumes clauses[optseq] new-line
+
+   #pragma omp begin declare target clauses[optseq] new-line  */
+
+#define OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK			\
+	(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE)
 
 static void
 c_parser_omp_begin (c_parser *parser)
@@ -22443,7 +22453,33 @@ c_parser_omp_begin (c_parser *parser)
   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)
+  if (strcmp (p, "declare") == 0)
+    {
+      c_parser_consume_token (parser);
+      p = "";
+      if (c_parser_next_token_is (parser, CPP_NAME))
+	p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (strcmp (p, "target") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  tree clauses
+	    = c_parser_omp_all_clauses (parser,
+					OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK,
+					"#pragma omp begin declare target");
+	  int device_type = 0;
+	  for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+	    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE)
+	      device_type |= OMP_CLAUSE_DEVICE_TYPE_KIND (c);
+	  c_omp_declare_target_attr attr = { device_type };
+	  vec_safe_push (current_omp_declare_target_attribute, attr);
+	}
+      else
+	{
+	  c_parser_error (parser, "expected %<target%>");
+	  c_parser_skip_to_pragma_eol (parser);
+	}
+    }
+  else if (strcmp (p, "assumes") == 0)
     {
       c_parser_consume_token (parser);
       c_parser_omp_assumption_clauses (parser, false);
@@ -22451,7 +22487,7 @@ c_parser_omp_begin (c_parser *parser)
     }
   else
     {
-      c_parser_error (parser, "expected %<assumes%>");
+      c_parser_error (parser, "expected %<declare target%> or %<assumes%>");
       c_parser_skip_to_pragma_eol (parser);
     }
 }
@@ -22484,19 +22520,20 @@ c_parser_omp_end (c_parser *parser)
 	  return;
 	}
       c_parser_skip_to_pragma_eol (parser);
-      if (!current_omp_declare_target_attribute)
+      if (!vec_safe_length (current_omp_declare_target_attribute))
 	error_at (loc, "%<#pragma omp end declare target%> without "
-		       "corresponding %<#pragma omp declare target%>");
+		       "corresponding %<#pragma omp declare target%> or "
+		       "%<#pragma omp begin declare target%>");
       else
-	current_omp_declare_target_attribute--;
+	current_omp_declare_target_attribute->pop ();
     }
   else if (strcmp (p, "assumes") == 0)
     {
       c_parser_consume_token (parser);
       c_parser_skip_to_pragma_eol (parser);
       if (!current_omp_begin_assumes)
-	error_at (loc, "%<#pragma omp end assumes%> without "
-		       "corresponding %<#pragma omp begin assumes%>");
+	error_at (loc, "%qs without corresponding %qs",
+		  "#pragma omp end assumes", "#pragma omp begin assumes");
       else
 	current_omp_begin_assumes--;
     }
--- gcc/c/c-decl.cc.jj	2022-09-30 14:12:44.299063275 +0200
+++ gcc/c/c-decl.cc	2022-09-30 17:11:46.135454719 +0200
@@ -153,9 +153,9 @@ static int warn_about_return_type;
 
 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;
+/* Vector of implicit "omp declare target" attributes to be added into
+   the attribute lists.  */
+vec<c_omp_declare_target_attr, va_gc> *current_omp_declare_target_attribute;
 
 /* If non-zero, we are inside of
    #pragma omp begin assumes ... #pragma omp end assumes region.  */
@@ -5105,7 +5105,7 @@ 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
+  if (vec_safe_length (current_omp_declare_target_attribute)
       && ((VAR_P (*node) && is_global_var (*node))
 	  || TREE_CODE (*node) == FUNCTION_DECL))
     {
@@ -5119,6 +5119,22 @@ c_decl_attributes (tree *node, tree attr
 	  attributes = tree_cons (get_identifier ("omp declare target block"),
 				  NULL_TREE, attributes);
 	}
+      if (TREE_CODE (*node) == FUNCTION_DECL)
+	{
+	  int device_type
+	    = current_omp_declare_target_attribute->last ().device_type;
+	  device_type = MAX (device_type, 0);
+	  if ((device_type & OMP_CLAUSE_DEVICE_TYPE_HOST) != 0
+	      && !lookup_attribute ("omp declare target host", attributes))
+	    attributes
+	      = tree_cons (get_identifier ("omp declare target host"),
+			   NULL_TREE, attributes);
+	  if ((device_type & OMP_CLAUSE_DEVICE_TYPE_NOHOST) != 0
+	      && !lookup_attribute ("omp declare target nohost", attributes))
+	    attributes
+	      = tree_cons (get_identifier ("omp declare target nohost"),
+			   NULL_TREE, attributes);
+	}
     }
 
   /* Look up the current declaration with all the attributes merged
--- gcc/cp/cp-tree.h.jj	2022-09-30 14:12:44.410061751 +0200
+++ gcc/cp/cp-tree.h	2022-09-30 17:08:58.114732884 +0200
@@ -1855,11 +1855,12 @@ union GTY((desc ("cp_tree_node_structure
 };
 
 
-struct GTY(()) omp_declare_target_attr {
+struct GTY(()) cp_omp_declare_target_attr {
   bool attr_syntax;
+  int device_type;
 };
 
-struct GTY(()) omp_begin_assumes_data {
+struct GTY(()) cp_omp_begin_assumes_data {
   bool attr_syntax;
 };
 
@@ -1909,8 +1910,8 @@ struct GTY(()) saved_scope {
   cp_binding_level *bindings;
 
   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;
+  vec<cp_omp_declare_target_attr, va_gc> *omp_declare_target_attribute;
+  vec<cp_omp_begin_assumes_data, va_gc> *omp_begin_assumes;
 
   struct saved_scope *prev;
 };
--- gcc/cp/parser.cc.jj	2022-09-29 18:11:34.858666499 +0200
+++ gcc/cp/parser.cc	2022-09-30 17:20:12.787471853 +0200
@@ -40315,8 +40315,8 @@ cp_parser_omp_clause_device_type (cp_par
     goto resync_fail;
 
   c = build_omp_clause (location, OMP_CLAUSE_DEVICE_TYPE);
-  /* check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE_TYPE, "device_type",
-				location);  */
+  check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE_TYPE, "device_type",
+			     location);
   OMP_CLAUSE_DEVICE_TYPE_KIND (c) = kind;
   OMP_CLAUSE_CHAIN (c) = list;
   return c;
@@ -40840,7 +40840,7 @@ cp_parser_omp_all_clauses (cp_parser *pa
 	  break;
 	case PRAGMA_OMP_CLAUSE_LINK:
 	  clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_LINK, clauses);
-	  c_name = "to";
+	  c_name = "link";
 	  break;
 	case PRAGMA_OMP_CLAUSE_TO:
 	  if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) != 0)
@@ -46737,8 +46737,8 @@ cp_parser_omp_declare_target (cp_parser
     }
   else
     {
-      struct omp_declare_target_attr a
-	= { parser->lexer->in_omp_attribute_pragma };
+      cp_omp_declare_target_attr a
+	= { parser->lexer->in_omp_attribute_pragma, -1 };
       vec_safe_push (scope_chain->omp_declare_target_attribute, a);
       cp_parser_require_pragma_eol (parser, pragma_tok);
       return;
@@ -46763,12 +46763,17 @@ cp_parser_omp_declare_target (cp_parser
 					  device_type);
     }
   if (device_type && only_device_type)
-    warning_at (OMP_CLAUSE_LOCATION (clauses), 0,
-		"directive with only %<device_type%> clauses ignored");
+    error_at (OMP_CLAUSE_LOCATION (clauses),
+	      "directive with only %<device_type%> clause");
 }
 
 /* OpenMP 5.1
-   #pragma omp begin assumes clauses[optseq] new-line  */
+   # pragma omp begin assumes clauses[optseq] new-line
+
+   # pragma omp begin declare target clauses[optseq] new-line  */
+
+#define OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK			\
+	(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE)
 
 static void
 cp_parser_omp_begin (cp_parser *parser, cp_token *pragma_tok)
@@ -46780,16 +46785,47 @@ cp_parser_omp_begin (cp_parser *parser,
       tree id = cp_lexer_peek_token (parser->lexer)->u.value;
       p = IDENTIFIER_POINTER (id);
     }
-  if (strcmp (p, "assumes") == 0)
+  if (strcmp (p, "declare") == 0)
+    {
+      cp_lexer_consume_token (parser->lexer);
+      p = "";
+      if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+	{
+	  tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+	  p = IDENTIFIER_POINTER (id);
+	}
+      if (strcmp (p, "target") == 0)
+	{
+	  cp_lexer_consume_token (parser->lexer);
+	  tree clauses
+	    = cp_parser_omp_all_clauses (parser,
+					 OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK,
+					 "#pragma omp begin declare target",
+					 pragma_tok);
+	  int device_type = 0;
+	  for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+	    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE)
+	      device_type |= OMP_CLAUSE_DEVICE_TYPE_KIND (c);
+	  cp_omp_declare_target_attr a
+	    = { in_omp_attribute_pragma, device_type };
+	  vec_safe_push (scope_chain->omp_declare_target_attribute, a);
+	}
+      else
+	{
+	  cp_parser_error (parser, "expected %<target%>");
+	  cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+	}
+    }
+  else 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 };
+      cp_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_error (parser, "expected %<declare target%> or %<assumes%>");
       cp_parser_skip_to_pragma_eol (parser, pragma_tok);
     }
 }
@@ -46831,21 +46867,28 @@ cp_parser_omp_end (cp_parser *parser, cp
       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%>");
+		  "%<#pragma omp declare target%> or "
+		  "%<#pragma omp begin declare target%>");
       else
 	{
-	  omp_declare_target_attr
+	  cp_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");
+			  "%qs in attribute syntax terminated "
+			  "with %qs in pragma syntax",
+			  a.device_type >= 0 ? "begin declare target"
+					     : "declare target",
+			  "end declare target");
 	      else
 		error_at (pragma_tok->location,
-			  "%<declare target%> in pragma syntax terminated "
-			  "with %<end declare target%> in attribute syntax");
+			  "%qs in pragma syntax terminated "
+			  "with %qs in attribute syntax",
+			  a.device_type >= 0 ? "begin declare target"
+					     : "declare target",
+			  "end declare target");
 	    }
 	}
     }
@@ -46855,22 +46898,24 @@ cp_parser_omp_end (cp_parser *parser, cp
       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%>");
+		  "%qs without corresponding %qs",
+		  "#pragma omp end assumes", "#pragma omp begin assumes");
       else
 	{
-	  omp_begin_assumes_data
+	  cp_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");
+			  "%qs in attribute syntax terminated "
+			  "with %qs in pragma syntax",
+			  "begin assumes", "end assumes");
 	      else
 		error_at (pragma_tok->location,
-			  "%<begin assumes%> in pragma syntax terminated "
-			  "with %<end assumes%> in attribute syntax");
+			  "%qs in pragma syntax terminated "
+			  "with %qs in attribute syntax",
+			  "begin assumes", "end assumes");
 	    }
 	}
     }
--- gcc/cp/semantics.cc.jj	2022-09-29 18:11:34.869666349 +0200
+++ gcc/cp/semantics.cc	2022-09-30 17:13:38.046922818 +0200
@@ -3358,16 +3358,20 @@ finish_translation_unit (void)
 
   if (vec_safe_length (scope_chain->omp_declare_target_attribute))
     {
+      cp_omp_declare_target_attr
+	a = scope_chain->omp_declare_target_attribute->pop ();
       if (!errorcount)
-	error ("%<#pragma omp declare target%> without corresponding "
-	       "%<#pragma omp end declare target%>");
+	error ("%qs without corresponding %qs",
+	       a.device_type >= 0 ? "#pragma omp begin declare target"
+				  : "#pragma omp declare target",
+	       "#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%>");
+	error ("%qs without corresponding %qs",
+	       "#pragma omp begin assumes", "#pragma omp end assumes");
       vec_safe_truncate (scope_chain->omp_begin_assumes, 0);
     }
 }
--- gcc/cp/decl2.cc.jj	2022-09-28 13:47:00.263269168 +0200
+++ gcc/cp/decl2.cc	2022-09-30 17:11:14.230887302 +0200
@@ -1652,17 +1652,40 @@ cplus_decl_attributes (tree *decl, tree
 	  && DECL_CLASS_SCOPE_P (*decl))
 	error ("%q+D static data member inside of declare target directive",
 	       *decl);
-      else if (VAR_P (*decl)
-	       && (processing_template_decl
-		   || !omp_mappable_type (TREE_TYPE (*decl))))
-	attributes = tree_cons (get_identifier ("omp declare target implicit"),
-				NULL_TREE, attributes);
       else
 	{
-	  attributes = tree_cons (get_identifier ("omp declare target"),
-				  NULL_TREE, attributes);
-	  attributes = tree_cons (get_identifier ("omp declare target block"),
-				  NULL_TREE, attributes);
+	  if (VAR_P (*decl)
+	      && (processing_template_decl
+		  || !omp_mappable_type (TREE_TYPE (*decl))))
+	    attributes
+	      = tree_cons (get_identifier ("omp declare target implicit"),
+			   NULL_TREE, attributes);
+	  else
+	    {
+	      attributes = tree_cons (get_identifier ("omp declare target"),
+				      NULL_TREE, attributes);
+	      attributes
+		= tree_cons (get_identifier ("omp declare target block"),
+			     NULL_TREE, attributes);
+	    }
+	  if (TREE_CODE (*decl) == FUNCTION_DECL)
+	    {
+	      cp_omp_declare_target_attr &last
+		= scope_chain->omp_declare_target_attribute->last ();
+	      int device_type = MAX (last.device_type, 0);
+	      if ((device_type & OMP_CLAUSE_DEVICE_TYPE_HOST) != 0
+		  && !lookup_attribute ("omp declare target host",
+					attributes))
+		attributes
+		  = tree_cons (get_identifier ("omp declare target host"),
+			       NULL_TREE, attributes);
+	      if ((device_type & OMP_CLAUSE_DEVICE_TYPE_NOHOST) != 0
+		  && !lookup_attribute ("omp declare target nohost",
+					attributes))
+		attributes
+		  = tree_cons (get_identifier ("omp declare target nohost"),
+			       NULL_TREE, attributes);
+	    }
 	}
     }
 
--- gcc/testsuite/c-c++-common/gomp/declare-target-4.c.jj	2020-01-12 11:54:37.012404372 +0100
+++ gcc/testsuite/c-c++-common/gomp/declare-target-4.c	2022-09-30 15:25:42.880123901 +0200
@@ -1,8 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-fopenmp" } */
 
-#pragma omp declare target device_type (any)		/* { dg-warning "directive with only 'device_type' clauses ignored" } */
-
 void f1 (void) {}
 void f2 (void);
 #pragma omp declare target to (f1) device_type (any) to (f2)
@@ -38,7 +36,3 @@ void f13 (void) {}
 void f14 (void) {}
 #pragma omp declare target device_type (nohost) to (f14)
 #pragma omp declare target device_type (any) to (f14)
-void f15 (void) {}
-#pragma omp declare target device_type (host) to (f15) device_type (nohost)
-void f16 (void) {}
-#pragma omp declare target device_type (any) to (f15) device_type (any)
--- gcc/testsuite/c-c++-common/gomp/declare-target-6.c.jj	2022-09-27 08:22:37.073635313 +0200
+++ gcc/testsuite/c-c++-common/gomp/declare-target-6.c	2022-09-30 15:28:46.858609049 +0200
@@ -1,2 +1,2 @@
-#pragma omp end declare target	/* { dg-error "'#pragma omp end declare target' without corresponding '#pragma omp declare target'" } */
+#pragma omp end declare target	/* { dg-error "'#pragma omp end declare target' without corresponding '#pragma omp declare target' or '#pragma omp begin declare target'" } */
 void foo (void);
--- gcc/testsuite/c-c++-common/gomp/declare-target-7.c.jj	2022-09-30 15:23:01.362331741 +0200
+++ gcc/testsuite/c-c++-common/gomp/declare-target-7.c	2022-09-30 15:27:01.105054620 +0200
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+#pragma omp declare target device_type (any)		/* { dg-error "directive with only 'device_type' clause" } */
+
+void f1 (void) {}
+#pragma omp declare target device_type (host) to (f1) device_type (nohost)	/* { dg-error "too many 'device_type' clauses" } */
+#pragma omp declare target device_type (any) to (f1) device_type (any)		/* { dg-error "too many 'device_type' clauses" } */
--- gcc/testsuite/c-c++-common/gomp/begin-declare-target-1.c.jj	2022-09-30 16:40:28.777857628 +0200
+++ gcc/testsuite/c-c++-common/gomp/begin-declare-target-1.c	2022-09-30 16:47:08.064466814 +0200
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+extern int a;
+#pragma omp begin declare target device_type (host)
+int b;
+#pragma omp begin declare target device_type (any)
+char d;
+#pragma omp end declare target
+#pragma omp end declare target
+#pragma omp begin declare target
+long c;
+#pragma omp end declare target
+#pragma omp declare target
+int foo (void) { return 0; }
+#pragma omp begin declare target device_type (any)
+int bar (void) { return 0; }
+#pragma omp end declare target
+#pragma omp end declare target
+#pragma omp begin declare target device_type (any)
+int baz (void) { return 0; }
+#pragma omp declare target
+int qux (void) { return 0; }
+#pragma omp end declare target
+#pragma omp end declare target
--- gcc/testsuite/c-c++-common/gomp/begin-declare-target-2.c.jj	2022-09-30 16:41:12.091272843 +0200
+++ gcc/testsuite/c-c++-common/gomp/begin-declare-target-2.c	2022-09-30 16:50:16.109927990 +0200
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+extern int a;
+#pragma omp begin declare target
+#pragma omp declare target to (a)
+#pragma omp end declare target
+int b;
+#pragma omp begin declare target to (b)		/* { dg-error "'to' is not valid for '#pragma omp begin declare target'" } */
+#pragma omp end declare target
+int c;
+#pragma omp begin declare target link (c)	/* { dg-error "'link' is not valid for '#pragma omp begin declare target'" } */
+#pragma omp end declare target
+int m;
+#pragma omp begin declare target device_type (host) device_type (any)	/* { dg-error "too many 'device_type' clauses" } */
+#pragma omp end declare target
+#pragma omp begin declare target
+#pragma omp end declare target to (p)		/* { dg-error "expected end of line before .to." } */
--- gcc/testsuite/c-c++-common/gomp/begin-declare-target-3.c.jj	2022-09-30 18:01:22.422193659 +0200
+++ gcc/testsuite/c-c++-common/gomp/begin-declare-target-3.c	2022-09-30 16:45:57.768415887 +0200
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+#pragma omp begin declare target
+int a[] = { 1, 2, 3 };
+extern int b[];			/* { dg-error "'b' in declare target directive does not have mappable type" } */
+extern int c[];			/* { dg-error "'c' in declare target directive does not have mappable type" } */
+extern int d[];			/* { dg-error "'d' in declare target directive does not have mappable type" } */
+int d[3];
+#pragma omp end declare target
+int c[3];
+#pragma omp begin declare target device_type (host)
+int e[] = { 1, 2, 3 };
+extern int f[];			/* { dg-error "'f' in declare target directive does not have mappable type" } */
+extern int g[];			/* { dg-error "'g' in declare target directive does not have mappable type" } */
+extern int h[];			/* { dg-error "'h' in declare target directive does not have mappable type" } */
+int h[3];
+#pragma omp end declare target
+int g[3];
--- gcc/testsuite/c-c++-common/gomp/begin-declare-target-4.c.jj	2022-09-30 16:47:44.763971326 +0200
+++ gcc/testsuite/c-c++-common/gomp/begin-declare-target-4.c	2022-09-30 17:32:49.370548159 +0200
@@ -0,0 +1,2 @@
+#pragma omp begin declare target
+void foo (void);	/* { dg-error "'#pragma omp begin declare target' without corresponding '#pragma omp end declare target'" } */
--- gcc/testsuite/g++.dg/gomp/attrs-9.C.jj	2022-09-27 08:22:37.164634077 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-9.C	2022-09-30 17:36:48.220575918 +0200
@@ -14,6 +14,21 @@ int b, c, e;
 int d;
 [[omp::directive (end declare target)]];
 [[omp::directive (end declare target)]];
+[[omp::directive (begin declare target, device_type (any))]];
+[[omp::directive (begin declare target)]];
+int f;
+[[omp::directive (end declare target)]];
+[[omp::directive (end declare target)]];
+[[omp::directive (begin declare target device_type (host))]];
+[[omp::directive (declare target)]];
+int g;
+[[omp::directive (end declare target)]];
+[[omp::directive (end declare target)]];
+[[omp::directive (declare target)]];
+[[omp::directive (begin declare target, device_type (nohost))]];
+int h;
+[[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)
--- gcc/testsuite/g++.dg/gomp/attrs-18.C.jj	2022-09-30 17:37:26.173944723 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-18.C	2022-09-30 17:38:58.603407551 +0200
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++11 } }
+
+#pragma omp begin declare target
+#pragma omp begin declare target device_type (any)
+[[omp::directive (begin declare target, device_type (host))]];
+int a;
+[[omp::directive (end declare target)]];
+#pragma omp end declare target
+#pragma omp end declare target
+[[omp::directive (begin declare target device_type (nohost))]];
+int b;
+#pragma omp end declare target		// { dg-error "'begin declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" }
+#pragma omp begin declare target
+int c;
+[[omp::directive (end declare target)]];// { dg-error "'begin declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" }
+#pragma omp begin declare target device_type (host)
+[[omp::directive (begin declare target)]];
+int d;
+#pragma omp end declare target		// { dg-error "'begin declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" }
+#pragma omp begin declare target
+int e;
+[[omp::directive (end declare target)]];// { dg-error "'begin declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" }
+#pragma omp end declare target
+[[omp::directive (begin declare target device_type (any))]];
+[[omp::directive (begin declare target)]];
+int f;
+#pragma omp end declare target		// { dg-error "'begin declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" }
+#pragma omp begin declare target
+int g;
+[[omp::directive (end declare target)]];// { dg-error "'begin declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" }
+[[omp::directive (end declare target)]];
+[[omp::directive (begin declare target)]];
+#pragma omp begin declare target
+int h;
+#pragma omp end declare target
+#pragma omp end declare target		// { dg-error "'begin declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" }
+#pragma omp begin declare target
+[[omp::directive (begin declare target)]];
+int i;
+[[omp::directive (end declare target)]];
+[[omp::directive (end declare target)]];// { dg-error "'begin declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" }
--- libgomp/libgomp.texi.jj	2022-09-28 13:47:07.681169256 +0200
+++ libgomp/libgomp.texi	2022-09-30 17:41:57.535431793 +0200
@@ -345,7 +345,7 @@ The OpenMP 4.5 specification is fully su
 @item Support of structured block sequences in C/C++ @tab Y @tab
 @item @code{unconstrained} and @code{reproducible} modifiers on @code{order}
       clause @tab Y @tab
-@item Support @code{begin/end declare target} syntax in C/C++ @tab N @tab
+@item Support @code{begin/end declare target} syntax in C/C++ @tab Y @tab
 @item Pointer predetermined firstprivate getting initialized
 to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab
 @item For Fortran, diagnose placing declarative before/between @code{USE},
